Exemplo n.º 1
0
/*
 * Get the ZFS volume name out of the given path
 */
int
get_zfsvolname(char *volname, int len, char *path)
{
    struct stat64 stbuf;
    struct extmnttab ent;
    FILE *mntfp;
    int rv;

    *volname = '\0';
    if (stat64(path, &stbuf) != 0) {
        return (-1);
    }

    if ((mntfp = fopen(MNTTAB, "r")) == NULL) {
        return (-1);
    }
    while ((rv = getextmntent(mntfp, &ent, 0)) == 0) {
        if (makedevice(ent.mnt_major, ent.mnt_minor) ==
                stbuf.st_dev)
            break;
    }

    if (rv == 0 &&
            strcmp(ent.mnt_fstype, MNTTYPE_ZFS) == 0)
        (void) strlcpy(volname, ent.mnt_special, len);
    else
        rv = -1;

    (void) fclose(mntfp);
    return (rv);
}
Exemplo n.º 2
0
static int
setmntpaths_stat(struct stat const *st, struct nix_statfs *dest, nix_env_t *env)
{
	FILE             *fp;
	struct extmnttab  ent;

	fp = fopen("/etc/mnttab", "r");
	if(fp == NULL) {
		nix_env_set_errno(env, errno);
		return (-1);
	}

#ifdef HAVE_RESETMNTTAB
	resetmnttab(fp);
#endif

	while ((getextmntent(fp, &ent, sizeof(ent))) == 0) {
		if (ent.mnt_major == major(st->st_dev) &&
		  ent.mnt_minor == minor(st->st_dev)) {
			setmntpaths_mntent(&ent, dest);
			break;
		}
	}

	fclose(fp);
}
Exemplo n.º 3
0
/* ZFS has similar problems to those of btrfs (see above).  */
void
grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs)
{
  char *slash;

  *poolname = *poolfs = NULL;

#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
  /* FreeBSD and GNU/kFreeBSD.  */
  {
    struct statfs mnt;

    if (statfs (dir, &mnt) != 0)
      return;

    if (strcmp (mnt.f_fstypename, "zfs") != 0)
      return;

    *poolname = xstrdup (mnt.f_mntfromname);
  }
#elif defined(HAVE_GETEXTMNTENT)
  /* Solaris.  */
  {
    struct stat st;
    struct extmnttab mnt;

    if (stat (dir, &st) != 0)
      return;

    FILE *mnttab = grub_util_fopen ("/etc/mnttab", "r");
    if (! mnttab)
      return;

    while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0)
      {
	if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev
	    && !strcmp (mnt.mnt_fstype, "zfs"))
	  {
	    *poolname = xstrdup (mnt.mnt_special);
	    break;
	  }
      }

    fclose (mnttab);
  }
#endif

  if (! *poolname)
    return;

  slash = strchr (*poolname, '/');
  if (slash)
    {
      *slash = '\0';
      *poolfs = xstrdup (slash + 1);
    }
  else
    *poolfs = xstrdup ("");
}
Exemplo n.º 4
0
static void
build_mnt_list(FILE *mpt)
{
	mnt_t *item;
	mnt_t **which;
	mnt_t *tmp;
	int  found;
	struct extmnttab mnt;

	if (mpt) {
		while (nfs) {
			free(nfs->device_name);
			free(nfs->mount_point);
			free(nfs->devinfo);
			tmp = nfs;
			nfs = nfs->next;
			free(tmp);
		}
		while (ufs) {
			free(ufs->device_name);
			free(ufs->mount_point);
			free(ufs->devinfo);
			tmp = ufs;
			ufs = ufs->next;
			free(tmp);
		}
		(void) memset(&mnt, 0, sizeof (struct extmnttab));

		resetmnttab(mpt);
		while ((found = getextmntent(mpt, &mnt,
			sizeof (struct extmnttab))) != -1) {
			if (found == 0) {
				if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) == 0)
					which = &ufs;
				else if (strcmp(mnt.mnt_fstype,
				    MNTTYPE_NFS) == 0)
					which = &nfs;
				else
					which = 0;
				if (which) {
					item = safe_alloc(sizeof (mnt_t));
					item->device_name =
						safe_strdup(mnt.mnt_special);
					item->mount_point =
						safe_strdup(mnt.mnt_mountp);
					item->devinfo =
						safe_strdup(mnt.mnt_mntopts);
					item->minor = mnt.mnt_minor;
					item->next = *which;
					*which = item;
				}
			}
		}
	}
}
Exemplo n.º 5
0
void
print_mnttab(int vflg, int pflg)
{
	FILE	*fd;
	FILE	*rfp;			/* this will be NULL if fopen fails */
	int	ret;
	char	time_buf[TIME_MAX];	/* array to hold date and time */
	struct extmnttab	mget;
	time_t	ltime;

	if ((fd = fopen(mnttab, "r")) == NULL) {
		fprintf(stderr, gettext("%s: Cannot open mnttab\n"), myname);
		exit(1);
	}
	rfp = fopen(REMOTE, "r");
	while ((ret = getextmntent(fd, &mget, sizeof (struct extmnttab)))
	    == 0) {
		if (ignore(mget.mnt_mntopts))
			continue;
		if (mget.mnt_special && mget.mnt_mountp &&
		    mget.mnt_fstype && mget.mnt_time) {
			ltime = atol(mget.mnt_time);
			cftime(time_buf, FORMAT, &ltime);
			if (pflg) {
				elide_dev(mget.mnt_mntopts);
				printf("%s - %s %s - no %s\n",
				    mget.mnt_special,
				    mget.mnt_mountp,
				    mget.mnt_fstype,
				    mget.mnt_mntopts != NULL ?
				    mget.mnt_mntopts : "-");
			} else if (vflg) {
				printf("%s on %s type %s %s%s on %s",
				    mget.mnt_special,
				    mget.mnt_mountp,
				    mget.mnt_fstype,
				    remote(mget.mnt_fstype, rfp),
				    flags(mget.mnt_mntopts, NEW),
				    time_buf);
			} else
				printf("%s on %s %s%s on %s",
				    mget.mnt_mountp,
				    mget.mnt_special,
				    remote(mget.mnt_fstype, rfp),
				    flags(mget.mnt_mntopts, OLD),
				    time_buf);
		}
	}
	if (ret > 0)
		mnterror(ret);
}
Exemplo n.º 6
0
/*
 * Print the mount table info
 */
static void
mi_print(void)
{
	FILE *mt;
	struct extmnttab m;
	struct myrec *list, *mrp, *pmrp;
	char *flavor;
	int ignored = 0;
	seconfig_t nfs_sec;
	kstat_t *ksp;
	struct mntinfo_kstat mik;
	int transport_flag = 0;
	int path_count;
	int found;
	char *timer_name[] = {
		"Lookups",
		"Reads",
		"Writes",
		"All"
	};

	mt = fopen(MNTTAB, "r");
	if (mt == NULL) {
		perror(MNTTAB);
		exit(0);
	}

	list = NULL;
	resetmnttab(mt);

	while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) {
		/* ignore non "nfs" and save the "ignore" entries */
		if (strcmp(m.mnt_fstype, MNTTYPE_NFS) != 0)
			continue;
		/*
		 * Check to see here if user gave a path(s) to
		 * only show the mount point they wanted
		 * Iterate through the list of paths the user gave and see
		 * if any of them match our current nfs mount
		 */
		if (path[0] != NULL) {
			found = 0;
			for (path_count = 0; path[path_count] != NULL;
			    path_count++) {
				if (strcmp(path[path_count], m.mnt_mountp)
				    == 0) {
					found = 1;
					break;
				}
			}
			if (!found)
				continue;
		}

		if ((mrp = malloc(sizeof (struct myrec))) == 0) {
			fprintf(stderr, "nfsstat: not enough memory\n");
			exit(1);
		}
		mrp->my_fsid = makedev(m.mnt_major, m.mnt_minor);
		if (ignore(m.mnt_mntopts)) {
			/*
			 * ignored entries cannot be ignored for this
			 * option. We have to display the info for this
			 * nfs mount. The ignore is an indication
			 * that the actual mount point is different and
			 * something is in between the nfs mount.
			 * So save the mount point now
			 */
			if ((mrp->ig_path = malloc(
			    strlen(m.mnt_mountp) + 1)) == 0) {
				fprintf(stderr, "nfsstat: not enough memory\n");
				exit(1);
			}
			(void) strcpy(mrp->ig_path, m.mnt_mountp);
			ignored++;
		} else {
			mrp->ig_path = 0;
			(void) strcpy(mrp->my_dir, m.mnt_mountp);
		}
		if ((mrp->my_path = strdup(m.mnt_special)) == NULL) {
			fprintf(stderr, "nfsstat: not enough memory\n");
			exit(1);
		}
		mrp->next = list;
		list = mrp;
	}

	/*
	 * If something got ignored, go to the beginning of the mnttab
	 * and look for the cachefs entries since they are the one
	 * causing this. The mount point saved for the ignored entries
	 * is matched against the special to get the actual mount point.
	 * We are interested in the acutal mount point so that the output
	 * look nice too.
	 */
	if (ignored) {
		rewind(mt);
		resetmnttab(mt);
		while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) {

			/* ignore non "cachefs" */
			if (strcmp(m.mnt_fstype, MNTTYPE_CACHEFS) != 0)
				continue;

			for (mrp = list; mrp; mrp = mrp->next) {
				if (mrp->ig_path == 0)
					continue;
				if (strcmp(mrp->ig_path, m.mnt_special) == 0) {
					mrp->ig_path = 0;
					(void) strcpy(mrp->my_dir,
					    m.mnt_mountp);
				}
			}
		}
		/*
		 * Now ignored entries which do not have
		 * the my_dir initialized are really ignored; This never
		 * happens unless the mnttab is corrupted.
		 */
		for (pmrp = 0, mrp = list; mrp; mrp = mrp->next) {
			if (mrp->ig_path == 0)
				pmrp = mrp;
			else if (pmrp)
				pmrp->next = mrp->next;
			else
				list = mrp->next;
		}
	}

	(void) fclose(mt);


	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
		int i;

		if (ksp->ks_type != KSTAT_TYPE_RAW)
			continue;
		if (strcmp(ksp->ks_module, "nfs") != 0)
			continue;
		if (strcmp(ksp->ks_name, "mntinfo") != 0)
			continue;

		for (mrp = list; mrp; mrp = mrp->next) {
			if ((mrp->my_fsid & MAXMIN) == ksp->ks_instance)
				break;
		}
		if (mrp == 0)
			continue;

		if (safe_kstat_read(kc, ksp, &mik) == -1)
			continue;

		printf("%s from %s\n", mrp->my_dir, mrp->my_path);

		/*
		 * for printing rdma transport and provider string.
		 * This way we avoid modifying the kernel mntinfo_kstat
		 * struct for protofmly.
		 */
		if (strcmp(mik.mik_proto, "ibtf") == 0) {
			printf(" Flags:		vers=%u,proto=rdma",
			    mik.mik_vers);
			transport_flag = 1;
		} else {
			printf(" Flags:		vers=%u,proto=%s",
			    mik.mik_vers, mik.mik_proto);
			transport_flag = 0;
		}

		/*
		 *  get the secmode name from /etc/nfssec.conf.
		 */
		if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) {
			flavor = nfs_sec.sc_name;
		} else
			flavor = NULL;

		if (flavor != NULL)
			printf(",sec=%s", flavor);
		else
			printf(",sec#=%d", mik.mik_secmod);

		printf(",%s", (mik.mik_flags & MI_HARD) ? "hard" : "soft");
		if (mik.mik_flags & MI_PRINTED)
			printf(",printed");
		printf(",%s", (mik.mik_flags & MI_INT) ? "intr" : "nointr");
		if (mik.mik_flags & MI_DOWN)
			printf(",down");
		if (mik.mik_flags & MI_NOAC)
			printf(",noac");
		if (mik.mik_flags & MI_NOCTO)
			printf(",nocto");
		if (mik.mik_flags & MI_DYNAMIC)
			printf(",dynamic");
		if (mik.mik_flags & MI_LLOCK)
			printf(",llock");
		if (mik.mik_flags & MI_GRPID)
			printf(",grpid");
		if (mik.mik_flags & MI_RPCTIMESYNC)
			printf(",rpctimesync");
		if (mik.mik_flags & MI_LINK)
			printf(",link");
		if (mik.mik_flags & MI_SYMLINK)
			printf(",symlink");
		if (mik.mik_vers < NFS_V4 && mik.mik_flags & MI_READDIRONLY)
			printf(",readdironly");
		if (mik.mik_flags & MI_ACL)
			printf(",acl");

		if (mik.mik_vers >= NFS_V4) {
			if (mik.mik_flags & MI4_MIRRORMOUNT)
				printf(",mirrormount");
		}

		printf(",rsize=%d,wsize=%d,retrans=%d,timeo=%d",
		    mik.mik_curread, mik.mik_curwrite, mik.mik_retrans,
		    mik.mik_timeo);
		printf("\n");
		printf(" Attr cache:	acregmin=%d,acregmax=%d"
		    ",acdirmin=%d,acdirmax=%d\n", mik.mik_acregmin,
		    mik.mik_acregmax, mik.mik_acdirmin, mik.mik_acdirmax);

		if (transport_flag) {
			printf(" Transport:	proto=rdma, plugin=%s\n",
			    mik.mik_proto);
		}

#define	srtt_to_ms(x) x, (x * 2 + x / 2)
#define	dev_to_ms(x) x, (x * 5)

		for (i = 0; i < NFS_CALLTYPES + 1; i++) {
			int j;

			j = (i == NFS_CALLTYPES ? i - 1 : i);
			if (mik.mik_timers[j].srtt ||
			    mik.mik_timers[j].rtxcur) {
				printf(" %s:     srtt=%d (%dms), "
				    "dev=%d (%dms), cur=%u (%ums)\n",
				    timer_name[i],
				    srtt_to_ms(mik.mik_timers[i].srtt),
				    dev_to_ms(mik.mik_timers[i].deviate),
				    mik.mik_timers[i].rtxcur,
				    mik.mik_timers[i].rtxcur * 20);
			}
		}

		if (strchr(mrp->my_path, ','))
			printf(
			    " Failover:	noresponse=%d,failover=%d,"
			    "remap=%d,currserver=%s\n",
			    mik.mik_noresponse, mik.mik_failover,
			    mik.mik_remap, mik.mik_curserver);
		printf("\n");
	}
}
Exemplo n.º 7
0
/*
 * Given a full path to a file, translate into a dataset name and a relative
 * path within the dataset.  'dataset' must be at least MAXNAMELEN characters,
 * and 'relpath' must be at least MAXPATHLEN characters.  We also pass a stat64
 * buffer, which we need later to get the object ID.
 */
static int
parse_pathname(const char *inpath, char *dataset, char *relpath,
    struct stat64 *statbuf)
{
	struct extmnttab mp;
	FILE *fp;
	int match;
	const char *rel;
	char fullpath[MAXPATHLEN];

	compress_slashes(inpath, fullpath);

	if (fullpath[0] != '/') {
		(void) fprintf(stderr, "invalid object '%s': must be full "
		    "path\n", fullpath);
		usage();
		return (-1);
	}

	if (strlen(fullpath) >= MAXPATHLEN) {
		(void) fprintf(stderr, "invalid object; pathname too long\n");
		return (-1);
	}

	if (stat64(fullpath, statbuf) != 0) {
		(void) fprintf(stderr, "cannot open '%s': %s\n",
		    fullpath, strerror(errno));
		return (-1);
	}

	if ((fp = fopen(MNTTAB, "r")) == NULL) {
		(void) fprintf(stderr, "cannot open /etc/mnttab\n");
		return (-1);
	}

	match = 0;
	while (getextmntent(fp, &mp, sizeof (mp)) == 0) {
		if (makedev(mp.mnt_major, mp.mnt_minor) == statbuf->st_dev) {
			match = 1;
			break;
		}
	}

	if (!match) {
		(void) fprintf(stderr, "cannot find mountpoint for '%s'\n",
		    fullpath);
		return (-1);
	}

	if (strcmp(mp.mnt_fstype, MNTTYPE_ZFS) != 0) {
		(void) fprintf(stderr, "invalid path '%s': not a ZFS "
		    "filesystem\n", fullpath);
		return (-1);
	}

	if (strncmp(fullpath, mp.mnt_mountp, strlen(mp.mnt_mountp)) != 0) {
		(void) fprintf(stderr, "invalid path '%s': mountpoint "
		    "doesn't match path\n", fullpath);
		return (-1);
	}

	(void) strcpy(dataset, mp.mnt_special);

	rel = fullpath + strlen(mp.mnt_mountp);
	if (rel[0] == '/')
		rel++;
	(void) strcpy(relpath, rel);

	return (0);
}
Exemplo n.º 8
0
void
print_mnttab(int vflg, int pflg)
{
	FILE	*fd;
	FILE	*rfp;			/* this will be NULL if fopen fails */
	int	ret;
	char	time_buf[TIME_MAX];	/* array to hold date and time */
	struct extmnttab	mget;
	time_t	ltime;
#ifdef MNTFS_DISABLE
	struct mnttab	gmtab;
#endif	/* MNTFS_DISABLE */

	if ((fd = fopen(mnttab, "r")) == NULL) {
		fprintf(stderr, gettext("%s: Cannot open mnttab\n"), myname);
		exit(1);
	}
	rfp = fopen(REMOTE, "r");
#ifndef MNTFS_DISABLE
	while ((ret = getextmntent(fd, &mget, sizeof (struct extmnttab)))
	    == 0) {
#else
	while ((ret = getmntent(fd, &gmtab)) == 0) {
		struct stat64 msb;

		if (stat64(gmtab.mnt_mountp, &msb) == -1) {
			fprintf(stderr,
			    gettext("%s: Cannot stat mnttab\n"), myname);
			exit(2);
		}
		mget.mnt_special = gmtab.mnt_special;
		mget.mnt_mountp = gmtab.mnt_mountp;
		mget.mnt_fstype = gmtab.mnt_fstype;
		mget.mnt_mntopts = gmtab.mnt_mntopts;
		mget.mnt_time = gmtab.mnt_time;
		mget.mnt_major = (uint_t) major(msb.st_dev);
		mget.mnt_minor = (uint_t) minor(msb.st_dev);

#endif	/* MNTFS_DISABLE */
		if (ignore(mget.mnt_mntopts))
			continue;
		if (mget.mnt_special && mget.mnt_mountp &&
		    mget.mnt_fstype && mget.mnt_time) {
			ltime = atol(mget.mnt_time);
			cftime(time_buf, FORMAT, &ltime);
			if (pflg) {
				elide_dev(mget.mnt_mntopts);
				printf("%s - %s %s - no %s\n",
				    mget.mnt_special,
				    mget.mnt_mountp,
				    mget.mnt_fstype,
				    mget.mnt_mntopts != NULL ?
				    mget.mnt_mntopts : "-");
			} else if (vflg) {
				printf("%s on %s type %s %s%s on %s",
				    mget.mnt_special,
				    mget.mnt_mountp,
				    mget.mnt_fstype,
				    remote(mget.mnt_fstype, rfp),
				    flags(mget.mnt_mntopts, NEW),
				    time_buf);
			} else
				printf("%s on %s %s%s on %s",
				    mget.mnt_mountp,
				    mget.mnt_special,
				    remote(mget.mnt_fstype, rfp),
				    flags(mget.mnt_mntopts, OLD),
				    time_buf);
		}
	}
	if (ret > 0)
		mnterror(ret);
}

char	*
flags(char *mntopts, int flag)
{
	char	opts[sizeof (mntflags)];
	char	*value;
	int	rdwr = 1;
	int	suid = 1;
	int	devices = 1;
	int	setuid = 1;

	if (mntopts == NULL || *mntopts == '\0')
		return ("read/write/setuid/devices");

	strcpy(opts, "");
	while (*mntopts != '\0')  {
		switch (getsubopt(&mntopts, myopts, &value)) {
		case READONLY:
			rdwr = 0;
			break;
		case READWRITE:
			rdwr = 1;
			break;
		case SUID:
			suid = 1;
			break;
		case NOSUID:
			suid = 0;
			break;
		case SETUID:
			setuid = 1;
			break;
		case NOSETUID:
			setuid = 0;
			break;
		case DEVICES:
			devices = 1;
			break;
		case NODEVICES:
			devices = 0;
			break;
		default:
			/* cat '/' separator to mntflags */
			if (*opts != '\0' && value != NULL)
				strcat(opts, "/");
			strcat(opts, value);
			break;
		}
	}

	strcpy(mntflags, "");
	if (rdwr)
		strcat(mntflags, "read/write");
	else if (flag == OLD)
		strcat(mntflags, "read only");
	else
		strcat(mntflags, "read-only");
	if (suid) {
		if (setuid)
			strcat(mntflags, "/setuid");
		else
			strcat(mntflags, "/nosetuid");
		if (devices)
			strcat(mntflags, "/devices");
		else
			strcat(mntflags, "/nodevices");
	} else {
		strcat(mntflags, "/nosetuid/nodevices");
	}
	if (*opts != '\0') {
		strcat(mntflags, "/");
		strcat(mntflags, opts);
	}

	/*
	 * The assumed assertion
	 * 	assert (strlen(mntflags) < sizeof mntflags);
	 * is valid at this point in the code. Note that a call to "assert"
	 * is not appropriate in production code since it halts the program.
	 */
	return (mntflags);
}
Exemplo n.º 9
0
/*
 * Given a name, determine whether or not it's a valid path
 * (starts with '/' or "./").  If so, walk the mnttab trying
 * to match the device number.  If not, treat the path as an
 * fs/vol/snap name.
 */
zfs_handle_t *
zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
{
#if _DARWIN_FEATURE_64_BIT_INODE
	
	struct stat statbuf;
#else
	struct stat64 statbuf;
#endif
#ifdef __APPLE__
	struct statfs *sfsp;
	int nitems;
#else
	struct extmnttab entry;
	int ret;
#endif

	if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) {
		/*
		 * It's not a valid path, assume it's a name of type 'argtype'.
		 */
		return (zfs_open(hdl, path, argtype));
	}

#if _DARWIN_FEATURE_64_BIT_INODE
	if (stat(path, &statbuf) != 0) {
#else
	if (stat64(path, &statbuf) != 0) {
#endif
		(void) fprintf(stderr, "%s: %s\n", path, strerror(errno));
		return (NULL);
	}

#ifdef __APPLE__
	if ((nitems = getmntinfo(&sfsp, MNT_WAIT)) == 0) {
		return (NULL);
	}
	while (nitems--) {
		if (sfsp->f_fsid.val[0] == statbuf.st_dev) {
			break;
		}
	}
	if (strcmp(sfsp->f_fstypename, MNTTYPE_ZFS) != 0) {
		(void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),
		    path);
		return (NULL);
	}
	return (zfs_open(hdl, sfsp->f_mntonname, ZFS_TYPE_FILESYSTEM));
#else
	rewind(hdl->libzfs_mnttab);
	while ((ret = getextmntent(hdl->libzfs_mnttab, &entry, 0)) == 0) {
		if (makedevice(entry.mnt_major, entry.mnt_minor) ==
		    statbuf.st_dev) {
			break;
		}
	}
	if (ret != 0) {
		return (NULL);
	}

	if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
		(void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),
		    path);
		return (NULL);
	}

	return (zfs_open(hdl, entry.mnt_special, ZFS_TYPE_FILESYSTEM));
#endif
}

/*
 * Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from
 * an ioctl().
 */
int
zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
{
	if (len == 0)
		len = 2048;
	zc->zc_nvlist_dst_size = len;
	if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
	    zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0)
		return (-1);

	return (0);
}

/*
 * Called when an ioctl() which returns an nvlist fails with ENOMEM.  This will
 * expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was
 * filled in by the kernel to indicate the actual required size.
 */
int
zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
{
	free((void *)(uintptr_t)zc->zc_nvlist_dst);
	if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
	    zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0)
		return (-1);

	return (0);
}
Exemplo n.º 10
0
Arquivo: fs.c Projeto: alex-tools/nad
int main(int argc, char **argv) {
  struct extmnttab mnt;
  FILE *fp;

  fp = fopen("/etc/mnttab", "r");
  if(!fp) {
    perror("fopen");
    exit(-1);
  }

  while(getextmntent(fp, &mnt, sizeof (struct extmnttab)) == 0) {
    struct statvfs buf;
    int i;

    for(i=0;suppress_fstype[i] != NULL;i++)
      if(!strcmp(mnt.mnt_fstype, suppress_fstype[i])) break;

    if (suppress_fstype[i] == NULL && statvfs(mnt.mnt_mountp, &buf) == 0) {
      if(!strcmp(mnt.mnt_fstype, "zfs")) {
        uint64_t used, avail;
        uint64_t *space_used = NULL, *space_avail = NULL;
        libzfs_handle_t *zfsh = libzfs_init();
        zfs_handle_t *handle = zfs_path_to_zhandle(zfsh, (char *)mnt.mnt_mountp, ZFS_TYPE_FILESYSTEM);
        if(handle) {
          char source[ZFS_MAXNAMELEN];
          zprop_source_t srctype;
          int rv;
#define ZFS_PULL_N_PRINT(prop, name, T, F, expr) do { \
  uint64_t datum; \
  if(zfs_prop_get_numeric(handle, prop, \
                          &datum, &srctype, source, sizeof(source)) == 0) { \
      printf("zfs`%s`" name "\t" T" \t" F "\n", mnt.mnt_mountp, expr); \
  } \
} while(0)

          uint64_t used = -1, avail = -1;
          if(zfs_prop_get_numeric(handle, ZFS_PROP_USEDDS,
                                  &used, &srctype,
                                  source, sizeof(source)) == 0) {
            printf("zfs`%s`used\tL\t%llu\n", mnt.mnt_mountp, used);
          }
          if(zfs_prop_get_numeric(handle, ZFS_PROP_AVAILABLE,
                                  &avail, &srctype,
                                  source, sizeof(source)) == 0) {
            printf("zfs`%s`avail\tL\t%llu\n", mnt.mnt_mountp, avail);
          }
          if(used != -1 && avail != -1) {
            printf("zfs`%s`used_percent\tn\t%f\n", mnt.mnt_mountp, 100.0 * (used / (double)(used + avail)));
          }

          ZFS_PULL_N_PRINT(ZFS_PROP_USEDCHILD, "used_children", "L", "%llu", datum);
          ZFS_PULL_N_PRINT(ZFS_PROP_USEDSNAP, "used_snapshot", "L", "%llu", datum);
          ZFS_PULL_N_PRINT(ZFS_PROP_REFERENCED, "referenced", "L", "%llu", datum);
          ZFS_PULL_N_PRINT(ZFS_PROP_RECORDSIZE, "record_size", "L", "%llu", datum);
          ZFS_PULL_N_PRINT(ZFS_PROP_QUOTA, "quota", "L", "%llu", datum);
          ZFS_PULL_N_PRINT(ZFS_PROP_RESERVATION, "reservation", "L", "%llu", datum);
          ZFS_PULL_N_PRINT(ZFS_PROP_REFRESERVATION, "ref_reservation", "L", "%llu", datum);
          ZFS_PULL_N_PRINT(ZFS_PROP_USEDREFRESERV, "ref_reservation_used", "L", "%llu", datum);
#ifdef HAVE_LOGICAL_USED
  ZFS_PULL_N_PRINT(ZFS_PROP_LOGICALUSED, "logical_used", "L", "%llu", datum);
  ZFS_PULL_N_PRINT(ZFS_PROP_LOGICALREFERENCED, "logical_referenced", "L", "%llu", datum);
#endif
          ZFS_PULL_N_PRINT(ZFS_PROP_COMPRESSRATIO, "compress_ratio", "n", "%f", (double)datum/100.0);
          zfs_close(handle);
        }
        libzfs_fini(zfsh);
      }
      else {
        printf("fs`%s`f_bsize\tL\t%llu\n", mnt.mnt_mountp, buf.f_bsize);
        printf("fs`%s`f_frsize\tL\t%llu\n", mnt.mnt_mountp, buf.f_frsize);
        printf("fs`%s`f_blocks\tL\t%llu\n", mnt.mnt_mountp, buf.f_blocks);
        printf("fs`%s`f_bfree\tL\t%llu\n", mnt.mnt_mountp, buf.f_bfree);
        printf("fs`%s`f_bavail\tL\t%llu\n", mnt.mnt_mountp, buf.f_bavail);
        printf("fs`%s`f_files\tL\t%llu\n", mnt.mnt_mountp, buf.f_blocks);
        printf("fs`%s`f_ffree\tL\t%llu\n", mnt.mnt_mountp, buf.f_ffree);
        printf("fs`%s`f_favail\tL\t%llu\n", mnt.mnt_mountp, buf.f_favail);
      }
    }
  }
  exit(0);
}
Exemplo n.º 11
0
/*
 * Verify the filesystem type for a regular statefile is "ufs"
 * or verify a block device is not in use as a mounted filesytem.
 * Returns 1 if any error, otherwise 0.
 */
static int
check_mount(char *sfile, dev_t sfdev, int ufs)
{
	char *src, *err_fmt = NULL, *mnttab = MNTTAB;
	int rgent, match = 0;
	struct mnttab zroot = { 0 };
	struct mnttab entry;
	struct extmnttab ent;
	FILE *fp;

	if ((fp = fopen(mnttab, "r")) == NULL) {
		mesg(MERR, open_fmt, mnttab, strerror(errno));
		return (1);
	}

	if (ufs) {
		zroot.mnt_mountp = "/";
		zroot.mnt_fstype = "zfs";
		if (getmntany(fp, &entry, &zroot) == 0) {
			err_fmt = "ufs statefile with zfs root is not"
			    " supported\n";
			mesg(MERR, err_fmt, sfile);
			(void) fclose(fp);
			return (1);
		}
		resetmnttab(fp);
	}
	/*
	 * Search for a matching dev_t;
	 * ignore non-ufs filesystems for a regular statefile.
	 */
	while ((rgent = getextmntent(fp, &ent, sizeof (ent))) != -1) {
		if (rgent > 0) {
			mesg(MERR, "error reading \"%s\"\n", mnttab);
			(void) fclose(fp);
			return (1);
		} else if (ufs && strcmp(ent.mnt_fstype, "ufs"))
			continue;
		else if (makedev(ent.mnt_major, ent.mnt_minor) == sfdev) {
			match = 1;
			break;
		}
	}

	/*
	 * No match is needed for a block device statefile,
	 * a match is needed for a regular statefile.
	 */
	if (match == 0) {
		if (new_cc.cf_type != CFT_UFS)
			STRCPYLIM(new_cc.cf_devfs, sfile, "block statefile");
		else
			err_fmt = "cannot find ufs mount point for \"%s\"\n";
	} else if (new_cc.cf_type == CFT_UFS) {
		STRCPYLIM(new_cc.cf_fs, ent.mnt_mountp, "mnt entry");
		STRCPYLIM(new_cc.cf_devfs, ent.mnt_special, "mnt special");
		while (*(sfile + 1) == '/') sfile++;
		src = sfile + strlen(ent.mnt_mountp);
		while (*src == '/') src++;
		STRCPYLIM(new_cc.cf_path, src, "statefile path");
	} else
		err_fmt = "statefile device \"%s\" is a mounted filesystem\n";
	(void) fclose(fp);
	if (err_fmt)
		mesg(MERR, err_fmt, sfile);
	return (err_fmt != NULL);
}
Exemplo n.º 12
0
/*
 * Given a full path to a file, translate into a dataset name and a relative
 * path within the dataset.  'dataset' must be at least MAXNAMELEN characters,
 * and 'relpath' must be at least MAXPATHLEN characters.  We also pass a stat
 * buffer, which we need later to get the object ID.
 */
static int
parse_pathname(const char *inpath, char *dataset, char *relpath,
    struct stat *statbuf)
{
	struct extmnttab mp;
	FILE *fp;
	int match;
	const char *rel;
	char fullpath[MAXPATHLEN];

	compress_slashes(inpath, fullpath);

	if (fullpath[0] != '/') {
		(void) fprintf(stderr, "invalid object '%s': must be full "
		    "path\n", fullpath);
		usage();
		return (-1);
	}

	if (strlen(fullpath) >= MAXPATHLEN) {
		(void) fprintf(stderr, "invalid object; pathname too long\n");
		return (-1);
	}

	if (stat(fullpath, statbuf) != 0) {
		(void) fprintf(stderr, "cannot open '%s': %s\n",
		    fullpath, strerror(errno));
		return (-1);
	}

#ifdef HAVE_SETMNTENT
	if ((fp = setmntent(MNTTAB, "r")) == NULL) {
#else
	if ((fp = fopen(MNTTAB, "r")) == NULL) {
#endif
		(void) fprintf(stderr, "cannot open /etc/mtab\n");
		return (-1);
	}

	match = 0;
	while (getextmntent(fp, &mp, sizeof (mp)) == 0) {
		if (makedev(mp.mnt_major, mp.mnt_minor) == statbuf->st_dev) {
			match = 1;
			break;
		}
	}

	if (!match) {
		(void) fprintf(stderr, "cannot find mountpoint for '%s'\n",
		    fullpath);
		return (-1);
	}

	if (strcmp(mp.mnt_fstype, MNTTYPE_ZFS) != 0) {
		(void) fprintf(stderr, "invalid path '%s': not a ZFS "
		    "filesystem\n", fullpath);
		return (-1);
	}

	if (strncmp(fullpath, mp.mnt_mountp, strlen(mp.mnt_mountp)) != 0) {
		(void) fprintf(stderr, "invalid path '%s': mountpoint "
		    "doesn't match path\n", fullpath);
		return (-1);
	}

	(void) strcpy(dataset, mp.mnt_special);

	rel = fullpath + strlen(mp.mnt_mountp);
	if (rel[0] == '/')
		rel++;
	(void) strcpy(relpath, rel);

	return (0);
}
#endif

//From FreeBSD
static int
parse_pathname(const char *inpath, char *dataset, char *relpath,
    struct stat *statbuf)
{
        struct statfs sfs;
        const char *rel;
        char fullpath[MAXPATHLEN];

        compress_slashes(inpath, fullpath);

        if (fullpath[0] != '/') {
                (void) fprintf(stderr, "invalid object '%s': must be full "
                    "path\n", fullpath);
                usage();
                return (-1);
        }

        if (strlen(fullpath) >= MAXPATHLEN) {
                (void) fprintf(stderr, "invalid object; pathname too long\n");
                return (-1);
        }

        if (stat(fullpath, statbuf) != 0) {
                (void) fprintf(stderr, "cannot open '%s': %s\n",
                    fullpath, strerror(errno));
                return (-1);
        }

        if (statfs(fullpath, &sfs) == -1) {
                (void) fprintf(stderr, "cannot find mountpoint for '%s': %s\n",
                    fullpath, strerror(errno));
                return (-1);
        }

        if (strcmp(sfs.f_fstypename, MNTTYPE_ZFS) != 0) {
                (void) fprintf(stderr, "invalid path '%s': not a ZFS "
                    "filesystem\n", fullpath);
                return (-1);
        }

        if (strncmp(fullpath, sfs.f_mntonname, strlen(sfs.f_mntonname)) != 0) {
                (void) fprintf(stderr, "invalid path '%s': mountpoint "
                    "doesn't match path\n", fullpath);
                return (-1);
        }

        (void) strcpy(dataset, sfs.f_mntfromname);

        rel = fullpath + strlen(sfs.f_mntonname);
        if (rel[0] == '/')
                rel++;
        (void) strcpy(relpath, rel);

        return (0);
}

/*
 * Convert from a (dataset, path) pair into a (objset, object) pair.  Note that
 * we grab the object number from the inode number, since looking this up via
 * libzpool is a real pain.
 */
/* ARGSUSED */
static int
object_from_path(const char *dataset, const char *path, struct stat *statbuf,
    zinject_record_t *record)
{
	objset_t *os;
	int err;

	/*
	 * Before doing any libzpool operations, call sync() to ensure that the
	 * on-disk state is consistent with the in-core state.
	 */
	sync();

	err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, B_FALSE, FTAG, &os);
	if (err != 0) {
		(void) fprintf(stderr, "cannot open dataset '%s': %s\n",
		    dataset, strerror(err));
		return (-1);
	}

	record->zi_objset = dmu_objset_id(os);
	record->zi_object = statbuf->st_ino;

	dmu_objset_disown(os, B_FALSE, FTAG);

	return (0);
}
Exemplo n.º 13
0
int
main(int argc, char **argv)
{
	char *myname;
	char *optionp;
	char *opigp;
	int mflag;
	int readonly;
	struct cachefs_mountargs margs;
	char *backfstypep;
	char *reducep;
	char *specp;
	int xx;
	int stat_loc;
	char *newargv[20];
	char *mntp;
	pid_t pid;
	int mounted;
	int c;
	int lockid;
	int Oflg;
	char *strp;
	char servname[33];
	int notify = 1;
	struct stat64 statb;
	struct mnttagdesc mtdesc;
	char mops[MAX_MNTOPT_STR];
	char cfs_nfsv4ops[MAX_MNTOPT_STR];
	uint32_t nfsvers = 0;
	uint32_t nfsvers_error = FALSE;
	int nfsv3pass = 0;
	(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN	"SYS_TEST"
#endif
	(void) textdomain(TEXT_DOMAIN);

	if (argv[0]) {
		myname = strrchr(argv[0], '/');
		if (myname)
			myname++;
		else
			myname = argv[0];
	} else {
		myname = "path unknown";
	}

	optionp = NULL;
	nomnttab = 0;
	quiet = 0;
	readonly = 0;
	Oflg = 0;
	cfs_nfsv4ops[0] = '\0';

	/* process command line options */
	while ((c = getopt(argc, argv, "mo:Orq")) != EOF) {
		switch (c) {
		case 'm':	/* no entry in /etc/mnttab */
			nomnttab = 1;
			break;

		case 'o':
			optionp = optarg;
			break;

		case 'O':
			Oflg++;
			break;

		case 'r':	/* read only mount */
			readonly = 1;
			break;

		case 'q':
			quiet = 1;
			break;

		default:
			usage("invalid option");
			return (1);
		}
	}

	/* if -o not specified */
	if (optionp == NULL) {
		usage(gettext("\"-o backfstype\" must be specified"));
		return (1);
	}

	/* verify special device and mount point are specified */
	if (argc - optind < 2) {
		usage(gettext("must specify special device and mount point"));
		return (1);
	}

	/* Store mount point and special device. */
	specp = argv[argc - 2];
	mntp = argv[argc - 1];

	/* Initialize default mount values */
	margs.cfs_options.opt_flags = CFS_ACCESS_BACKFS;
	margs.cfs_options.opt_popsize = DEF_POP_SIZE;
	margs.cfs_options.opt_fgsize = DEF_FILEGRP_SIZE;
	margs.cfs_fsid = NULL;
	memset(margs.cfs_cacheid, 0, sizeof (margs.cfs_cacheid));
	margs.cfs_cachedir = CFS_DEF_DIR;
	margs.cfs_backfs = NULL;
	margs.cfs_acregmin = 0;
	margs.cfs_acregmax = 0;
	margs.cfs_acdirmin = 0;
	margs.cfs_acdirmax = 0;
	mflag = MS_OPTIONSTR;
	if (nomnttab)
		mflag |= MS_NOMNTTAB;
	backfstypep = NULL;

	/* process -o options */
	xx = set_cfs_args(optionp, &margs, &mflag, &backfstypep, &reducep,
	    &notify, &nfsv3pass);
	if (xx) {
		return (1);
	}
	strcpy(mops, optionp);

	/* backfstype has to be specified */
	if (backfstypep == NULL) {
		usage(gettext("\"-o backfstype\" must be specified"));
		return (1);
	}

	if ((strcmp(backfstypep, "nfs") != 0) &&
				(strcmp(backfstypep, "hsfs") != 0)) {
		pr_err(gettext("%s as backfstype is not supported."),
					backfstypep);
		return (1);
	}

	/* set default write mode if not specified */
	if ((margs.cfs_options.opt_flags &
	    (CFS_WRITE_AROUND|CFS_NONSHARED)) == 0) {
		margs.cfs_options.opt_flags |= CFS_WRITE_AROUND;
		if (strcmp(backfstypep, "hsfs") == 0)
			mflag |= MS_RDONLY;
	}

	/* if read-only was specified with the -r option */
	if (readonly) {
		mflag |= MS_RDONLY;
	}

	/* if overlay was specified with -O option */
	if (Oflg) {
		mflag |= MS_OVERLAY;
	}

	/* get the fsid of the backfs and the cacheid */
	margs.cfs_fsid = get_back_fsid(specp);
	if (margs.cfs_fsid == NULL) {
		pr_err(gettext("out of memory"));
		return (1);
	}

	/*
	 * If using this cachedir to mount a file system for the first time
	 * after reboot, the ncheck for the sanity of the cachedir
	 */
	if (first_time_ab(margs.cfs_cachedir))
		if (check_cache(margs.cfs_cachedir))
			return (1);

	/* get the front file system cache id if necessary */
	if (margs.cfs_cacheid[0] == '\0') {
		char *cacheid = get_cacheid(margs.cfs_fsid, mntp);

		if (cacheid == NULL) {
			pr_err(gettext("default cacheid too long"));
			return (1);
		}

		strcpy(margs.cfs_cacheid, cacheid);
	}

	/* lock the cache directory shared */
	lockid = cachefs_dir_lock(margs.cfs_cachedir, 1);
	if (lockid == -1) {
		/* exit if could not get the lock */
		return (1);
	}

	/* if no mount point was specified and we are not remounting */
	mounted = 0;
	if ((margs.cfs_backfs == NULL) &&
	    (((mflag & MS_REMOUNT) == 0) ||
	    (margs.cfs_options.opt_flags & CFS_SLIDE))) {
		/* if a disconnectable mount */
		xx = 0;
		if (margs.cfs_options.opt_flags & CFS_DISCONNECTABLE) {
			/* see if the server is alive */
			xx = pingserver(specp);
		}

		/* attempt to mount the back file system */
		if (xx == 0) {
			xx = dobackmnt(&margs, reducep, specp, backfstypep,
			    myname, readonly);
			/*
			 * nfs mount exits with a value of 32 if a timeout
			 * error occurs trying the mount.
			 */
			if (xx && (xx != 32)) {
				cachefs_dir_unlock(lockid);
				rmdir(margs.cfs_backfs);
				return (1);
			}
			if (xx == 0)
				mounted = 1;
		}
	}

	/*
	 * At this point the back file system should be mounted.
	 * Get NFS version information for the back filesystem if
	 * it is NFS. The version information is required
	 * because NFS version 4 is incompatible with cachefs
	 * and we provide pass-through support for NFS version 4
	 * with cachefs, aka the cachefs mount is installed but
	 * there is no caching. This is indicated to the kernel
	 * during the mount by setting the CFS_BACKFS_NFSV4 flag.
	 */
	if (margs.cfs_backfs != NULL && strcmp(backfstypep, "nfs") == 0) {

		nfsvers = cachefs_get_back_nfsvers(margs.cfs_backfs, nomnttab);
		switch (nfsvers) {
		case 2:
			break;

		case 3:
			if (nfsv3pass) {
				/* Force pass through (for debugging) */
				margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4;
				if (cfs_nfsv4_build_opts(optionp,
						cfs_nfsv4ops) != 0) {
					nfsvers_error = TRUE;
					goto clean_backmnt;
				}
			}
			break;

		case 4:
			/*
			 * overwrite old option flags with NFSv4 flag.
			 * Note that will also operate in strict
			 * consistency mode. Clean up the option string
			 * to get rid of the cachefs-specific options
			 * to be in sync with the opt flags, otherwise
			 * these can make it into the mnttab and cause
			 * problems (esp. the disconnected option).
			 */
			margs.cfs_options.opt_flags = CFS_BACKFS_NFSV4;
			if (cfs_nfsv4_build_opts(optionp, cfs_nfsv4ops) != 0) {
				nfsvers_error = TRUE;
				goto clean_backmnt;
			}
			break;

		default:
			/* error, unknown version */
			nfsvers_error = TRUE;
			goto clean_backmnt;
		}
	}

	/*
	 * Grab server name from special file arg if it is there or set
	 * server name to "server unknown".
	 */
	margs.cfs_hostname = servname;
	strncpy(servname, specp, sizeof (servname));
	servname[sizeof (servname) - 1] = '\0';
	strp = strchr(servname, ':');
	if (strp == NULL) {
		margs.cfs_hostname = "server unknown";
		margs.cfs_backfsname = specp;
	} else {
		*strp = '\0';
		/*
		 * The rest of the special file arg is the name of
		 * the back filesystem.
		 */
		strp++;
		margs.cfs_backfsname = strp;
	}

	/* mount the cache file system */
	xx = mount((margs.cfs_backfs != NULL) ? margs.cfs_backfs : "nobackfs",
		mntp, mflag | MS_DATA, MNTTYPE_CFS,
		&margs, sizeof (margs),
		(cfs_nfsv4ops[0] == '\0' ? mops : cfs_nfsv4ops),
		MAX_MNTOPT_STR);
clean_backmnt:
	if (xx == -1 || nfsvers_error) {
		if (nfsvers_error) {
			pr_err(gettext("nfs version error."));
		} else if (errno == ESRCH) {
			pr_err(gettext("mount failed, options do not match."));
		} else if ((errno == EAGAIN) && (margs.cfs_backfs == NULL)) {
			pr_err(gettext("mount failed, server not responding."));
		} else {
			pr_err(gettext("mount failed %s"), strerror(errno));
		}

		/* try to unmount the back file system if we mounted it */
		if (mounted) {
			xx = 1;
			newargv[xx++] = "umount";
			newargv[xx++] = margs.cfs_backfs;
			newargv[xx++] = NULL;

			/* fork */
			if ((pid = fork()) == -1) {
				pr_err(gettext("could not fork: %s"),
				    strerror(errno));
				cachefs_dir_unlock(lockid);
				return (1);
			}

			/* if the child */
			if (pid == 0) {
				/* do the unmount */
				doexec(backfstypep, newargv, "umount");
			}

			/* else if the parent */
			else {
				wait(0);
			}
			rmdir(margs.cfs_backfs);
		}

		cachefs_dir_unlock(lockid);
		return (1);
	}

	/* release the lock on the cache directory */
	cachefs_dir_unlock(lockid);

	/* record the mount information in the fscache directory */
	record_mount(mntp, specp, margs.cfs_backfs, backfstypep,
		margs.cfs_cachedir, margs.cfs_cacheid,
		(cfs_nfsv4ops[0] == '\0' ? optionp : cfs_nfsv4ops), reducep);

	/* notify the daemon of the mount */
	if (notify)
		daemon_notify(margs.cfs_cachedir, margs.cfs_cacheid);

	/* update mnttab file if necessary */
	if (!nomnttab) {
		/*
		 * If we added the back file system, tag it with ignore,
		 * however, don't fail the mount after its done
		 * if the tag can't be added (eg., this would cause
		 * automounter problems).
		 */
		if (mounted) {
			FILE *mt;
			struct extmnttab mnt;

			if ((mt = fopen(MNTTAB, "r")) == NULL)
				return (1);
			while (getextmntent(mt, &mnt, sizeof (mnt)) != -1) {
				if (mnt.mnt_mountp != NULL &&
				    strcmp(margs.cfs_backfs,
					mnt.mnt_mountp) == 0) {
					/* found it, do tag ioctl */
					mtdesc.mtd_major = mnt.mnt_major;
					mtdesc.mtd_minor = mnt.mnt_minor;
					mtdesc.mtd_mntpt = margs.cfs_backfs;
					mtdesc.mtd_tag = MNTOPT_IGNORE;

					(void) ioctl(fileno(mt),
						MNTIOC_SETTAG, &mtdesc);
					break;
				}
			}
			fclose(mt);
		}
	}

	/* return success */
	return (0);
}