src/sys/kern/vfs_mount.c
/*
 * Build a linked list of mount options from a struct uio.
 */
Build a linked list of mount options from a struct uio.
Build a linked list of mount options from a struct uio .
int
vfs_buildopts(struct uio *auio, struct vfsoptlist **options)
{
	struct vfsoptlist *opts;
	struct vfsopt *opt;
	size_t memused, namelen, optlen;
	unsigned int i, iovcnt;
	int error;
	opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK);
	TAILQ_INIT(opts);
	memused = 0;
	iovcnt = auio->uio_iovcnt;
	for (i = 0; i < iovcnt; i += 2) {
		namelen = auio->uio_iov[i].iov_len;
		optlen = auio->uio_iov[i + 1].iov_len;
		memused += sizeof(struct vfsopt) + optlen + namelen;
		if (memused > VFS_MOUNTARG_SIZE_MAX ||
		    optlen > VFS_MOUNTARG_SIZE_MAX ||
		    namelen > VFS_MOUNTARG_SIZE_MAX) {
			error = EINVAL;
			goto bad;
		}
		opt = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK);
		opt->name = malloc(namelen, M_MOUNT, M_WAITOK);
		opt->value = NULL;
		opt->len = 0;
		opt->pos = i / 2;
		opt->seen = 0;
		TAILQ_INSERT_TAIL(opts, opt, link);
		if (auio->uio_segflg == UIO_SYSSPACE) {
			bcopy(auio->uio_iov[i].iov_base, opt->name, namelen);
		} else {
			error = copyin(auio->uio_iov[i].iov_base, opt->name,
			    namelen);
			if (error)
				goto bad;
		}
		if (namelen == 0 || opt->name[namelen - 1] != '\0') {
			error = EINVAL;
			goto bad;
		}
		if (optlen != 0) {
			opt->len = optlen;
			opt->value = malloc(optlen, M_MOUNT, M_WAITOK);
			if (auio->uio_segflg == UIO_SYSSPACE) {
				bcopy(auio->uio_iov[i + 1].iov_base, opt->value,
				    optlen);
			} else {
				error = copyin(auio->uio_iov[i + 1].iov_base,
				    opt->value, optlen);
				if (error)
					goto bad;
			}
		}
	}
	vfs_sanitizeopts(opts);
	*options = opts;
	return (0);
bad:
	vfs_freeopts(opts);
	return (error);
}
int vfs_buildopts ( struct uio * auio , struct vfsoptlist * * options ) { struct vfsoptlist * opts ; struct vfsopt * opt ; size_t memused , namelen , optlen ; unsigned int i , iovcnt ; int error ; opts = malloc ( sizeof ( struct vfsoptlist ) , M_MOUNT , M_WAITOK ) ; TAILQ_INIT ( opts ) ; memused = 0 ; iovcnt = auio -> uio_iovcnt ; for ( i = 0 ; i < iovcnt ; i += 2 ) { namelen = auio -> uio_iov [ i ] . iov_len ; optlen = auio -> uio_iov [ i + 1 ] . iov_len ; memused += sizeof ( struct vfsopt ) + optlen + namelen ; if ( memused > VFS_MOUNTARG_SIZE_MAX || optlen > VFS_MOUNTARG_SIZE_MAX || namelen > VFS_MOUNTARG_SIZE_MAX ) { error = EINVAL ; goto bad ; } opt = malloc ( sizeof ( struct vfsopt ) , M_MOUNT , M_WAITOK ) ; opt -> name = malloc ( namelen , M_MOUNT , M_WAITOK ) ; opt -> value = NULL ; opt -> len = 0 ; opt -> pos = i / 2 ; opt -> seen = 0 ; TAILQ_INSERT_TAIL ( opts , opt , link ) ; if ( auio -> uio_segflg == UIO_SYSSPACE ) { bcopy ( auio -> uio_iov [ i ] . iov_base , opt -> name , namelen ) ; } else { error = copyin ( auio -> uio_iov [ i ] . iov_base , opt -> name , namelen ) ; if ( error ) goto bad ; } if ( namelen == 0 || opt -> name [ namelen - 1 ] != ' \0 ' ) { error = EINVAL ; goto bad ; } if ( optlen != 0 ) { opt -> len = optlen ; opt -> value = malloc ( optlen , M_MOUNT , M_WAITOK ) ; if ( auio -> uio_segflg == UIO_SYSSPACE ) { bcopy ( auio -> uio_iov [ i + 1 ] . iov_base , opt -> value , optlen ) ; } else { error = copyin ( auio -> uio_iov [ i + 1 ] . iov_base , opt -> value , optlen ) ; if ( error ) goto bad ; } } } vfs_sanitizeopts ( opts ) ; * options = opts ; return ( 0 ) ; bad : vfs_freeopts ( opts ) ; return ( error ) ; }
Build a linked list of mount options from a struct uio.
Build a linked list of mount options from a struct uio .
/*
		 * Avoid consuming too much memory, and attempts to overflow
		 * memused.
		 */ /*
		 * Do this early, so jumps to "bad" will free the current
		 * option.
		 */ /* Ensure names are null-terminated strings. */