/* * 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); }
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); }
/* 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 (""); }
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; } } } } }
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, <ime); 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); }
/* * 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"); } }
/* * 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); }
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, <ime); 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); }
/* * 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); }
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); }
/* * 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); }
/* * 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); }
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, ¬ify, &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); }