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); }
int zfs_for_each(int argc, char **argv, int flags, zfs_type_t types, zfs_sort_column_t *sortcol, zprop_list_t **proplist, int limit, zfs_iter_cb callback, void *data) { callback_data_t cb = {0}; int ret = 0; zfs_node_t *node; uu_avl_walk_t *walk; avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT); if (avl_pool == NULL) nomem(); cb.cb_sortcol = sortcol; cb.cb_flags = flags; cb.cb_proplist = proplist; cb.cb_types = types; cb.cb_depth_limit = limit; /* * If cb_proplist is provided then in the zfs_handles created we * retain only those properties listed in cb_proplist and sortcol. * The rest are pruned. So, the caller should make sure that no other * properties other than those listed in cb_proplist/sortcol are * accessed. * * If cb_proplist is NULL then we retain all the properties. We * always retain the zoned property, which some other properties * need (userquota & friends), and the createtxg property, which * we need to sort snapshots. */ if (cb.cb_proplist && *cb.cb_proplist) { zprop_list_t *p = *cb.cb_proplist; while (p) { if (p->pl_prop >= ZFS_PROP_TYPE && p->pl_prop < ZFS_NUM_PROPS) { cb.cb_props_table[p->pl_prop] = B_TRUE; } p = p->pl_next; } while (sortcol) { if (sortcol->sc_prop >= ZFS_PROP_TYPE && sortcol->sc_prop < ZFS_NUM_PROPS) { cb.cb_props_table[sortcol->sc_prop] = B_TRUE; } sortcol = sortcol->sc_next; } cb.cb_props_table[ZFS_PROP_ZONED] = B_TRUE; cb.cb_props_table[ZFS_PROP_CREATETXG] = B_TRUE; } else { (void) memset(cb.cb_props_table, B_TRUE, sizeof (cb.cb_props_table)); } if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) nomem(); if (argc == 0) { /* * If given no arguments, iterate over all datasets. */ cb.cb_flags |= ZFS_ITER_RECURSE; ret = zfs_iter_root(g_zfs, zfs_callback, &cb); } else { int i; zfs_handle_t *zhp; zfs_type_t argtype; /* * If we're recursive, then we always allow filesystems as * arguments. If we also are interested in snapshots, then we * can take volumes as well. */ argtype = types; if (flags & ZFS_ITER_RECURSE) { argtype |= ZFS_TYPE_FILESYSTEM; if (types & ZFS_TYPE_SNAPSHOT) argtype |= ZFS_TYPE_VOLUME; } for (i = 0; i < argc; i++) { if (flags & ZFS_ITER_ARGS_CAN_BE_PATHS) { zhp = zfs_path_to_zhandle(g_zfs, argv[i], argtype); } else { zhp = zfs_open(g_zfs, argv[i], argtype); } if (zhp != NULL) ret |= zfs_callback(zhp, &cb); else ret = 1; } } /* * At this point we've got our AVL tree full of zfs handles, so iterate * over each one and execute the real user callback. */ for (node = uu_avl_first(cb.cb_avl); node != NULL; node = uu_avl_next(cb.cb_avl, node)) ret |= callback(node->zn_handle, node->zn_depth, data); /* * Finally, clean up the AVL tree. */ if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) nomem(); while ((node = uu_avl_walk_next(walk)) != NULL) { uu_avl_remove(cb.cb_avl, node); zfs_close(node->zn_handle); free(node); } uu_avl_walk_end(walk); uu_avl_destroy(cb.cb_avl); uu_avl_pool_destroy(avl_pool); return (ret); }
int zfs_for_each(int argc, char **argv, boolean_t recurse, zfs_type_t types, zfs_sort_column_t *sortcol, zprop_list_t **proplist, zfs_iter_f callback, void *data, boolean_t args_can_be_paths) { callback_data_t cb; int ret = 0; zfs_node_t *node; uu_avl_walk_t *walk; avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT); if (avl_pool == NULL) { (void) fprintf(stderr, gettext("internal error: out of memory\n")); exit(1); } cb.cb_sortcol = sortcol; cb.cb_recurse = recurse; cb.cb_proplist = proplist; cb.cb_types = types; if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) { (void) fprintf(stderr, gettext("internal error: out of memory\n")); exit(1); } if (argc == 0) { /* * If given no arguments, iterate over all datasets. */ cb.cb_recurse = 1; ret = zfs_iter_root(g_zfs, zfs_callback, &cb); } else { int i; zfs_handle_t *zhp; zfs_type_t argtype; /* * If we're recursive, then we always allow filesystems as * arguments. If we also are interested in snapshots, then we * can take volumes as well. */ argtype = types; if (recurse) { argtype |= ZFS_TYPE_FILESYSTEM; if (types & ZFS_TYPE_SNAPSHOT) argtype |= ZFS_TYPE_VOLUME; } for (i = 0; i < argc; i++) { if (args_can_be_paths) { zhp = zfs_path_to_zhandle(g_zfs, argv[i], argtype); } else { zhp = zfs_open(g_zfs, argv[i], argtype); } if (zhp != NULL) ret |= zfs_callback(zhp, &cb); else ret = 1; } } /* * At this point we've got our AVL tree full of zfs handles, so iterate * over each one and execute the real user callback. */ for (node = uu_avl_first(cb.cb_avl); node != NULL; node = uu_avl_next(cb.cb_avl, node)) ret |= callback(node->zn_handle, data); /* * Finally, clean up the AVL tree. */ if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) { (void) fprintf(stderr, gettext("internal error: out of memory")); exit(1); } while ((node = uu_avl_walk_next(walk)) != NULL) { uu_avl_remove(cb.cb_avl, node); zfs_close(node->zn_handle); free(node); } uu_avl_walk_end(walk); uu_avl_destroy(cb.cb_avl); uu_avl_pool_destroy(avl_pool); return (ret); }