int
set_charset(struct iovec **iov, int *iovlen, const char *cs_local, const char *cs_dos)
{
	int error;

	if (modfind("msdosfs_iconv") < 0)
		if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) {
			warnx("cannot find or load \"msdosfs_iconv\" kernel module");
			return (-1);
		}

	build_iovec_argf(iov, iovlen, "cs_win", ENCODING_UNICODE);
	error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, cs_local);
	if (error && errno != EEXIST)
		return (-1);
	if (cs_dos != NULL) {
		error = kiconv_add_xlat16_cspairs(cs_dos, cs_local);
		if (error && errno != EEXIST)
			return (-1);
	} else {
		build_iovec_argf(iov, iovlen, "cs_dos", cs_local);
		error = kiconv_add_xlat16_cspair(cs_local, cs_local,
				KICONV_FROM_UPPER | KICONV_LOWER);
		if (error && errno != EEXIST)
			return (-1);
	}

	return (0);
}
Exemple #2
0
static int
fuse_mount_sys (const char *mountpoint, char *fsname,
                unsigned long mountflags, char *mnt_param, int fd)
{
        int ret = -1;
        unsigned mounted = 0;
        char *mnt_param_mnt = NULL;
        char *fstype = "fuse.glusterfs";
        char *source = fsname;

        ret = asprintf (&mnt_param_mnt,
                        "%s,fd=%i,rootmode=%o,user_id=%i,group_id=%i",
                        mnt_param, fd, S_IFDIR, getuid (), getgid ());
        if (ret == -1) {
                GFFUSE_LOGERR ("Out of memory");

                goto out;
        }

#ifdef __FreeBSD__
        struct iovec *iov = NULL;
        int iovlen = 0;
        build_iovec (&iov, &iovlen, "fstype", "fusefs", -1);
        build_iovec (&iov, &iovlen, "subtype", "glusterfs", -1);
        build_iovec (&iov, &iovlen, "fspath", mountpoint, -1);
        build_iovec (&iov, &iovlen, "from", "/dev/fuse", -1);
        build_iovec (&iov, &iovlen, "volname", source, -1);
        build_iovec_argf (&iov, &iovlen, "fd", "%d", fd);
        build_iovec_argf (&iov, &iovlen, "user_id", "%d", getuid());
        build_iovec_argf (&iov, &iovlen, "group_id", "%d", getgid());
        ret = nmount (iov, iovlen, mountflags);
#else
        ret = mount (source, mountpoint, fstype, mountflags,
                     mnt_param_mnt);
#endif /* __FreeBSD__ */
#ifdef GF_LINUX_HOST_OS
        if (ret == -1 && errno == ENODEV) {
                /* fs subtype support was added by 79c0b2df aka
                   v2.6.21-3159-g79c0b2d. Probably we have an
                   older kernel ... */
                fstype = "fuse";
                ret = asprintf (&source, "glusterfs#%s", fsname);
                if (ret == -1) {
                        GFFUSE_LOGERR ("Out of memory");

                        goto out;
                }
                ret = mount (source, mountpoint, fstype, mountflags,
                             mnt_param_mnt);
        }
#endif /* GF_LINUX_HOST_OS */
        if (ret == -1)
                goto out;
        else
                mounted = 1;

#ifdef GF_LINUX_HOST_OS
        if (geteuid () == 0) {
                char *newmnt = fuse_mnt_resolve_path ("fuse", mountpoint);
                char *mnt_param_mtab = NULL;

                if (!newmnt) {
                        ret = -1;

                        goto out;
                }

                ret = asprintf (&mnt_param_mtab, "%s%s",
                                mountflags & MS_RDONLY ? "ro," : "",
                                mnt_param);
                if (ret == -1)
                        GFFUSE_LOGERR ("Out of memory");
                else {
                        ret = fuse_mnt_add_mount ("fuse", source, newmnt,
                                                  fstype, mnt_param_mtab);
                        FREE (mnt_param_mtab);
                }

                FREE (newmnt);
                if (ret == -1) {
                        GFFUSE_LOGERR ("failed to add mtab entry");

                        goto out;
                }
        }
#endif /* GF_LINUX_HOST_OS */

out:
        if (ret == -1) {
                GFFUSE_LOGERR("ret = -1\n");
                if (mounted)
                        umount2 (mountpoint, 2); /* lazy umount */
        }
        FREE (mnt_param_mnt);
        if (source != fsname)
                FREE (source);

        return ret;
}
int
main(int argc, char *argv[])
{
	struct iovec *iov;
	unsigned int iovlen;
	struct smb_ctx sctx, *ctx = &sctx;
	struct stat st;
#ifdef APPLE
	extern void dropsuid();
	extern int loadsmbvfs();
#else
	struct xvfsconf vfc;
#endif
	char *next, *p, *val;
	int opt, error, mntflags, caseopt, fd;
	uid_t uid;
	gid_t gid;
	mode_t dir_mode, file_mode;
	char errmsg[255] = { 0 };

	iov = NULL;
	iovlen = 0;
	fd = 0;
	uid = (uid_t)-1;
	gid = (gid_t)-1;
	caseopt = 0;
	file_mode = 0;
	dir_mode = 0;

#ifdef APPLE
	dropsuid();
#endif
	if (argc == 2) {
		if (strcmp(argv[1], "-h") == 0) {
			usage();
		}
	}
	if (argc < 3)
		usage();

#ifdef APPLE
	error = loadsmbvfs();
#else
	error = getvfsbyname(smbfs_vfsname, &vfc);
	if (error) {
		if (kldload(smbfs_vfsname) < 0)
			err(EX_OSERR, "kldload(%s)", smbfs_vfsname);
		error = getvfsbyname(smbfs_vfsname, &vfc);
	}
#endif
	if (error)
		errx(EX_OSERR, "SMB filesystem is not available");

	if (smb_lib_init() != 0)
		exit(1);

	mntflags = error = 0;

	caseopt = SMB_CS_NONE;

	if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 0)
		exit(1);
	if (smb_ctx_readrc(ctx) != 0)
		exit(1);
	if (smb_rc)
		rc_close(smb_rc);

	while ((opt = getopt(argc, argv, STDPARAM_OPT"c:d:f:g:l:n:o:u:w:")) != -1) {
		switch (opt) {
		    case STDPARAM_ARGS:
			error = smb_ctx_opt(ctx, opt, optarg);
			if (error)
				exit(1);
			break;
		    case 'u': {
			struct passwd *pwd;

			pwd = isdigit(optarg[0]) ?
			    getpwuid(atoi(optarg)) : getpwnam(optarg);
			if (pwd == NULL)
				errx(EX_NOUSER, "unknown user '%s'", optarg);
			uid = pwd->pw_uid;
			break;
		    }
		    case 'g': {
			struct group *grp;

			grp = isdigit(optarg[0]) ?
			    getgrgid(atoi(optarg)) : getgrnam(optarg);
			if (grp == NULL)
				errx(EX_NOUSER, "unknown group '%s'", optarg);
			gid = grp->gr_gid;
			break;
		    }
		    case 'd':
			errno = 0;
			dir_mode = strtol(optarg, &next, 8);
			if (errno || *next != 0)
				errx(EX_DATAERR, "invalid value for directory mode");
			break;
		    case 'f':
			errno = 0;
			file_mode = strtol(optarg, &next, 8);
			if (errno || *next != 0)
				errx(EX_DATAERR, "invalid value for file mode");
			break;
		    case '?':
			usage();
			/*NOTREACHED*/
		    case 'n': {
			char *inp, *nsp;

			nsp = inp = optarg;
			while ((nsp = strsep(&inp, ",;:")) != NULL) {
				if (strcasecmp(nsp, "LONG") == 0) {
					build_iovec(&iov, &iovlen,
					    "nolong", NULL, 0);
				} else {
					errx(EX_DATAERR,
					    "unknown suboption '%s'", nsp);
				}
			}
			break;
		    };
		    case 'o':
			getmntopts(optarg, mopts, &mntflags, 0);
			p = strchr(optarg, '=');
			val = NULL;
			if (p != NULL) {
				*p = '\0';
				val = p + 1;
			}
			build_iovec(&iov, &iovlen, optarg, val, (size_t)-1);
			break;
		    case 'c':
			switch (optarg[0]) {
			    case 'l':
				caseopt |= SMB_CS_LOWER;
				break;
			    case 'u':
				caseopt |= SMB_CS_UPPER;
				break;
			    default:
		    		errx(EX_DATAERR, "invalid suboption '%c' for -c",
				    optarg[0]);
			}
			break;
		    default:
			usage();
		}
	}

	if (optind == argc - 2)
		optind++;
	
	if (optind != argc - 1)
		usage();
	realpath(argv[optind], mount_point);

	if (stat(mount_point, &st) == -1)
		err(EX_OSERR, "could not find mount point %s", mount_point);
	if (!S_ISDIR(st.st_mode)) {
		errno = ENOTDIR;
		err(EX_OSERR, "can't mount on %s", mount_point);
	}
/*
	if (smb_getextattr(mount_point, &einfo) == 0)
		errx(EX_OSERR, "can't mount on %s twice", mount_point);
*/
	if (uid == (uid_t)-1)
		uid = st.st_uid;
	if (gid == (gid_t)-1)
		gid = st.st_gid;
	if (file_mode == 0 )
		file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
	if (dir_mode == 0) {
		dir_mode = file_mode;
		if (dir_mode & S_IRUSR)
			dir_mode |= S_IXUSR;
		if (dir_mode & S_IRGRP)
			dir_mode |= S_IXGRP;
		if (dir_mode & S_IROTH)
			dir_mode |= S_IXOTH;
	}
	/*
	 * For now, let connection be private for this mount
	 */
	ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE;
	ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */
	ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid;
	opt = 0;
	if (dir_mode & S_IXGRP)
		opt |= SMBM_EXECGRP;
	if (dir_mode & S_IXOTH)
		opt |= SMBM_EXECOTH;
	ctx->ct_ssn.ioc_rights |= opt;
	ctx->ct_sh.ioc_rights |= opt;
	error = smb_ctx_resolve(ctx);
	if (error)
		exit(1);
	error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
	if (error) {
		exit(1);
	}

	fd = ctx->ct_fd;

	build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1);
	build_iovec(&iov, &iovlen, "fspath", mount_point, -1);
	build_iovec_argf(&iov, &iovlen, "fd", "%d", fd);
	build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1);
	build_iovec_argf(&iov, &iovlen, "uid", "%d", uid);
	build_iovec_argf(&iov, &iovlen, "gid", "%d", gid);
	build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode);
	build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode);
	build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt);
	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg); 

	error = nmount(iov, iovlen, mntflags);
	smb_ctx_done(ctx);
	if (error) {
		smb_error("mount error: %s %s", error, mount_point, errmsg);
		exit(1);
	}
	return 0;
}
int
main(int argc, char **argv)
{
	struct iovec *iov = NULL;
	int iovlen = 0;
	struct stat sb;
	int c, set_gid, set_uid, set_mask, set_dirmask;
	char *dev, *dir, mntpath[MAXPATHLEN], *csp;
	char fstype[] = "msdosfs";
	char errmsg[255] = {0};
	char *cs_dos = NULL;
	char *cs_local = NULL;
	mode_t mask = 0, dirmask = 0;
	uid_t uid = 0;
	gid_t gid = 0;

	set_gid = set_uid = set_mask = set_dirmask = 0;

	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) {
		switch (c) {
		case 's':
			build_iovec(&iov, &iovlen, "shortnames", NULL, (size_t)-1);
			break;
		case 'l':
			build_iovec(&iov, &iovlen, "longnames", NULL, (size_t)-1);
			break;
		case '9':
			build_iovec_argf(&iov, &iovlen, "nowin95", "", (size_t)-1);
			break;
		case 'u':
			uid = a_uid(optarg);
			set_uid = 1;
			break;
		case 'g':
			gid = a_gid(optarg);
			set_gid = 1;
			break;
		case 'm':
			mask = a_mask(optarg);
			set_mask = 1;
			break;
		case 'M':
			dirmask = a_mask(optarg);
			set_dirmask = 1;
			break;
		case 'L': {
			const char *quirk = NULL;
			if (setlocale(LC_CTYPE, optarg) == NULL)
				err(EX_CONFIG, "%s", optarg);
			csp = strchr(optarg,'.');
			if (!csp)
				err(EX_CONFIG, "%s", optarg);
			quirk = kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT);
			build_iovec_argf(&iov, &iovlen, "cs_local", quirk);
			cs_local = strdup(quirk);
			}
			break;
		case 'D':
			cs_dos = strdup(optarg);
			build_iovec_argf(&iov, &iovlen, "cs_dos", cs_dos, (size_t)-1);
			break;
		case 'o': {
			char *p = NULL;
			char *val = strdup("");
			p = strchr(optarg, '=');
			if (p != NULL) {
				free(val);
				*p = '\0';
				val = p + 1;
			}
			build_iovec(&iov, &iovlen, optarg, val, (size_t)-1);
			}
			break;
		case 'W':
			if (strcmp(optarg, "iso22dos") == 0) {
				cs_local = strdup("ISO8859-2");
				cs_dos = strdup("CP852");
			} else if (strcmp(optarg, "iso72dos") == 0) {
				cs_local = strdup("ISO8859-7");
				cs_dos = strdup("CP737");
			} else if (strcmp(optarg, "koi2dos") == 0) {
				cs_local = strdup("KOI8-R");
				cs_dos = strdup("CP866");
			} else if (strcmp(optarg, "koi8u2dos") == 0) {
				cs_local = strdup("KOI8-U");
				cs_dos = strdup("CP866");
			} else {
				err(EX_NOINPUT, "%s", optarg);
			}
			build_iovec(&iov, &iovlen, "cs_local", cs_local, (size_t)-1);
			build_iovec(&iov, &iovlen, "cs_dos", cs_dos, (size_t)-1);
			break;
		case '?':
		default:
			usage();
			break;
		}
	}

	if (optind + 2 != argc)
		usage();

	if (set_mask && !set_dirmask) {
		dirmask = mask;
		set_dirmask = 1;
	}
	else if (set_dirmask && !set_mask) {
		mask = dirmask;
		set_mask = 1;
	}

	dev = argv[optind];
	dir = argv[optind + 1];

	if (cs_local != NULL) {
		if (set_charset(&iov, &iovlen, cs_local, cs_dos) == -1)
			err(EX_OSERR, "msdosfs_iconv");
		build_iovec_argf(&iov, &iovlen, "kiconv", "");
	} else if (cs_dos != NULL) {
		build_iovec_argf(&iov, &iovlen, "cs_local", "ISO8859-1");
		if (set_charset(&iov, &iovlen, "ISO8859-1", cs_dos) == -1)
			err(EX_OSERR, "msdosfs_iconv");
		build_iovec_argf(&iov, &iovlen, "kiconv", "");
	}

	/*
	 * Resolve the mountpoint with realpath(3) and remove unnecessary
	 * slashes from the devicename if there are any.
	 */
	if (checkpath(dir, mntpath) != 0)
		err(EX_USAGE, "%s", mntpath);
	(void)rmslashes(dev, dev);

	if (!set_gid || !set_uid || !set_mask) {
		if (stat(mntpath, &sb) == -1)
			err(EX_OSERR, "stat %s", mntpath);

		if (!set_uid)
			uid = sb.st_uid;
		if (!set_gid)
			gid = sb.st_gid;
		if (!set_mask)
			mask = dirmask =
				sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
	}

	build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
	build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1);
	build_iovec(&iov, &iovlen, "from", dev, (size_t)-1);
	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
	build_iovec_argf(&iov, &iovlen, "uid", "%d", uid);
	build_iovec_argf(&iov, &iovlen, "gid", "%u", gid);
	build_iovec_argf(&iov, &iovlen, "mask", "%u", mask);
	build_iovec_argf(&iov, &iovlen, "dirmask", "%u", dirmask);

	if (nmount(iov, iovlen, 0) < 0) {
		if (errmsg[0])
			err(1, "%s: %s", dev, errmsg);
		else
			err(1, "%s", dev);
	}

	exit (0);
}
Exemple #5
0
int
main(int argc, char **argv)
{
	struct iovec *iov;
	int iovlen;
	int ch, mntflags;
	char *dev, *dir, *p, *val, mntpath[MAXPATHLEN];
	int verbose;
	int ssector;		/* starting sector, 0 for 1st session */
	char fstype[] = "cd9660";

	iov = NULL;
	iovlen = 0;
	mntflags = verbose = 0;
	ssector = -1;

	while ((ch = getopt(argc, argv, "begjo:rs:vC:")) != -1)
		switch (ch) {
		case 'b':
			build_iovec(&iov, &iovlen, "brokenjoliet", NULL, (size_t)-1);
			break;
		case 'e':
			build_iovec(&iov, &iovlen, "extatt", NULL, (size_t)-1);
			break;
		case 'g':
			build_iovec(&iov, &iovlen, "gens", NULL, (size_t)-1);
			break;
		case 'j':
			build_iovec(&iov, &iovlen, "nojoliet", NULL, (size_t)-1);
			break;
		case 'o':
			getmntopts(optarg, mopts, &mntflags, NULL);
			p = strchr(optarg, '=');
			val = NULL;
			if (p != NULL) {
				*p = '\0';
				val = p + 1;
			}
			build_iovec(&iov, &iovlen, optarg, val, (size_t)-1);
			break;
		case 'r':
			build_iovec(&iov, &iovlen, "norrip", NULL, (size_t)-1);
			break;
		case 's':
			ssector = atoi(optarg);
			break;
		case 'v':
			verbose++;
			break;
		case 'C':
			if (set_charset(&iov, &iovlen, optarg) == -1)
				err(EX_OSERR, "cd9660_iconv");
			build_iovec(&iov, &iovlen, "kiconv", NULL, (size_t)-1);
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (argc != 2)
		usage();

	dev = argv[0];
	dir = argv[1];

	/*
	 * Resolve the mountpoint with realpath(3) and remove unnecessary
	 * slashes from the devicename if there are any.
	 */
	if (checkpath(dir, mntpath) != 0)
		err(1, "%s", mntpath);
	(void)rmslashes(dev, dev);

	if (ssector == -1) {
		/*
		 * The start of the session has not been specified on
		 * the command line.  If we can successfully read the
		 * TOC of a CD-ROM, use the last data track we find.
		 * Otherwise, just use 0, in order to mount the very
		 * first session.  This is compatible with the
		 * historic behaviour of mount_cd9660(8).  If the user
		 * has specified -s <ssector> above, we don't get here
		 * and leave the user's will.
		 */
		if ((ssector = get_ssector(dev)) == -1) {
			if (verbose)
				printf("could not determine starting sector, "
				       "using very first session\n");
			ssector = 0;
		} else if (verbose)
			printf("using starting sector %d\n", ssector);
	}
	mntflags |= MNT_RDONLY;
	build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
	build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1);
	build_iovec(&iov, &iovlen, "from", dev, (size_t)-1);
	build_iovec_argf(&iov, &iovlen, "ssector", "%d", ssector);

	if (nmount(iov, iovlen, mntflags) < 0)
		err(1, "%s", dev);
	exit(0);
}
Exemple #6
0
int main( int argc, char **argv ) {
	struct iovec *iov;
	int iovlen;
	int ch, mntflags;
	char *dev, *dir, *p, *val, mntpath[MAXPATHLEN];
	int verbose;
	int ssector;
	char fstype[] = "cd9660";
	iov = NULL;
	iovlen = 0;
	mntflags = verbose = 0;
	ssector = -1;
	while ( ( ch = getopt( argc, argv, "begjo:rs:vC:" ) ) != -1 )
		switch ( ch ) {
			case 'b':
				build_iovec( &iov, &iovlen, "brokenjoliet", NULL, ( size_t ) - 1 );
				break;
			case 'e':
				build_iovec( &iov, &iovlen, "extatt", NULL, ( size_t ) - 1 );
				break;
			case 'g':
				build_iovec( &iov, &iovlen, "gens", NULL, ( size_t ) - 1 );
				break;
			case 'j':
				build_iovec( &iov, &iovlen, "nojoliet", NULL, ( size_t ) - 1 );
				break;
			case 'o':
				getmntopts( optarg, mopts, &mntflags, NULL );
				p = strchr( optarg, '=' );
				val = NULL;
				if ( p != NULL ) {
					*p = '\0';
					val = p + 1;
				}
				build_iovec( &iov, &iovlen, optarg, val, ( size_t ) - 1 );
				break;
			case 'r':
				build_iovec( &iov, &iovlen, "norrip", NULL, ( size_t ) - 1 );
				break;
			case 's':
				ssector = atoi( optarg );
				break;
			case 'v':
				verbose++;
				break;
			case 'C':
				if ( set_charset( &iov, &iovlen, optarg ) == -1 ) err( EX_OSERR, "cd9660_iconv" );
				build_iovec( &iov, &iovlen, "kiconv", NULL, ( size_t ) - 1 );
				break;
			case '?':
			default:
				usage();
		}
	argc -= optind;
	argv += optind;
	if ( argc != 2 ) usage();
	dev = argv[0];
	dir = argv[1];
	if ( checkpath( dir, mntpath ) != 0 ) err( 1, "%s", mntpath );
	(void) rmslashes( dev, dev );
	if ( ssector == -1 ) {
		if ( ( ssector = get_ssector( dev ) ) == -1 ) {
			if ( verbose ) printf( "could not determine starting sector, "
					"using very first session\n" );
			ssector = 0;
		} else if ( verbose ) printf( "using starting sector %d\n", ssector );
	}
	mntflags |= MNT_RDONLY;
	build_iovec( &iov, &iovlen, "fstype", fstype, ( size_t ) - 1 );
	build_iovec( &iov, &iovlen, "fspath", mntpath, ( size_t ) - 1 );
	build_iovec( &iov, &iovlen, "from", dev, ( size_t ) - 1 );
	build_iovec_argf( &iov, &iovlen, "ssector", "%d", ssector );
	if ( nmount( iov, iovlen, mntflags ) < 0 ) err( 1, "%s", dev );
	exit( 0 );
}
Exemple #7
0
int
main(int argc, char *argv[])
{
	struct stat stbuf;
	struct statfs statfsbuf, totalbuf;
	struct maxwidths maxwidths;
	struct statfs *mntbuf;
#ifdef MOUNT_CHAR_DEVS
	struct iovec *iov = NULL;
#endif
	const char *fstype;
#ifdef MOUNT_CHAR_DEVS
	char *mntpath;
	char errmsg[255] = {0};
#endif
	char *mntpt;
	const char **vfslist;
	int i, mntsize;
	int ch, rv;
#ifdef MOUNT_CHAR_DEVS
	int iovlen = 0;
#endif

	fstype = "ufs";
	(void)setlocale(LC_ALL, "");
	memset(&maxwidths, 0, sizeof(maxwidths));
	memset(&totalbuf, 0, sizeof(totalbuf));
	totalbuf.f_bsize = DEV_BSIZE;
	strlcpy(totalbuf.f_mntfromname, "total", MNAMELEN);
	vfslist = NULL;

	argc = xo_parse_args(argc, argv);
	if (argc < 0)
		exit(1);

	while ((ch = getopt(argc, argv, "abcgHhiklmnPt:T,")) != -1)
		switch (ch) {
		case 'a':
			aflag = 1;
			break;
		case 'b':
				/* FALLTHROUGH */
		case 'P':
			/*
			 * POSIX specifically discusses the behavior of
			 * both -k and -P. It states that the blocksize should
			 * be set to 1024. Thus, if this occurs, simply break
			 * rather than clobbering the old blocksize.
			 */
			if (kflag)
				break;
			setenv("BLOCKSIZE", "512", 1);
			hflag = 0;
			break;
		case 'c':
			cflag = 1;
			break;
		case 'g':
			setenv("BLOCKSIZE", "1g", 1);
			hflag = 0;
			break;
		case 'H':
			hflag = UNITS_SI;
			break;
		case 'h':
			hflag = UNITS_2;
			break;
		case 'i':
			iflag = 1;
			break;
		case 'k':
			kflag++;
			setenv("BLOCKSIZE", "1024", 1);
			hflag = 0;
			break;
		case 'l':
			/* Ignore duplicate -l */
			if (lflag)
				break;
			if (vfslist != NULL)
				xo_errx(1, "-l and -t are mutually exclusive.");
			vfslist = makevfslist(makenetvfslist());
			lflag = 1;
			break;
		case 'm':
			setenv("BLOCKSIZE", "1m", 1);
			hflag = 0;
			break;
		case 'n':
			nflag = 1;
			break;
		case 't':
			if (lflag)
				xo_errx(1, "-l and -t are mutually exclusive.");
			if (vfslist != NULL)
				xo_errx(1, "only one -t option may be specified");
			fstype = optarg;
			vfslist = makevfslist(optarg);
			break;
		case 'T':
			Tflag = 1;
			break;
		case ',':
			thousands = 1;
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	rv = 0;
	if (!*argv) {
		/* everything (modulo -t) */
		mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
		mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
	} else {
		/* just the filesystems specified on the command line */
		mntbuf = malloc(argc * sizeof(*mntbuf));
		if (mntbuf == NULL)
			xo_err(1, "malloc()");
		mntsize = 0;
		/* continued in for loop below */
	}

	xo_open_container("storage-system-information");
	xo_open_list("filesystem");

	/* iterate through specified filesystems */
	for (; *argv; argv++) {
		if (stat(*argv, &stbuf) < 0) {
			if ((mntpt = getmntpt(*argv)) == NULL) {
				xo_warn("%s", *argv);
				rv = 1;
				continue;
			}
#ifdef MOUNT_CHAR_DEVS
		} else if (S_ISCHR(stbuf.st_mode)) {
			if ((mntpt = getmntpt(*argv)) == NULL) {
				mdev.fspec = *argv;
				mntpath = strdup("/tmp/df.XXXXXX");
				if (mntpath == NULL) {
					xo_warn("strdup failed");
					rv = 1;
					continue;
				}
				mntpt = mkdtemp(mntpath);
				if (mntpt == NULL) {
					xo_warn("mkdtemp(\"%s\") failed", mntpath);
					rv = 1;
					free(mntpath);
					continue;
				}
				if (iov != NULL)
					free_iovec(&iov, &iovlen);
				build_iovec_argf(&iov, &iovlen, "fstype", "%s",
				    fstype);
				build_iovec_argf(&iov, &iovlen, "fspath", "%s",
				    mntpath);
				build_iovec_argf(&iov, &iovlen, "from", "%s",
				    *argv);
				build_iovec(&iov, &iovlen, "errmsg", errmsg,
				    sizeof(errmsg));
				if (nmount(iov, iovlen,
				    MNT_RDONLY|MNT_NOEXEC) < 0) {
					if (errmsg[0])
						xo_warn("%s: %s", *argv,
						    errmsg);
					else
						xo_warn("%s", *argv);
					rv = 1;
					(void)rmdir(mntpt);
					free(mntpath);
					continue;
				} else if (statfs(mntpt, &statfsbuf) == 0) {
					statfsbuf.f_mntonname[0] = '\0';
					prtstat(&statfsbuf, &maxwidths);
					if (cflag)
						addstat(&totalbuf, &statfsbuf);
				} else {
					xo_warn("%s", *argv);
					rv = 1;
				}
				(void)unmount(mntpt, 0);
				(void)rmdir(mntpt);
				free(mntpath);
				continue;
			}
#endif
		} else
			mntpt = *argv;

		/*
		 * Statfs does not take a `wait' flag, so we cannot
		 * implement nflag here.
		 */
		if (statfs(mntpt, &statfsbuf) < 0) {
			xo_warn("%s", mntpt);
			rv = 1;
			continue;
		}

		/*
		 * Check to make sure the arguments we've been given are
		 * satisfied.  Return an error if we have been asked to
		 * list a mount point that does not match the other args
		 * we've been given (-l, -t, etc.).
		 */
		if (checkvfsname(statfsbuf.f_fstypename, vfslist)) {
			rv = 1;
			continue;
		}

		/* the user asked for it, so ignore the ignore flag */
		statfsbuf.f_flags &= ~MNT_IGNORE;

		/* add to list */
		mntbuf[mntsize++] = statfsbuf;
	}

	memset(&maxwidths, 0, sizeof(maxwidths));
	for (i = 0; i < mntsize; i++) {
		if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0) {
			update_maxwidths(&maxwidths, &mntbuf[i]);
			if (cflag)
				addstat(&totalbuf, &mntbuf[i]);
		}
	}
	for (i = 0; i < mntsize; i++)
		if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
			prtstat(&mntbuf[i], &maxwidths);

	xo_close_list("filesystem");

	if (cflag)
		prtstat(&totalbuf, &maxwidths);

	xo_close_container("storage-system-information");
	xo_finish();
	exit(rv);
}