FreeBSD/sys/security/audit/audit_pipe.c
/*
 * Audit pipe read.  Read one or more partial or complete records to user
 * memory.
 */
Audit pipe read.  Read one or more partial or complete records to user
memory.
Audit pipe read . Read one or more partial or complete records to user memory .
static int
audit_pipe_read(struct cdev *dev, struct uio *uio, int flag)
{
	struct audit_pipe_entry *ape;
	struct audit_pipe *ap;
	u_int toread;
	int error;
	error = devfs_get_cdevpriv((void **)&ap);
	if (error != 0)
		return (error);
	if (AUDIT_PIPE_SX_XLOCK_SIG(ap) != 0)
		return (EINTR);
	AUDIT_PIPE_LOCK(ap);
	while (TAILQ_EMPTY(&ap->ap_queue)) {
		if (ap->ap_flags & AUDIT_PIPE_NBIO) {
			AUDIT_PIPE_UNLOCK(ap);
			AUDIT_PIPE_SX_XUNLOCK(ap);
			return (EAGAIN);
		}
		error = cv_wait_sig(&ap->ap_cv, AUDIT_PIPE_MTX(ap));
		if (error) {
			AUDIT_PIPE_UNLOCK(ap);
			AUDIT_PIPE_SX_XUNLOCK(ap);
			return (error);
		}
	}
	ap->ap_reads++;
	while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL &&
	    uio->uio_resid > 0) {
		AUDIT_PIPE_LOCK_ASSERT(ap);
		KASSERT(ape->ape_record_len > ap->ap_qoffset,
		    ("audit_pipe_read: record_len > qoffset (1)"));
		toread = MIN(ape->ape_record_len - ap->ap_qoffset,
		    uio->uio_resid);
		AUDIT_PIPE_UNLOCK(ap);
		error = uiomove((char *)ape->ape_record + ap->ap_qoffset,
		    toread, uio);
		if (error) {
			AUDIT_PIPE_SX_XUNLOCK(ap);
			return (error);
		}
		AUDIT_PIPE_LOCK(ap);
		KASSERT(TAILQ_FIRST(&ap->ap_queue) == ape,
		    ("audit_pipe_read: queue out of sync after uiomove"));
		ap->ap_qoffset += toread;
		KASSERT(ape->ape_record_len >= ap->ap_qoffset,
		    ("audit_pipe_read: record_len >= qoffset (2)"));
		if (ap->ap_qoffset == ape->ape_record_len) {
			TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue);
			ap->ap_qbyteslen -= ape->ape_record_len;
			audit_pipe_entry_free(ape);
			ap->ap_qlen--;
			ap->ap_qoffset = 0;
		}
	}
	AUDIT_PIPE_UNLOCK(ap);
	AUDIT_PIPE_SX_XUNLOCK(ap);
	return (0);
}
static int audit_pipe_read ( struct cdev * dev , struct uio * uio , int flag ) { struct audit_pipe_entry * ape ; struct audit_pipe * ap ; u_int toread ; int error ; error = devfs_get_cdevpriv ( ( void * * ) & ap ) ; if ( error != 0 ) return ( error ) ; if ( AUDIT_PIPE_SX_XLOCK_SIG ( ap ) != 0 ) return ( EINTR ) ; AUDIT_PIPE_LOCK ( ap ) ; while ( TAILQ_EMPTY ( & ap -> ap_queue ) ) { if ( ap -> ap_flags & AUDIT_PIPE_NBIO ) { AUDIT_PIPE_UNLOCK ( ap ) ; AUDIT_PIPE_SX_XUNLOCK ( ap ) ; return ( EAGAIN ) ; } error = cv_wait_sig ( & ap -> ap_cv , AUDIT_PIPE_MTX ( ap ) ) ; if ( error ) { AUDIT_PIPE_UNLOCK ( ap ) ; AUDIT_PIPE_SX_XUNLOCK ( ap ) ; return ( error ) ; } } ap -> ap_reads ++ ; while ( ( ape = TAILQ_FIRST ( & ap -> ap_queue ) ) != NULL && uio -> uio_resid > 0 ) { AUDIT_PIPE_LOCK_ASSERT ( ap ) ; KASSERT ( ape -> ape_record_len > ap -> ap_qoffset , ( " " ) ) ; toread = MIN ( ape -> ape_record_len - ap -> ap_qoffset , uio -> uio_resid ) ; AUDIT_PIPE_UNLOCK ( ap ) ; error = uiomove ( ( char * ) ape -> ape_record + ap -> ap_qoffset , toread , uio ) ; if ( error ) { AUDIT_PIPE_SX_XUNLOCK ( ap ) ; return ( error ) ; } AUDIT_PIPE_LOCK ( ap ) ; KASSERT ( TAILQ_FIRST ( & ap -> ap_queue ) == ape , ( " " ) ) ; ap -> ap_qoffset += toread ; KASSERT ( ape -> ape_record_len >= ap -> ap_qoffset , ( " " ) ) ; if ( ap -> ap_qoffset == ape -> ape_record_len ) { TAILQ_REMOVE ( & ap -> ap_queue , ape , ape_queue ) ; ap -> ap_qbyteslen -= ape -> ape_record_len ; audit_pipe_entry_free ( ape ) ; ap -> ap_qlen -- ; ap -> ap_qoffset = 0 ; } } AUDIT_PIPE_UNLOCK ( ap ) ; AUDIT_PIPE_SX_XUNLOCK ( ap ) ; return ( 0 ) ; }
Audit pipe read.
Audit pipe read .
/*
	 * We hold an sx(9) lock over read and flush because we rely on the
	 * stability of a record in the queue during uiomove(9).
	 */ /*
	 * Copy as many remaining bytes from the current record to userspace
	 * as we can.  Keep processing records until we run out of records in
	 * the queue, or until the user buffer runs out of space.
	 *
	 * Note: we rely on the SX lock to maintain ape's stability here.
	 */ /*
		 * If the copy succeeded, update book-keeping, and if no
		 * bytes remain in the current record, free it.
		 */