Deleted Added
full compact
zfs_main.c (238422) zfs_main.c (240415)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 290 unchanged lines hidden (view full) ---

299 "\t [<perm|@setname>[,...]] <filesystem|volume>\n"
300 "\tunallow [-rld] -e [<perm|@setname>[,...]] "
301 "<filesystem|volume>\n"
302 "\tunallow [-r] -c [<perm|@setname>[,...]] "
303 "<filesystem|volume>\n"
304 "\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
305 "<filesystem|volume>\n"));
306 case HELP_USERSPACE:
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 290 unchanged lines hidden (view full) ---

299 "\t [<perm|@setname>[,...]] <filesystem|volume>\n"
300 "\tunallow [-rld] -e [<perm|@setname>[,...]] "
301 "<filesystem|volume>\n"
302 "\tunallow [-r] -c [<perm|@setname>[,...]] "
303 "<filesystem|volume>\n"
304 "\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
305 "<filesystem|volume>\n"));
306 case HELP_USERSPACE:
307 return (gettext("\tuserspace [-niHp] [-o field[,...]] "
308 "[-sS field] ... [-t type[,...]]\n"
309 "\t <filesystem|snapshot>\n"));
307 return (gettext("\tuserspace [-Hinp] [-o field[,...]] "
308 "[-s field] ...\n\t[-S field] ... "
309 "[-t type[,...]] <filesystem|snapshot>\n"));
310 case HELP_GROUPSPACE:
310 case HELP_GROUPSPACE:
311 return (gettext("\tgroupspace [-niHp] [-o field[,...]] "
312 "[-sS field] ... [-t type[,...]]\n"
313 "\t <filesystem|snapshot>\n"));
311 return (gettext("\tgroupspace [-Hinp] [-o field[,...]] "
312 "[-s field] ...\n\t[-S field] ... "
313 "[-t type[,...]] <filesystem|snapshot>\n"));
314 case HELP_HOLD:
315 return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
316 case HELP_HOLDS:
317 return (gettext("\tholds [-r] <snapshot> ...\n"));
318 case HELP_RELEASE:
319 return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
320 case HELP_DIFF:
321 return (gettext("\tdiff [-FHt] <snapshot> "

--- 1741 unchanged lines hidden (view full) ---

2063 (void) printf(gettext("All filesystems are "
2064 "formatted with the current version.\n"));
2065 }
2066 }
2067
2068 return (ret);
2069}
2070
314 case HELP_HOLD:
315 return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
316 case HELP_HOLDS:
317 return (gettext("\tholds [-r] <snapshot> ...\n"));
318 case HELP_RELEASE:
319 return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
320 case HELP_DIFF:
321 return (gettext("\tdiff [-FHt] <snapshot> "

--- 1741 unchanged lines hidden (view full) ---

2063 (void) printf(gettext("All filesystems are "
2064 "formatted with the current version.\n"));
2065 }
2066 }
2067
2068 return (ret);
2069}
2070
2071#define USTYPE_USR_BIT (0)
2072#define USTYPE_GRP_BIT (1)
2073#define USTYPE_PSX_BIT (2)
2074#define USTYPE_SMB_BIT (3)
2071/*
2072 * zfs userspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
2073 * [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
2074 * zfs groupspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
2075 * [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
2076 *
2077 * -H Scripted mode; elide headers and separate columns by tabs.
2078 * -i Translate SID to POSIX ID.
2079 * -n Print numeric ID instead of user/group name.
2080 * -o Control which fields to display.
2081 * -p Use exact (parseable) numeric output.
2082 * -s Specify sort columns, descending order.
2083 * -S Specify sort columns, ascending order.
2084 * -t Control which object types to display.
2085 *
2086 * Displays space consumed by, and quotas on, each user in the specified
2087 * filesystem or snapshot.
2088 */
2075
2089
2076#define USTYPE_USR (1 << USTYPE_USR_BIT)
2077#define USTYPE_GRP (1 << USTYPE_GRP_BIT)
2090/* us_field_types, us_field_hdr and us_field_names should be kept in sync */
2091enum us_field_types {
2092 USFIELD_TYPE,
2093 USFIELD_NAME,
2094 USFIELD_USED,
2095 USFIELD_QUOTA
2096};
2097static char *us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA" };
2098static char *us_field_names[] = { "type", "name", "used", "quota" };
2099#define USFIELD_LAST (sizeof (us_field_names) / sizeof (char *))
2078
2100
2079#define USTYPE_PSX (1 << USTYPE_PSX_BIT)
2080#define USTYPE_SMB (1 << USTYPE_SMB_BIT)
2101#define USTYPE_PSX_GRP (1 << 0)
2102#define USTYPE_PSX_USR (1 << 1)
2103#define USTYPE_SMB_GRP (1 << 2)
2104#define USTYPE_SMB_USR (1 << 3)
2105#define USTYPE_ALL \
2106 (USTYPE_PSX_GRP | USTYPE_PSX_USR | USTYPE_SMB_GRP | USTYPE_SMB_USR)
2081
2107
2082#define USTYPE_PSX_USR (USTYPE_PSX | USTYPE_USR)
2083#define USTYPE_SMB_USR (USTYPE_SMB | USTYPE_USR)
2084#define USTYPE_PSX_GRP (USTYPE_PSX | USTYPE_GRP)
2085#define USTYPE_SMB_GRP (USTYPE_SMB | USTYPE_GRP)
2086#define USTYPE_ALL (USTYPE_PSX_USR | USTYPE_SMB_USR \
2087 | USTYPE_PSX_GRP | USTYPE_SMB_GRP)
2108static int us_type_bits[] = {
2109 USTYPE_PSX_GRP,
2110 USTYPE_PSX_USR,
2111 USTYPE_SMB_GRP,
2112 USTYPE_SMB_USR,
2113 USTYPE_ALL
2114};
2115static char *us_type_names[] = { "posixgroup", "posxiuser", "smbgroup",
2116 "smbuser", "all" };
2088
2117
2089
2090#define USPROP_USED_BIT (0)
2091#define USPROP_QUOTA_BIT (1)
2092
2093#define USPROP_USED (1 << USPROP_USED_BIT)
2094#define USPROP_QUOTA (1 << USPROP_QUOTA_BIT)
2095
2096typedef struct us_node {
2097 nvlist_t *usn_nvl;
2098 uu_avl_node_t usn_avlnode;
2099 uu_list_node_t usn_listnode;
2100} us_node_t;
2101
2102typedef struct us_cbdata {
2118typedef struct us_node {
2119 nvlist_t *usn_nvl;
2120 uu_avl_node_t usn_avlnode;
2121 uu_list_node_t usn_listnode;
2122} us_node_t;
2123
2124typedef struct us_cbdata {
2103 nvlist_t **cb_nvlp;
2104 uu_avl_pool_t *cb_avl_pool;
2105 uu_avl_t *cb_avl;
2106 boolean_t cb_numname;
2107 boolean_t cb_nicenum;
2108 boolean_t cb_sid2posix;
2109 zfs_userquota_prop_t cb_prop;
2110 zfs_sort_column_t *cb_sortcol;
2111 size_t cb_max_typelen;
2112 size_t cb_max_namelen;
2113 size_t cb_max_usedlen;
2114 size_t cb_max_quotalen;
2125 nvlist_t **cb_nvlp;
2126 uu_avl_pool_t *cb_avl_pool;
2127 uu_avl_t *cb_avl;
2128 boolean_t cb_numname;
2129 boolean_t cb_nicenum;
2130 boolean_t cb_sid2posix;
2131 zfs_userquota_prop_t cb_prop;
2132 zfs_sort_column_t *cb_sortcol;
2133 size_t cb_width[USFIELD_LAST];
2115} us_cbdata_t;
2116
2134} us_cbdata_t;
2135
2136static boolean_t us_populated = B_FALSE;
2137
2117typedef struct {
2118 zfs_sort_column_t *si_sortcol;
2138typedef struct {
2139 zfs_sort_column_t *si_sortcol;
2119 boolean_t si_num_name;
2120 boolean_t si_parsable;
2140 boolean_t si_numname;
2121} us_sort_info_t;
2122
2123static int
2141} us_sort_info_t;
2142
2143static int
2144us_field_index(char *field)
2145{
2146 int i;
2147
2148 for (i = 0; i < USFIELD_LAST; i++) {
2149 if (strcmp(field, us_field_names[i]) == 0)
2150 return (i);
2151 }
2152
2153 return (-1);
2154}
2155
2156static int
2124us_compare(const void *larg, const void *rarg, void *unused)
2125{
2126 const us_node_t *l = larg;
2127 const us_node_t *r = rarg;
2157us_compare(const void *larg, const void *rarg, void *unused)
2158{
2159 const us_node_t *l = larg;
2160 const us_node_t *r = rarg;
2128 int rc = 0;
2129 us_sort_info_t *si = (us_sort_info_t *)unused;
2130 zfs_sort_column_t *sortcol = si->si_sortcol;
2161 us_sort_info_t *si = (us_sort_info_t *)unused;
2162 zfs_sort_column_t *sortcol = si->si_sortcol;
2131 boolean_t num_name = si->si_num_name;
2163 boolean_t numname = si->si_numname;
2132 nvlist_t *lnvl = l->usn_nvl;
2133 nvlist_t *rnvl = r->usn_nvl;
2164 nvlist_t *lnvl = l->usn_nvl;
2165 nvlist_t *rnvl = r->usn_nvl;
2166 int rc = 0;
2167 boolean_t lvb, rvb;
2134
2135 for (; sortcol != NULL; sortcol = sortcol->sc_next) {
2136 char *lvstr = "";
2137 char *rvstr = "";
2138 uint32_t lv32 = 0;
2139 uint32_t rv32 = 0;
2140 uint64_t lv64 = 0;
2141 uint64_t rv64 = 0;
2142 zfs_prop_t prop = sortcol->sc_prop;
2143 const char *propname = NULL;
2144 boolean_t reverse = sortcol->sc_reverse;
2145
2146 switch (prop) {
2147 case ZFS_PROP_TYPE:
2148 propname = "type";
2149 (void) nvlist_lookup_uint32(lnvl, propname, &lv32);
2150 (void) nvlist_lookup_uint32(rnvl, propname, &rv32);
2151 if (rv32 != lv32)
2168
2169 for (; sortcol != NULL; sortcol = sortcol->sc_next) {
2170 char *lvstr = "";
2171 char *rvstr = "";
2172 uint32_t lv32 = 0;
2173 uint32_t rv32 = 0;
2174 uint64_t lv64 = 0;
2175 uint64_t rv64 = 0;
2176 zfs_prop_t prop = sortcol->sc_prop;
2177 const char *propname = NULL;
2178 boolean_t reverse = sortcol->sc_reverse;
2179
2180 switch (prop) {
2181 case ZFS_PROP_TYPE:
2182 propname = "type";
2183 (void) nvlist_lookup_uint32(lnvl, propname, &lv32);
2184 (void) nvlist_lookup_uint32(rnvl, propname, &rv32);
2185 if (rv32 != lv32)
2152 rc = (rv32 > lv32) ? 1 : -1;
2186 rc = (rv32 < lv32) ? 1 : -1;
2153 break;
2154 case ZFS_PROP_NAME:
2155 propname = "name";
2187 break;
2188 case ZFS_PROP_NAME:
2189 propname = "name";
2156 if (num_name) {
2157 (void) nvlist_lookup_uint32(lnvl, propname,
2158 &lv32);
2159 (void) nvlist_lookup_uint32(rnvl, propname,
2160 &rv32);
2161 if (rv32 != lv32)
2162 rc = (rv32 > lv32) ? 1 : -1;
2190 if (numname) {
2191 (void) nvlist_lookup_uint64(lnvl, propname,
2192 &lv64);
2193 (void) nvlist_lookup_uint64(rnvl, propname,
2194 &rv64);
2195 if (rv64 != lv64)
2196 rc = (rv64 < lv64) ? 1 : -1;
2163 } else {
2164 (void) nvlist_lookup_string(lnvl, propname,
2165 &lvstr);
2166 (void) nvlist_lookup_string(rnvl, propname,
2167 &rvstr);
2168 rc = strcmp(lvstr, rvstr);
2169 }
2170 break;
2197 } else {
2198 (void) nvlist_lookup_string(lnvl, propname,
2199 &lvstr);
2200 (void) nvlist_lookup_string(rnvl, propname,
2201 &rvstr);
2202 rc = strcmp(lvstr, rvstr);
2203 }
2204 break;
2171
2172 case ZFS_PROP_USED:
2173 case ZFS_PROP_QUOTA:
2205 case ZFS_PROP_USED:
2206 case ZFS_PROP_QUOTA:
2174 if (ZFS_PROP_USED == prop)
2207 if (!us_populated)
2208 break;
2209 if (prop == ZFS_PROP_USED)
2175 propname = "used";
2176 else
2177 propname = "quota";
2178 (void) nvlist_lookup_uint64(lnvl, propname, &lv64);
2179 (void) nvlist_lookup_uint64(rnvl, propname, &rv64);
2180 if (rv64 != lv64)
2210 propname = "used";
2211 else
2212 propname = "quota";
2213 (void) nvlist_lookup_uint64(lnvl, propname, &lv64);
2214 (void) nvlist_lookup_uint64(rnvl, propname, &rv64);
2215 if (rv64 != lv64)
2181 rc = (rv64 > lv64) ? 1 : -1;
2216 rc = (rv64 < lv64) ? 1 : -1;
2217 break;
2182 }
2183
2218 }
2219
2184 if (rc)
2220 if (rc != 0) {
2185 if (rc < 0)
2186 return (reverse ? 1 : -1);
2187 else
2188 return (reverse ? -1 : 1);
2221 if (rc < 0)
2222 return (reverse ? 1 : -1);
2223 else
2224 return (reverse ? -1 : 1);
2225 }
2189 }
2190
2226 }
2227
2191 return (rc);
2228 /*
2229 * If entries still seem to be the same, check if they are of the same
2230 * type (smbentity is added only if we are doing SID to POSIX ID
2231 * translation where we can have duplicate type/name combinations).
2232 */
2233 if (nvlist_lookup_boolean_value(lnvl, "smbentity", &lvb) == 0 &&
2234 nvlist_lookup_boolean_value(rnvl, "smbentity", &rvb) == 0 &&
2235 lvb != rvb)
2236 return (lvb < rvb ? -1 : 1);
2237
2238 return (0);
2192}
2193
2194static inline const char *
2195us_type2str(unsigned field_type)
2196{
2197 switch (field_type) {
2198 case USTYPE_PSX_USR:
2199 return ("POSIX User");
2200 case USTYPE_PSX_GRP:
2201 return ("POSIX Group");
2202 case USTYPE_SMB_USR:
2203 return ("SMB User");
2204 case USTYPE_SMB_GRP:
2205 return ("SMB Group");
2206 default:
2207 return ("Undefined");
2208 }
2209}
2210
2239}
2240
2241static inline const char *
2242us_type2str(unsigned field_type)
2243{
2244 switch (field_type) {
2245 case USTYPE_PSX_USR:
2246 return ("POSIX User");
2247 case USTYPE_PSX_GRP:
2248 return ("POSIX Group");
2249 case USTYPE_SMB_USR:
2250 return ("SMB User");
2251 case USTYPE_SMB_GRP:
2252 return ("SMB Group");
2253 default:
2254 return ("Undefined");
2255 }
2256}
2257
2211/*
2212 * zfs userspace
2213 */
2214static int
2215userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
2216{
2217 us_cbdata_t *cb = (us_cbdata_t *)arg;
2218 zfs_userquota_prop_t prop = cb->cb_prop;
2219 char *name = NULL;
2220 char *propname;
2258static int
2259userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
2260{
2261 us_cbdata_t *cb = (us_cbdata_t *)arg;
2262 zfs_userquota_prop_t prop = cb->cb_prop;
2263 char *name = NULL;
2264 char *propname;
2221 char namebuf[32];
2222 char sizebuf[32];
2223 us_node_t *node;
2224 uu_avl_pool_t *avl_pool = cb->cb_avl_pool;
2225 uu_avl_t *avl = cb->cb_avl;
2226 uu_avl_index_t idx;
2227 nvlist_t *props;
2228 us_node_t *n;
2229 zfs_sort_column_t *sortcol = cb->cb_sortcol;
2230 unsigned type;
2231 const char *typestr;
2232 size_t namelen;
2233 size_t typelen;
2234 size_t sizelen;
2265 char sizebuf[32];
2266 us_node_t *node;
2267 uu_avl_pool_t *avl_pool = cb->cb_avl_pool;
2268 uu_avl_t *avl = cb->cb_avl;
2269 uu_avl_index_t idx;
2270 nvlist_t *props;
2271 us_node_t *n;
2272 zfs_sort_column_t *sortcol = cb->cb_sortcol;
2273 unsigned type;
2274 const char *typestr;
2275 size_t namelen;
2276 size_t typelen;
2277 size_t sizelen;
2278 int typeidx, nameidx, sizeidx;
2235 us_sort_info_t sortinfo = { sortcol, cb->cb_numname };
2279 us_sort_info_t sortinfo = { sortcol, cb->cb_numname };
2280 boolean_t smbentity = B_FALSE;
2236
2281
2237 if (domain == NULL || domain[0] == '\0') {
2238 /* POSIX */
2239 if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
2240 type = USTYPE_PSX_GRP;
2241 struct group *g = getgrgid(rid);
2242 if (g)
2243 name = g->gr_name;
2244 } else {
2245 type = USTYPE_PSX_USR;
2246 struct passwd *p = getpwuid(rid);
2247 if (p)
2248 name = p->pw_name;
2249 }
2250 } else {
2251 char sid[ZFS_MAXNAMELEN+32];
2282 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
2283 nomem();
2284 node = safe_malloc(sizeof (us_node_t));
2285 uu_avl_node_init(node, &node->usn_avlnode, avl_pool);
2286 node->usn_nvl = props;
2287
2288 if (domain != NULL && domain[0] != '\0') {
2289 /* SMB */
2290 char sid[ZFS_MAXNAMELEN + 32];
2252 uid_t id;
2253 uint64_t classes;
2254#ifdef sun
2291 uid_t id;
2292 uint64_t classes;
2293#ifdef sun
2255 int err = 0;
2294 int err;
2256 directory_error_t e;
2257#endif
2258
2295 directory_error_t e;
2296#endif
2297
2298 smbentity = B_TRUE;
2299
2259 (void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid);
2300 (void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid);
2260 /* SMB */
2301
2261 if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
2262 type = USTYPE_SMB_GRP;
2263#ifdef sun
2264 err = sid_to_id(sid, B_FALSE, &id);
2265#endif
2266 } else {
2267 type = USTYPE_SMB_USR;
2268#ifdef sun
2269 err = sid_to_id(sid, B_TRUE, &id);
2270#endif
2271 }
2272
2273#ifdef sun
2274 if (err == 0) {
2275 rid = id;
2302 if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
2303 type = USTYPE_SMB_GRP;
2304#ifdef sun
2305 err = sid_to_id(sid, B_FALSE, &id);
2306#endif
2307 } else {
2308 type = USTYPE_SMB_USR;
2309#ifdef sun
2310 err = sid_to_id(sid, B_TRUE, &id);
2311#endif
2312 }
2313
2314#ifdef sun
2315 if (err == 0) {
2316 rid = id;
2276
2277 e = directory_name_from_sid(NULL, sid, &name, &classes);
2278 if (e != NULL) {
2279 directory_error_free(e);
2280 return (NULL);
2317 if (!cb->cb_sid2posix) {
2318 e = directory_name_from_sid(NULL, sid, &name,
2319 &classes);
2320 if (e != NULL)
2321 directory_error_free(e);
2322 if (name == NULL)
2323 name = sid;
2281 }
2324 }
2282
2283 if (name == NULL)
2284 name = sid;
2285 }
2286#endif
2287 }
2288
2325 }
2326#endif
2327 }
2328
2289/*
2290 * if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA)
2291 * ug = "group";
2292 * else
2293 * ug = "user";
2294 */
2329 if (cb->cb_sid2posix || domain == NULL || domain[0] == '\0') {
2330 /* POSIX or -i */
2331 if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
2332 type = USTYPE_PSX_GRP;
2333 if (!cb->cb_numname) {
2334 struct group *g;
2295
2335
2296 if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED)
2297 propname = "used";
2298 else
2299 propname = "quota";
2336 if ((g = getgrgid(rid)) != NULL)
2337 name = g->gr_name;
2338 }
2339 } else {
2340 type = USTYPE_PSX_USR;
2341 if (!cb->cb_numname) {
2342 struct passwd *p;
2300
2343
2301 (void) snprintf(namebuf, sizeof (namebuf), "%u", rid);
2302 if (name == NULL)
2303 name = namebuf;
2304
2305 if (cb->cb_nicenum)
2306 zfs_nicenum(space, sizebuf, sizeof (sizebuf));
2307 else
2308 (void) sprintf(sizebuf, "%llu", space);
2309
2310 node = safe_malloc(sizeof (us_node_t));
2311 uu_avl_node_init(node, &node->usn_avlnode, avl_pool);
2312
2313 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2314 free(node);
2315 return (-1);
2344 if ((p = getpwuid(rid)) != NULL)
2345 name = p->pw_name;
2346 }
2347 }
2316 }
2317
2348 }
2349
2350 /*
2351 * Make sure that the type/name combination is unique when doing
2352 * SID to POSIX ID translation (hence changing the type from SMB to
2353 * POSIX).
2354 */
2355 if (cb->cb_sid2posix &&
2356 nvlist_add_boolean_value(props, "smbentity", smbentity) != 0)
2357 nomem();
2358
2359 /* Calculate/update width of TYPE field */
2360 typestr = us_type2str(type);
2361 typelen = strlen(gettext(typestr));
2362 typeidx = us_field_index("type");
2363 if (typelen > cb->cb_width[typeidx])
2364 cb->cb_width[typeidx] = typelen;
2318 if (nvlist_add_uint32(props, "type", type) != 0)
2319 nomem();
2320
2365 if (nvlist_add_uint32(props, "type", type) != 0)
2366 nomem();
2367
2321 if (cb->cb_numname) {
2322 if (nvlist_add_uint32(props, "name", rid) != 0)
2368 /* Calculate/update width of NAME field */
2369 if ((cb->cb_numname && cb->cb_sid2posix) || name == NULL) {
2370 if (nvlist_add_uint64(props, "name", rid) != 0)
2323 nomem();
2371 nomem();
2324 namelen = strlen(namebuf);
2372 namelen = snprintf(NULL, 0, "%u", rid);
2325 } else {
2326 if (nvlist_add_string(props, "name", name) != 0)
2327 nomem();
2328 namelen = strlen(name);
2329 }
2373 } else {
2374 if (nvlist_add_string(props, "name", name) != 0)
2375 nomem();
2376 namelen = strlen(name);
2377 }
2378 nameidx = us_field_index("name");
2379 if (namelen > cb->cb_width[nameidx])
2380 cb->cb_width[nameidx] = namelen;
2330
2381
2331 typestr = us_type2str(type);
2332 typelen = strlen(gettext(typestr));
2333 if (typelen > cb->cb_max_typelen)
2334 cb->cb_max_typelen = typelen;
2335
2336 if (namelen > cb->cb_max_namelen)
2337 cb->cb_max_namelen = namelen;
2338
2339 sizelen = strlen(sizebuf);
2340 if (0 == strcmp(propname, "used")) {
2341 if (sizelen > cb->cb_max_usedlen)
2342 cb->cb_max_usedlen = sizelen;
2343 } else {
2344 if (sizelen > cb->cb_max_quotalen)
2345 cb->cb_max_quotalen = sizelen;
2346 }
2347
2348 node->usn_nvl = props;
2349
2350 n = uu_avl_find(avl, node, &sortinfo, &idx);
2351 if (n == NULL)
2382 /*
2383 * Check if this type/name combination is in the list and update it;
2384 * otherwise add new node to the list.
2385 */
2386 if ((n = uu_avl_find(avl, node, &sortinfo, &idx)) == NULL) {
2352 uu_avl_insert(avl, node, idx);
2387 uu_avl_insert(avl, node, idx);
2353 else {
2388 } else {
2354 nvlist_free(props);
2355 free(node);
2356 node = n;
2357 props = node->usn_nvl;
2358 }
2359
2389 nvlist_free(props);
2390 free(node);
2391 node = n;
2392 props = node->usn_nvl;
2393 }
2394
2395 /* Calculate/update width of USED/QUOTA fields */
2396 if (cb->cb_nicenum)
2397 zfs_nicenum(space, sizebuf, sizeof (sizebuf));
2398 else
2399 (void) snprintf(sizebuf, sizeof (sizebuf), "%llu", space);
2400 sizelen = strlen(sizebuf);
2401 if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED) {
2402 propname = "used";
2403 if (!nvlist_exists(props, "quota"))
2404 (void) nvlist_add_uint64(props, "quota", 0);
2405 } else {
2406 propname = "quota";
2407 if (!nvlist_exists(props, "used"))
2408 (void) nvlist_add_uint64(props, "used", 0);
2409 }
2410 sizeidx = us_field_index(propname);
2411 if (sizelen > cb->cb_width[sizeidx])
2412 cb->cb_width[sizeidx] = sizelen;
2413
2360 if (nvlist_add_uint64(props, propname, space) != 0)
2361 nomem();
2362
2363 return (0);
2364}
2365
2414 if (nvlist_add_uint64(props, propname, space) != 0)
2415 nomem();
2416
2417 return (0);
2418}
2419
2366static inline boolean_t
2367usprop_check(zfs_userquota_prop_t p, unsigned types, unsigned props)
2368{
2369 unsigned type;
2370 unsigned prop;
2371
2372 switch (p) {
2373 case ZFS_PROP_USERUSED:
2374 type = USTYPE_USR;
2375 prop = USPROP_USED;
2376 break;
2377 case ZFS_PROP_USERQUOTA:
2378 type = USTYPE_USR;
2379 prop = USPROP_QUOTA;
2380 break;
2381 case ZFS_PROP_GROUPUSED:
2382 type = USTYPE_GRP;
2383 prop = USPROP_USED;
2384 break;
2385 case ZFS_PROP_GROUPQUOTA:
2386 type = USTYPE_GRP;
2387 prop = USPROP_QUOTA;
2388 break;
2389 default: /* ALL */
2390 return (B_TRUE);
2391 };
2392
2393 return (type & types && prop & props);
2394}
2395
2396#define USFIELD_TYPE (1 << 0)
2397#define USFIELD_NAME (1 << 1)
2398#define USFIELD_USED (1 << 2)
2399#define USFIELD_QUOTA (1 << 3)
2400#define USFIELD_ALL (USFIELD_TYPE | USFIELD_NAME | USFIELD_USED | USFIELD_QUOTA)
2401
2402static int
2403parsefields(unsigned *fieldsp, char **names, unsigned *bits, size_t len)
2404{
2405 char *field = optarg;
2406 char *delim;
2407
2408 do {
2409 int i;
2410 boolean_t found = B_FALSE;
2411 delim = strchr(field, ',');
2412 if (delim != NULL)
2413 *delim = '\0';
2414
2415 for (i = 0; i < len; i++)
2416 if (0 == strcmp(field, names[i])) {
2417 found = B_TRUE;
2418 *fieldsp |= bits[i];
2419 break;
2420 }
2421
2422 if (!found) {
2423 (void) fprintf(stderr, gettext("invalid type '%s'"
2424 "for -t option\n"), field);
2425 return (-1);
2426 }
2427
2428 field = delim + 1;
2429 } while (delim);
2430
2431 return (0);
2432}
2433
2434
2435static char *type_names[] = { "posixuser", "smbuser", "posixgroup", "smbgroup",
2436 "all" };
2437static unsigned type_bits[] = {
2438 USTYPE_PSX_USR,
2439 USTYPE_SMB_USR,
2440 USTYPE_PSX_GRP,
2441 USTYPE_SMB_GRP,
2442 USTYPE_ALL
2443};
2444
2445static char *us_field_names[] = { "type", "name", "used", "quota" };
2446static unsigned us_field_bits[] = {
2447 USFIELD_TYPE,
2448 USFIELD_NAME,
2449 USFIELD_USED,
2450 USFIELD_QUOTA
2451};
2452
2453static void
2420static void
2454print_us_node(boolean_t scripted, boolean_t parseable, unsigned fields,
2455 size_t type_width, size_t name_width, size_t used_width,
2456 size_t quota_width, us_node_t *node)
2421print_us_node(boolean_t scripted, boolean_t parsable, int *fields, int types,
2422 size_t *width, us_node_t *node)
2457{
2458 nvlist_t *nvl = node->usn_nvl;
2423{
2424 nvlist_t *nvl = node->usn_nvl;
2459 nvpair_t *nvp = NULL;
2460 char valstr[ZFS_MAXNAMELEN];
2461 boolean_t first = B_TRUE;
2425 char valstr[ZFS_MAXNAMELEN];
2426 boolean_t first = B_TRUE;
2462 boolean_t quota_found = B_FALSE;
2427 int cfield = 0;
2428 int field;
2429 uint32_t ustype;
2463
2430
2464 if (fields & USFIELD_QUOTA && !nvlist_exists(nvl, "quota"))
2465 if (nvlist_add_string(nvl, "quota", "none") != 0)
2466 nomem();
2431 /* Check type */
2432 (void) nvlist_lookup_uint32(nvl, "type", &ustype);
2433 if (!(ustype & types))
2434 return;
2467
2435
2468 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
2469 char *pname = nvpair_name(nvp);
2470 data_type_t type = nvpair_type(nvp);
2471 uint32_t val32 = 0;
2472 uint64_t val64 = 0;
2436 while ((field = fields[cfield]) != USFIELD_LAST) {
2437 nvpair_t *nvp = NULL;
2438 data_type_t type;
2439 uint32_t val32;
2440 uint64_t val64;
2473 char *strval = NULL;
2441 char *strval = NULL;
2474 unsigned field = 0;
2475 unsigned width = 0;
2476 int i;
2477 for (i = 0; i < 4; i++) {
2478 if (0 == strcmp(pname, us_field_names[i])) {
2479 field = us_field_bits[i];
2442
2443 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
2444 if (strcmp(nvpair_name(nvp),
2445 us_field_names[field]) == 0)
2480 break;
2446 break;
2481 }
2482 }
2483
2447 }
2448
2484 if (!(field & fields))
2485 continue;
2486
2449 type = nvpair_type(nvp);
2487 switch (type) {
2488 case DATA_TYPE_UINT32:
2489 (void) nvpair_value_uint32(nvp, &val32);
2490 break;
2491 case DATA_TYPE_UINT64:
2492 (void) nvpair_value_uint64(nvp, &val64);
2493 break;
2494 case DATA_TYPE_STRING:
2495 (void) nvpair_value_string(nvp, &strval);
2496 break;
2497 default:
2450 switch (type) {
2451 case DATA_TYPE_UINT32:
2452 (void) nvpair_value_uint32(nvp, &val32);
2453 break;
2454 case DATA_TYPE_UINT64:
2455 (void) nvpair_value_uint64(nvp, &val64);
2456 break;
2457 case DATA_TYPE_STRING:
2458 (void) nvpair_value_string(nvp, &strval);
2459 break;
2460 default:
2498 (void) fprintf(stderr, "Invalid data type\n");
2461 (void) fprintf(stderr, "invalid data type\n");
2499 }
2500
2462 }
2463
2501 if (!first)
2502 if (scripted)
2503 (void) printf("\t");
2504 else
2505 (void) printf(" ");
2506
2507 switch (field) {
2508 case USFIELD_TYPE:
2509 strval = (char *)us_type2str(val32);
2464 switch (field) {
2465 case USFIELD_TYPE:
2466 strval = (char *)us_type2str(val32);
2510 width = type_width;
2511 break;
2512 case USFIELD_NAME:
2513 if (type == DATA_TYPE_UINT64) {
2514 (void) sprintf(valstr, "%llu", val64);
2515 strval = valstr;
2516 }
2467 break;
2468 case USFIELD_NAME:
2469 if (type == DATA_TYPE_UINT64) {
2470 (void) sprintf(valstr, "%llu", val64);
2471 strval = valstr;
2472 }
2517 width = name_width;
2518 break;
2519 case USFIELD_USED:
2520 case USFIELD_QUOTA:
2521 if (type == DATA_TYPE_UINT64) {
2473 break;
2474 case USFIELD_USED:
2475 case USFIELD_QUOTA:
2476 if (type == DATA_TYPE_UINT64) {
2522 (void) nvpair_value_uint64(nvp, &val64);
2523 if (parseable)
2477 if (parsable) {
2524 (void) sprintf(valstr, "%llu", val64);
2478 (void) sprintf(valstr, "%llu", val64);
2525 else
2479 } else {
2526 zfs_nicenum(val64, valstr,
2527 sizeof (valstr));
2480 zfs_nicenum(val64, valstr,
2481 sizeof (valstr));
2528 strval = valstr;
2482 }
2483 if (field == USFIELD_QUOTA &&
2484 strcmp(valstr, "0") == 0)
2485 strval = "none";
2486 else
2487 strval = valstr;
2529 }
2488 }
2530
2531 if (field == USFIELD_USED)
2532 width = used_width;
2533 else {
2534 quota_found = B_FALSE;
2535 width = quota_width;
2536 }
2537
2538 break;
2539 }
2540
2489 break;
2490 }
2491
2541 if (field == USFIELD_QUOTA && !quota_found)
2542 (void) printf("%*s", width, strval);
2543 else {
2544 if (type == DATA_TYPE_STRING)
2545 (void) printf("%-*s", width, strval);
2492 if (!first) {
2493 if (scripted)
2494 (void) printf("\t");
2546 else
2495 else
2547 (void) printf("%*s", width, strval);
2496 (void) printf(" ");
2548 }
2497 }
2498 if (scripted)
2499 (void) printf("%s", strval);
2500 else if (field == USFIELD_TYPE || field == USFIELD_NAME)
2501 (void) printf("%-*s", width[field], strval);
2502 else
2503 (void) printf("%*s", width[field], strval);
2549
2550 first = B_FALSE;
2504
2505 first = B_FALSE;
2551
2506 cfield++;
2552 }
2553
2554 (void) printf("\n");
2555}
2556
2557static void
2507 }
2508
2509 (void) printf("\n");
2510}
2511
2512static void
2558print_us(boolean_t scripted, boolean_t parsable, unsigned fields,
2559 unsigned type_width, unsigned name_width, unsigned used_width,
2560 unsigned quota_width, boolean_t rmnode, uu_avl_t *avl)
2513print_us(boolean_t scripted, boolean_t parsable, int *fields, int types,
2514 size_t *width, boolean_t rmnode, uu_avl_t *avl)
2561{
2515{
2562 static char *us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA" };
2563 us_node_t *node;
2564 const char *col;
2516 us_node_t *node;
2517 const char *col;
2565 int i;
2566 size_t width[4] = { type_width, name_width, used_width, quota_width };
2518 int cfield = 0;
2519 int field;
2567
2568 if (!scripted) {
2569 boolean_t first = B_TRUE;
2520
2521 if (!scripted) {
2522 boolean_t first = B_TRUE;
2570 for (i = 0; i < 4; i++) {
2571 unsigned field = us_field_bits[i];
2572 if (!(field & fields))
2573 continue;
2574
2523
2575 col = gettext(us_field_hdr[i]);
2576 if (field == USFIELD_TYPE || field == USFIELD_NAME)
2577 (void) printf(first?"%-*s":" %-*s", width[i],
2578 col);
2579 else
2580 (void) printf(first?"%*s":" %*s", width[i],
2581 col);
2524 while ((field = fields[cfield]) != USFIELD_LAST) {
2525 col = gettext(us_field_hdr[field]);
2526 if (field == USFIELD_TYPE || field == USFIELD_NAME) {
2527 (void) printf(first ? "%-*s" : " %-*s",
2528 width[field], col);
2529 } else {
2530 (void) printf(first ? "%*s" : " %*s",
2531 width[field], col);
2532 }
2582 first = B_FALSE;
2533 first = B_FALSE;
2534 cfield++;
2583 }
2584 (void) printf("\n");
2585 }
2586
2535 }
2536 (void) printf("\n");
2537 }
2538
2587 for (node = uu_avl_first(avl); node != NULL;
2588 node = uu_avl_next(avl, node)) {
2589 print_us_node(scripted, parsable, fields, type_width,
2590 name_width, used_width, used_width, node);
2539 for (node = uu_avl_first(avl); node; node = uu_avl_next(avl, node)) {
2540 print_us_node(scripted, parsable, fields, types, width, node);
2591 if (rmnode)
2592 nvlist_free(node->usn_nvl);
2593 }
2594}
2595
2596static int
2597zfs_do_userspace(int argc, char **argv)
2598{
2599 zfs_handle_t *zhp;
2600 zfs_userquota_prop_t p;
2601
2602 uu_avl_pool_t *avl_pool;
2603 uu_avl_t *avl_tree;
2604 uu_avl_walk_t *walk;
2541 if (rmnode)
2542 nvlist_free(node->usn_nvl);
2543 }
2544}
2545
2546static int
2547zfs_do_userspace(int argc, char **argv)
2548{
2549 zfs_handle_t *zhp;
2550 zfs_userquota_prop_t p;
2551
2552 uu_avl_pool_t *avl_pool;
2553 uu_avl_t *avl_tree;
2554 uu_avl_walk_t *walk;
2605
2606 char *cmd;
2555 char *delim;
2556 char deffields[] = "type,name,used,quota";
2557 char *ofield = NULL;
2558 char *tfield = NULL;
2559 int cfield = 0;
2560 int fields[256];
2561 int i;
2607 boolean_t scripted = B_FALSE;
2608 boolean_t prtnum = B_FALSE;
2562 boolean_t scripted = B_FALSE;
2563 boolean_t prtnum = B_FALSE;
2609 boolean_t parseable = B_FALSE;
2564 boolean_t parsable = B_FALSE;
2610 boolean_t sid2posix = B_FALSE;
2565 boolean_t sid2posix = B_FALSE;
2611 int error = 0;
2566 int ret = 0;
2612 int c;
2567 int c;
2613 zfs_sort_column_t *default_sortcol = NULL;
2614 zfs_sort_column_t *sortcol = NULL;
2568 zfs_sort_column_t *sortcol = NULL;
2615 unsigned types = USTYPE_PSX_USR | USTYPE_SMB_USR;
2616 unsigned fields = 0;
2617 unsigned props = USPROP_USED | USPROP_QUOTA;
2569 int types = USTYPE_PSX_USR | USTYPE_SMB_USR;
2618 us_cbdata_t cb;
2619 us_node_t *node;
2570 us_cbdata_t cb;
2571 us_node_t *node;
2620 boolean_t resort_avl = B_FALSE;
2572 us_node_t *rmnode;
2573 uu_list_pool_t *listpool;
2574 uu_list_t *list;
2575 uu_avl_index_t idx = 0;
2576 uu_list_index_t idx2 = 0;
2621
2622 if (argc < 2)
2623 usage(B_FALSE);
2624
2577
2578 if (argc < 2)
2579 usage(B_FALSE);
2580
2625 cmd = argv[0];
2626 if (0 == strcmp(cmd, "groupspace"))
2627 /* toggle default group types */
2581 if (strcmp(argv[0], "groupspace") == 0)
2582 /* Toggle default group types */
2628 types = USTYPE_PSX_GRP | USTYPE_SMB_GRP;
2629
2583 types = USTYPE_PSX_GRP | USTYPE_SMB_GRP;
2584
2630 /* check options */
2631 while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) {
2632 switch (c) {
2633 case 'n':
2634 prtnum = B_TRUE;
2635 break;
2636 case 'H':
2637 scripted = B_TRUE;
2638 break;
2639 case 'p':
2585 while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) {
2586 switch (c) {
2587 case 'n':
2588 prtnum = B_TRUE;
2589 break;
2590 case 'H':
2591 scripted = B_TRUE;
2592 break;
2593 case 'p':
2640 parseable = B_TRUE;
2594 parsable = B_TRUE;
2641 break;
2642 case 'o':
2595 break;
2596 case 'o':
2643 if (parsefields(&fields, us_field_names, us_field_bits,
2644 4) != 0)
2645 return (1);
2597 ofield = optarg;
2646 break;
2647 case 's':
2598 break;
2599 case 's':
2648 if (zfs_add_sort_column(&sortcol, optarg,
2649 B_FALSE) != 0) {
2650 (void) fprintf(stderr,
2651 gettext("invalid property '%s'\n"), optarg);
2652 usage(B_FALSE);
2653 }
2654 break;
2655 case 'S':
2656 if (zfs_add_sort_column(&sortcol, optarg,
2600 case 'S':
2601 if (zfs_add_sort_column(&sortcol, optarg,
2657 B_TRUE) != 0) {
2602 c == 's' ? B_FALSE : B_TRUE) != 0) {
2658 (void) fprintf(stderr,
2603 (void) fprintf(stderr,
2659 gettext("invalid property '%s'\n"), optarg);
2604 gettext("invalid field '%s'\n"), optarg);
2660 usage(B_FALSE);
2661 }
2662 break;
2663 case 't':
2605 usage(B_FALSE);
2606 }
2607 break;
2608 case 't':
2664 if (parsefields(&types, type_names, type_bits, 5))
2665 return (1);
2609 tfield = optarg;
2666 break;
2667 case 'i':
2668 sid2posix = B_TRUE;
2669 break;
2670 case ':':
2671 (void) fprintf(stderr, gettext("missing argument for "
2672 "'%c' option\n"), optopt);
2673 usage(B_FALSE);
2674 break;
2675 case '?':
2676 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2677 optopt);
2678 usage(B_FALSE);
2679 }
2680 }
2681
2682 argc -= optind;
2683 argv += optind;
2684
2610 break;
2611 case 'i':
2612 sid2posix = B_TRUE;
2613 break;
2614 case ':':
2615 (void) fprintf(stderr, gettext("missing argument for "
2616 "'%c' option\n"), optopt);
2617 usage(B_FALSE);
2618 break;
2619 case '?':
2620 (void) fprintf(stderr, gettext("invalid option '%c'\n"),
2621 optopt);
2622 usage(B_FALSE);
2623 }
2624 }
2625
2626 argc -= optind;
2627 argv += optind;
2628
2685 /* ok, now we have sorted by default colums (type,name) avl tree */
2686 if (sortcol) {
2687 zfs_sort_column_t *sc;
2688 for (sc = sortcol; sc; sc = sc->sc_next) {
2689 if (sc->sc_prop == ZFS_PROP_QUOTA) {
2690 resort_avl = B_TRUE;
2691 break;
2692 }
2693 }
2629 if (argc < 1) {
2630 (void) fprintf(stderr, gettext("missing dataset name\n"));
2631 usage(B_FALSE);
2694 }
2632 }
2633 if (argc > 1) {
2634 (void) fprintf(stderr, gettext("too many arguments\n"));
2635 usage(B_FALSE);
2636 }
2695
2637
2696 if (!fields)
2697 fields = USFIELD_ALL;
2638 /* Use default output fields if not specified using -o */
2639 if (ofield == NULL)
2640 ofield = deffields;
2641 do {
2642 if ((delim = strchr(ofield, ',')) != NULL)
2643 *delim = '\0';
2644 if ((fields[cfield++] = us_field_index(ofield)) == -1) {
2645 (void) fprintf(stderr, gettext("invalid type '%s' "
2646 "for -o option\n"), ofield);
2647 return (-1);
2648 }
2649 if (delim != NULL)
2650 ofield = delim + 1;
2651 } while (delim != NULL);
2652 fields[cfield] = USFIELD_LAST;
2698
2653
2699 if ((zhp = zfs_open(g_zfs, argv[argc-1], ZFS_TYPE_DATASET)) == NULL)
2654 /* Override output types (-t option) */
2655 if (tfield != NULL) {
2656 types = 0;
2657
2658 do {
2659 boolean_t found = B_FALSE;
2660
2661 if ((delim = strchr(tfield, ',')) != NULL)
2662 *delim = '\0';
2663 for (i = 0; i < sizeof (us_type_bits) / sizeof (int);
2664 i++) {
2665 if (strcmp(tfield, us_type_names[i]) == 0) {
2666 found = B_TRUE;
2667 types |= us_type_bits[i];
2668 break;
2669 }
2670 }
2671 if (!found) {
2672 (void) fprintf(stderr, gettext("invalid type "
2673 "'%s' for -t option\n"), tfield);
2674 return (-1);
2675 }
2676 if (delim != NULL)
2677 tfield = delim + 1;
2678 } while (delim != NULL);
2679 }
2680
2681 if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
2700 return (1);
2701
2702 if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t),
2682 return (1);
2683
2684 if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t),
2703 offsetof(us_node_t, usn_avlnode),
2704 us_compare, UU_DEFAULT)) == NULL)
2685 offsetof(us_node_t, usn_avlnode), us_compare, UU_DEFAULT)) == NULL)
2705 nomem();
2706 if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
2707 nomem();
2708
2686 nomem();
2687 if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
2688 nomem();
2689
2709 if (sortcol && !resort_avl)
2710 cb.cb_sortcol = sortcol;
2711 else {
2712 (void) zfs_add_sort_column(&default_sortcol, "type", B_FALSE);
2713 (void) zfs_add_sort_column(&default_sortcol, "name", B_FALSE);
2714 cb.cb_sortcol = default_sortcol;
2715 }
2690 /* Always add default sorting columns */
2691 (void) zfs_add_sort_column(&sortcol, "type", B_FALSE);
2692 (void) zfs_add_sort_column(&sortcol, "name", B_FALSE);
2693
2694 cb.cb_sortcol = sortcol;
2716 cb.cb_numname = prtnum;
2695 cb.cb_numname = prtnum;
2717 cb.cb_nicenum = !parseable;
2696 cb.cb_nicenum = !parsable;
2718 cb.cb_avl_pool = avl_pool;
2719 cb.cb_avl = avl_tree;
2720 cb.cb_sid2posix = sid2posix;
2697 cb.cb_avl_pool = avl_pool;
2698 cb.cb_avl = avl_tree;
2699 cb.cb_sid2posix = sid2posix;
2721 cb.cb_max_typelen = strlen(gettext("TYPE"));
2722 cb.cb_max_namelen = strlen(gettext("NAME"));
2723 cb.cb_max_usedlen = strlen(gettext("USED"));
2724 cb.cb_max_quotalen = strlen(gettext("QUOTA"));
2725
2700
2701 for (i = 0; i < USFIELD_LAST; i++)
2702 cb.cb_width[i] = strlen(gettext(us_field_hdr[i]));
2703
2726 for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
2704 for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
2727 if (!usprop_check(p, types, props))
2705 if (((p == ZFS_PROP_USERUSED || p == ZFS_PROP_USERQUOTA) &&
2706 !(types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
2707 ((p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA) &&
2708 !(types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))))
2728 continue;
2709 continue;
2729
2730 cb.cb_prop = p;
2710 cb.cb_prop = p;
2731 error = zfs_userspace(zhp, p, userspace_cb, &cb);
2732
2733 if (error)
2734 break;
2711 if ((ret = zfs_userspace(zhp, p, userspace_cb, &cb)) != 0)
2712 return (ret);
2735 }
2736
2713 }
2714
2737 if (resort_avl) {
2738 us_node_t *node;
2739 us_node_t *rmnode;
2740 uu_list_pool_t *listpool;
2741 uu_list_t *list;
2742 uu_avl_index_t idx = 0;
2743 uu_list_index_t idx2 = 0;
2744 listpool = uu_list_pool_create("tmplist", sizeof (us_node_t),
2745 offsetof(us_node_t, usn_listnode), NULL,
2746 UU_DEFAULT);
2747 list = uu_list_create(listpool, NULL, UU_DEFAULT);
2715 /* Sort the list */
2716 if ((node = uu_avl_first(avl_tree)) == NULL)
2717 return (0);
2748
2718
2749 node = uu_avl_first(avl_tree);
2750 uu_list_node_init(node, &node->usn_listnode, listpool);
2751 while (node != NULL) {
2752 rmnode = node;
2753 node = uu_avl_next(avl_tree, node);
2754 uu_avl_remove(avl_tree, rmnode);
2755 if (uu_list_find(list, rmnode, NULL, &idx2) == NULL) {
2756 uu_list_insert(list, rmnode, idx2);
2757 }
2758 }
2719 us_populated = B_TRUE;
2759
2720
2760 for (node = uu_list_first(list); node != NULL;
2761 node = uu_list_next(list, node)) {
2762 us_sort_info_t sortinfo = { sortcol, cb.cb_numname };
2763 if (uu_avl_find(avl_tree, node, &sortinfo, &idx) ==
2764 NULL)
2765 uu_avl_insert(avl_tree, node, idx);
2766 }
2721 listpool = uu_list_pool_create("tmplist", sizeof (us_node_t),
2722 offsetof(us_node_t, usn_listnode), NULL, UU_DEFAULT);
2723 list = uu_list_create(listpool, NULL, UU_DEFAULT);
2724 uu_list_node_init(node, &node->usn_listnode, listpool);
2767
2725
2768 uu_list_destroy(list);
2726 while (node != NULL) {
2727 rmnode = node;
2728 node = uu_avl_next(avl_tree, node);
2729 uu_avl_remove(avl_tree, rmnode);
2730 if (uu_list_find(list, rmnode, NULL, &idx2) == NULL)
2731 uu_list_insert(list, rmnode, idx2);
2769 }
2770
2732 }
2733
2771 /* print & free node`s nvlist memory */
2772 print_us(scripted, parseable, fields, cb.cb_max_typelen,
2773 cb.cb_max_namelen, cb.cb_max_usedlen,
2774 cb.cb_max_quotalen, B_TRUE, cb.cb_avl);
2734 for (node = uu_list_first(list); node != NULL;
2735 node = uu_list_next(list, node)) {
2736 us_sort_info_t sortinfo = { sortcol, cb.cb_numname };
2775
2737
2776 if (sortcol)
2777 zfs_free_sort_columns(sortcol);
2778 zfs_free_sort_columns(default_sortcol);
2738 if (uu_avl_find(avl_tree, node, &sortinfo, &idx) == NULL)
2739 uu_avl_insert(avl_tree, node, idx);
2740 }
2779
2741
2780 /*
2781 * Finally, clean up the AVL tree.
2782 */
2742 uu_list_destroy(list);
2743 uu_list_pool_destroy(listpool);
2744
2745 /* Print and free node nvlist memory */
2746 print_us(scripted, parsable, fields, types, cb.cb_width, B_TRUE,
2747 cb.cb_avl);
2748
2749 zfs_free_sort_columns(sortcol);
2750
2751 /* Clean up the AVL tree */
2783 if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
2784 nomem();
2785
2786 while ((node = uu_avl_walk_next(walk)) != NULL) {
2787 uu_avl_remove(cb.cb_avl, node);
2788 free(node);
2789 }
2790
2791 uu_avl_walk_end(walk);
2792 uu_avl_destroy(avl_tree);
2793 uu_avl_pool_destroy(avl_pool);
2794
2752 if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
2753 nomem();
2754
2755 while ((node = uu_avl_walk_next(walk)) != NULL) {
2756 uu_avl_remove(cb.cb_avl, node);
2757 free(node);
2758 }
2759
2760 uu_avl_walk_end(walk);
2761 uu_avl_destroy(avl_tree);
2762 uu_avl_pool_destroy(avl_pool);
2763
2795 return (error);
2764 return (ret);
2796}
2797
2798/*
2799 * list [-r][-d max] [-H] [-o property[,property]...] [-t type[,type]...]
2800 * [-s property [-s property]...] [-S property [-S property]...]
2801 * <dataset> ...
2802 *
2803 * -r Recurse over all children

--- 3901 unchanged lines hidden ---
2765}
2766
2767/*
2768 * list [-r][-d max] [-H] [-o property[,property]...] [-t type[,type]...]
2769 * [-s property [-s property]...] [-S property [-S property]...]
2770 * <dataset> ...
2771 *
2772 * -r Recurse over all children

--- 3901 unchanged lines hidden ---