libzfs_dataset.c (177698) | libzfs_dataset.c (185029) |
---|---|
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 --- 6 unchanged lines hidden (view full) --- 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* | 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 --- 6 unchanged lines hidden (view full) --- 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* |
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
24 * Use is subject to license terms. 25 */ 26 | 24 * Use is subject to license terms. 25 */ 26 |
27#pragma ident "%Z%%M% %I% %E% SMI" 28 | |
29#include <assert.h> 30#include <ctype.h> 31#include <errno.h> 32#include <libintl.h> 33#include <math.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <strings.h> 37#include <unistd.h> | 27#include <assert.h> 28#include <ctype.h> 29#include <errno.h> 30#include <libintl.h> 31#include <math.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <strings.h> 35#include <unistd.h> |
36#include <stddef.h> |
|
38#include <zone.h> 39#include <fcntl.h> 40#include <sys/mntent.h> 41#include <sys/mnttab.h> 42#include <sys/mount.h> | 37#include <zone.h> 38#include <fcntl.h> 39#include <sys/mntent.h> 40#include <sys/mnttab.h> 41#include <sys/mount.h> |
42#include <sys/avl.h> 43#include <priv.h> 44#include <pwd.h> 45#include <grp.h> 46#include <stddef.h> |
|
43 44#include <sys/spa.h> | 47 48#include <sys/spa.h> |
45#include <sys/zio.h> | |
46#include <sys/zap.h> 47#include <libzfs.h> 48 49#include "zfs_namecheck.h" 50#include "zfs_prop.h" 51#include "libzfs_impl.h" | 49#include <sys/zap.h> 50#include <libzfs.h> 51 52#include "zfs_namecheck.h" 53#include "zfs_prop.h" 54#include "libzfs_impl.h" |
55#include "zfs_deleg.h" |
|
52 53static int zvol_create_link_common(libzfs_handle_t *, const char *, int); 54 55/* 56 * Given a single type (not a mask of types), return the type in a human 57 * readable form. 58 */ 59const char * --- 56 unchanged lines hidden (view full) --- 116} 117 118/* 119 * Validate a ZFS path. This is used even before trying to open the dataset, to 120 * provide a more meaningful error message. We place a more useful message in 121 * 'buf' detailing exactly why the name was not valid. 122 */ 123static int | 56 57static int zvol_create_link_common(libzfs_handle_t *, const char *, int); 58 59/* 60 * Given a single type (not a mask of types), return the type in a human 61 * readable form. 62 */ 63const char * --- 56 unchanged lines hidden (view full) --- 120} 121 122/* 123 * Validate a ZFS path. This is used even before trying to open the dataset, to 124 * provide a more meaningful error message. We place a more useful message in 125 * 'buf' detailing exactly why the name was not valid. 126 */ 127static int |
124zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type) | 128zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, 129 boolean_t modifying) |
125{ 126 namecheck_err_t why; 127 char what; 128 129 if (dataset_namecheck(path, &why, &what) != 0) { 130 if (hdl != NULL) { 131 switch (why) { 132 case NAME_ERR_TOOLONG: --- 56 unchanged lines hidden (view full) --- 189 190 if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 191 if (hdl != NULL) 192 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 193 "missing '@' delimiter in snapshot name")); 194 return (0); 195 } 196 | 130{ 131 namecheck_err_t why; 132 char what; 133 134 if (dataset_namecheck(path, &why, &what) != 0) { 135 if (hdl != NULL) { 136 switch (why) { 137 case NAME_ERR_TOOLONG: --- 56 unchanged lines hidden (view full) --- 194 195 if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) { 196 if (hdl != NULL) 197 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 198 "missing '@' delimiter in snapshot name")); 199 return (0); 200 } 201 |
202 if (modifying && strchr(path, '%') != NULL) { 203 if (hdl != NULL) 204 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 205 "invalid character %c in name"), '%'); 206 return (0); 207 } 208 |
|
197 return (-1); 198} 199 200int 201zfs_name_valid(const char *name, zfs_type_t type) 202{ | 209 return (-1); 210} 211 212int 213zfs_name_valid(const char *name, zfs_type_t type) 214{ |
203 return (zfs_validate_name(NULL, name, type)); | 215 if (type == ZFS_TYPE_POOL) 216 return (zpool_name_valid(NULL, B_FALSE, name)); 217 return (zfs_validate_name(NULL, name, type, B_FALSE)); |
204} 205 206/* 207 * This function takes the raw DSL properties, and filters out the user-defined 208 * properties into a separate nvlist. 209 */ | 218} 219 220/* 221 * This function takes the raw DSL properties, and filters out the user-defined 222 * properties into a separate nvlist. 223 */ |
210static int 211process_user_props(zfs_handle_t *zhp) | 224static nvlist_t * 225process_user_props(zfs_handle_t *zhp, nvlist_t *props) |
212{ 213 libzfs_handle_t *hdl = zhp->zfs_hdl; 214 nvpair_t *elem; 215 nvlist_t *propval; | 226{ 227 libzfs_handle_t *hdl = zhp->zfs_hdl; 228 nvpair_t *elem; 229 nvlist_t *propval; |
230 nvlist_t *nvl; |
|
216 | 231 |
217 nvlist_free(zhp->zfs_user_props); | 232 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 233 (void) no_memory(hdl); 234 return (NULL); 235 } |
218 | 236 |
219 if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0) 220 return (no_memory(hdl)); 221 | |
222 elem = NULL; | 237 elem = NULL; |
223 while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) { | 238 while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { |
224 if (!zfs_prop_user(nvpair_name(elem))) 225 continue; 226 227 verify(nvpair_value_nvlist(elem, &propval) == 0); | 239 if (!zfs_prop_user(nvpair_name(elem))) 240 continue; 241 242 verify(nvpair_value_nvlist(elem, &propval) == 0); |
228 if (nvlist_add_nvlist(zhp->zfs_user_props, 229 nvpair_name(elem), propval) != 0) 230 return (no_memory(hdl)); | 243 if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) { 244 nvlist_free(nvl); 245 (void) no_memory(hdl); 246 return (NULL); 247 } |
231 } 232 | 248 } 249 |
233 return (0); | 250 return (nvl); |
234} 235 | 251} 252 |
253static zpool_handle_t * 254zpool_add_handle(zfs_handle_t *zhp, const char *pool_name) 255{ 256 libzfs_handle_t *hdl = zhp->zfs_hdl; 257 zpool_handle_t *zph; 258 259 if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) { 260 if (hdl->libzfs_pool_handles != NULL) 261 zph->zpool_next = hdl->libzfs_pool_handles; 262 hdl->libzfs_pool_handles = zph; 263 } 264 return (zph); 265} 266 267static zpool_handle_t * 268zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) 269{ 270 libzfs_handle_t *hdl = zhp->zfs_hdl; 271 zpool_handle_t *zph = hdl->libzfs_pool_handles; 272 273 while ((zph != NULL) && 274 (strncmp(pool_name, zpool_get_name(zph), len) != 0)) 275 zph = zph->zpool_next; 276 return (zph); 277} 278 |
|
236/* | 279/* |
280 * Returns a handle to the pool that contains the provided dataset. 281 * If a handle to that pool already exists then that handle is returned. 282 * Otherwise, a new handle is created and added to the list of handles. 283 */ 284static zpool_handle_t * 285zpool_handle(zfs_handle_t *zhp) 286{ 287 char *pool_name; 288 int len; 289 zpool_handle_t *zph; 290 291 len = strcspn(zhp->zfs_name, "/@") + 1; 292 pool_name = zfs_alloc(zhp->zfs_hdl, len); 293 (void) strlcpy(pool_name, zhp->zfs_name, len); 294 295 zph = zpool_find_handle(zhp, pool_name, len); 296 if (zph == NULL) 297 zph = zpool_add_handle(zhp, pool_name); 298 299 free(pool_name); 300 return (zph); 301} 302 303void 304zpool_free_handles(libzfs_handle_t *hdl) 305{ 306 zpool_handle_t *next, *zph = hdl->libzfs_pool_handles; 307 308 while (zph != NULL) { 309 next = zph->zpool_next; 310 zpool_close(zph); 311 zph = next; 312 } 313 hdl->libzfs_pool_handles = NULL; 314} 315 316/* |
|
237 * Utility function to gather stats (objset and zpl) for the given object. 238 */ 239static int 240get_stats(zfs_handle_t *zhp) 241{ 242 zfs_cmd_t zc = { 0 }; 243 libzfs_handle_t *hdl = zhp->zfs_hdl; | 317 * Utility function to gather stats (objset and zpl) for the given object. 318 */ 319static int 320get_stats(zfs_handle_t *zhp) 321{ 322 zfs_cmd_t zc = { 0 }; 323 libzfs_handle_t *hdl = zhp->zfs_hdl; |
324 nvlist_t *allprops, *userprops; |
|
244 245 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 246 247 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 248 return (-1); 249 250 while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 251 if (errno == ENOMEM) { --- 4 unchanged lines hidden (view full) --- 256 } else { 257 zcmd_free_nvlists(&zc); 258 return (-1); 259 } 260 } 261 262 zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */ 263 | 325 326 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 327 328 if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) 329 return (-1); 330 331 while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) { 332 if (errno == ENOMEM) { --- 4 unchanged lines hidden (view full) --- 337 } else { 338 zcmd_free_nvlists(&zc); 339 return (-1); 340 } 341 } 342 343 zhp->zfs_dmustats = zc.zc_objset_stats; /* structure assignment */ 344 |
264 (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root)); 265 266 if (zhp->zfs_props) { 267 nvlist_free(zhp->zfs_props); 268 zhp->zfs_props = NULL; 269 } 270 271 if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) { | 345 if (zcmd_read_dst_nvlist(hdl, &zc, &allprops) != 0) { |
272 zcmd_free_nvlists(&zc); 273 return (-1); 274 } 275 276 zcmd_free_nvlists(&zc); 277 | 346 zcmd_free_nvlists(&zc); 347 return (-1); 348 } 349 350 zcmd_free_nvlists(&zc); 351 |
278 if (process_user_props(zhp) != 0) | 352 if ((userprops = process_user_props(zhp, allprops)) == NULL) { 353 nvlist_free(allprops); |
279 return (-1); | 354 return (-1); |
355 } |
|
280 | 356 |
357 nvlist_free(zhp->zfs_props); 358 nvlist_free(zhp->zfs_user_props); 359 360 zhp->zfs_props = allprops; 361 zhp->zfs_user_props = userprops; 362 |
|
281 return (0); 282} 283 284/* 285 * Refresh the properties currently stored in the handle. 286 */ 287void 288zfs_refresh_properties(zfs_handle_t *zhp) --- 4 unchanged lines hidden (view full) --- 293/* 294 * Makes a handle from the given dataset name. Used by zfs_open() and 295 * zfs_iter_* to create child handles on the fly. 296 */ 297zfs_handle_t * 298make_dataset_handle(libzfs_handle_t *hdl, const char *path) 299{ 300 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); | 363 return (0); 364} 365 366/* 367 * Refresh the properties currently stored in the handle. 368 */ 369void 370zfs_refresh_properties(zfs_handle_t *zhp) --- 4 unchanged lines hidden (view full) --- 375/* 376 * Makes a handle from the given dataset name. Used by zfs_open() and 377 * zfs_iter_* to create child handles on the fly. 378 */ 379zfs_handle_t * 380make_dataset_handle(libzfs_handle_t *hdl, const char *path) 381{ 382 zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); |
383 char *logstr; |
|
301 302 if (zhp == NULL) 303 return (NULL); 304 305 zhp->zfs_hdl = hdl; 306 | 384 385 if (zhp == NULL) 386 return (NULL); 387 388 zhp->zfs_hdl = hdl; 389 |
390 /* 391 * Preserve history log string. 392 * any changes performed here will be 393 * logged as an internal event. 394 */ 395 logstr = zhp->zfs_hdl->libzfs_log_str; 396 zhp->zfs_hdl->libzfs_log_str = NULL; |
|
307top: 308 (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 309 310 if (get_stats(zhp) != 0) { | 397top: 398 (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); 399 400 if (get_stats(zhp) != 0) { |
401 zhp->zfs_hdl->libzfs_log_str = logstr; |
|
311 free(zhp); 312 return (NULL); 313 } 314 315 if (zhp->zfs_dmustats.dds_inconsistent) { 316 zfs_cmd_t zc = { 0 }; 317 318 /* --- 15 unchanged lines hidden (view full) --- 334 335 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 336 (void) zvol_remove_link(hdl, zhp->zfs_name); 337 zc.zc_objset_type = DMU_OST_ZVOL; 338 } else { 339 zc.zc_objset_type = DMU_OST_ZFS; 340 } 341 | 402 free(zhp); 403 return (NULL); 404 } 405 406 if (zhp->zfs_dmustats.dds_inconsistent) { 407 zfs_cmd_t zc = { 0 }; 408 409 /* --- 15 unchanged lines hidden (view full) --- 425 426 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) { 427 (void) zvol_remove_link(hdl, zhp->zfs_name); 428 zc.zc_objset_type = DMU_OST_ZVOL; 429 } else { 430 zc.zc_objset_type = DMU_OST_ZFS; 431 } 432 |
342 /* If we can successfully roll it back, reget the stats */ 343 if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 344 goto top; | |
345 /* | 433 /* |
346 * If we can sucessfully destroy it, pretend that it | 434 * If we can successfully destroy it, pretend that it |
347 * never existed. 348 */ 349 if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { | 435 * never existed. 436 */ 437 if (ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) == 0) { |
438 zhp->zfs_hdl->libzfs_log_str = logstr; |
|
350 free(zhp); 351 errno = ENOENT; 352 return (NULL); 353 } | 439 free(zhp); 440 errno = ENOENT; 441 return (NULL); 442 } |
443 /* If we can successfully roll it back, reget the stats */ 444 if (ioctl(hdl->libzfs_fd, ZFS_IOC_ROLLBACK, &zc) == 0) 445 goto top; |
|
354 } 355 356 /* 357 * We've managed to open the dataset and gather statistics. Determine 358 * the high-level type. 359 */ 360 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 361 zhp->zfs_head_type = ZFS_TYPE_VOLUME; --- 6 unchanged lines hidden (view full) --- 368 zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 369 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 370 zhp->zfs_type = ZFS_TYPE_VOLUME; 371 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 372 zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 373 else 374 abort(); /* we should never see any other types */ 375 | 446 } 447 448 /* 449 * We've managed to open the dataset and gather statistics. Determine 450 * the high-level type. 451 */ 452 if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 453 zhp->zfs_head_type = ZFS_TYPE_VOLUME; --- 6 unchanged lines hidden (view full) --- 460 zhp->zfs_type = ZFS_TYPE_SNAPSHOT; 461 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL) 462 zhp->zfs_type = ZFS_TYPE_VOLUME; 463 else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) 464 zhp->zfs_type = ZFS_TYPE_FILESYSTEM; 465 else 466 abort(); /* we should never see any other types */ 467 |
468 zhp->zfs_hdl->libzfs_log_str = logstr; 469 zhp->zpool_hdl = zpool_handle(zhp); |
|
376 return (zhp); 377} 378 379/* 380 * Opens the given snapshot, filesystem, or volume. The 'types' 381 * argument is a mask of acceptable types. The function will print an 382 * appropriate error message and return NULL if it can't be opened. 383 */ --- 4 unchanged lines hidden (view full) --- 388 char errbuf[1024]; 389 390 (void) snprintf(errbuf, sizeof (errbuf), 391 dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 392 393 /* 394 * Validate the name before we even try to open it. 395 */ | 470 return (zhp); 471} 472 473/* 474 * Opens the given snapshot, filesystem, or volume. The 'types' 475 * argument is a mask of acceptable types. The function will print an 476 * appropriate error message and return NULL if it can't be opened. 477 */ --- 4 unchanged lines hidden (view full) --- 482 char errbuf[1024]; 483 484 (void) snprintf(errbuf, sizeof (errbuf), 485 dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); 486 487 /* 488 * Validate the name before we even try to open it. 489 */ |
396 if (!zfs_validate_name(hdl, path, ZFS_TYPE_ANY)) { | 490 if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { |
397 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 398 "invalid dataset name")); 399 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 400 return (NULL); 401 } 402 403 /* 404 * Try to get stats for the dataset, which will tell us if it exists. --- 21 unchanged lines hidden (view full) --- 426{ 427 if (zhp->zfs_mntopts) 428 free(zhp->zfs_mntopts); 429 nvlist_free(zhp->zfs_props); 430 nvlist_free(zhp->zfs_user_props); 431 free(zhp); 432} 433 | 491 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 492 "invalid dataset name")); 493 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 494 return (NULL); 495 } 496 497 /* 498 * Try to get stats for the dataset, which will tell us if it exists. --- 21 unchanged lines hidden (view full) --- 520{ 521 if (zhp->zfs_mntopts) 522 free(zhp->zfs_mntopts); 523 nvlist_free(zhp->zfs_props); 524 nvlist_free(zhp->zfs_user_props); 525 free(zhp); 526} 527 |
434/* 435 * Given a numeric suffix, convert the value into a number of bits that the 436 * resulting value must be shifted. 437 */ 438static int 439str2shift(libzfs_handle_t *hdl, const char *buf) | 528int 529zfs_spa_version(zfs_handle_t *zhp, int *spa_version) |
440{ | 530{ |
441 const char *ends = "BKMGTPEZ"; 442 int i; | 531 zpool_handle_t *zpool_handle = zhp->zpool_hdl; |
443 | 532 |
444 if (buf[0] == '\0') 445 return (0); 446 for (i = 0; i < strlen(ends); i++) { 447 if (toupper(buf[0]) == ends[i]) 448 break; 449 } 450 if (i == strlen(ends)) { 451 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 452 "invalid numeric suffix '%s'"), buf); | 533 if (zpool_handle == NULL) |
453 return (-1); | 534 return (-1); |
454 } | |
455 | 535 |
456 /* 457 * We want to allow trailing 'b' characters for 'GB' or 'Mb'. But don't 458 * allow 'BB' - that's just weird. 459 */ 460 if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' && 461 toupper(buf[0]) != 'B')) 462 return (10*i); 463 464 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 465 "invalid numeric suffix '%s'"), buf); 466 return (-1); 467} 468 469/* 470 * Convert a string of the form '100G' into a real number. Used when setting 471 * properties or creating a volume. 'buf' is used to place an extended error 472 * message for the caller to use. 473 */ 474static int 475nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num) 476{ 477 char *end; 478 int shift; 479 480 *num = 0; 481 482 /* Check to see if this looks like a number. */ 483 if ((value[0] < '0' || value[0] > '9') && value[0] != '.') { 484 if (hdl) 485 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 486 "bad numeric value '%s'"), value); 487 return (-1); 488 } 489 490 /* Rely on stroll() to process the numeric portion. */ 491 errno = 0; 492 *num = strtoll(value, &end, 10); 493 494 /* 495 * Check for ERANGE, which indicates that the value is too large to fit 496 * in a 64-bit value. 497 */ 498 if (errno == ERANGE) { 499 if (hdl) 500 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 501 "numeric value is too large")); 502 return (-1); 503 } 504 505 /* 506 * If we have a decimal value, then do the computation with floating 507 * point arithmetic. Otherwise, use standard arithmetic. 508 */ 509 if (*end == '.') { 510 double fval = strtod(value, &end); 511 512 if ((shift = str2shift(hdl, end)) == -1) 513 return (-1); 514 515 fval *= pow(2, shift); 516 517 if (fval > UINT64_MAX) { 518 if (hdl) 519 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 520 "numeric value is too large")); 521 return (-1); 522 } 523 524 *num = (uint64_t)fval; 525 } else { 526 if ((shift = str2shift(hdl, end)) == -1) 527 return (-1); 528 529 /* Check for overflow */ 530 if (shift >= 64 || (*num << shift) >> shift != *num) { 531 if (hdl) 532 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 533 "numeric value is too large")); 534 return (-1); 535 } 536 537 *num <<= shift; 538 } 539 | 536 *spa_version = zpool_get_prop_int(zpool_handle, 537 ZPOOL_PROP_VERSION, NULL); |
540 return (0); 541} 542 | 538 return (0); 539} 540 |
543int 544zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val) 545{ 546 return (nicestrtonum(hdl, str, val)); 547} 548 | |
549/* | 541/* |
550 * The prop_parse_*() functions are designed to allow flexibility in callers 551 * when setting properties. At the DSL layer, all properties are either 64-bit 552 * numbers or strings. We want the user to be able to ignore this fact and 553 * specify properties as native values (boolean, for example) or as strings (to 554 * simplify command line utilities). This also handles converting index types 555 * (compression, checksum, etc) from strings to their on-disk index. | 542 * The choice of reservation property depends on the SPA version. |
556 */ | 543 */ |
557 | |
558static int | 544static int |
559prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val) | 545zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) |
560{ | 546{ |
561 uint64_t ret; | 547 int spa_version; |
562 | 548 |
563 switch (nvpair_type(elem)) { 564 case DATA_TYPE_STRING: 565 { 566 char *value; 567 verify(nvpair_value_string(elem, &value) == 0); 568 569 if (strcmp(value, "on") == 0) { 570 ret = 1; 571 } else if (strcmp(value, "off") == 0) { 572 ret = 0; 573 } else { 574 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 575 "property '%s' must be 'on' or 'off'"), 576 nvpair_name(elem)); 577 return (-1); 578 } 579 break; 580 } 581 582 case DATA_TYPE_UINT64: 583 { 584 verify(nvpair_value_uint64(elem, &ret) == 0); 585 if (ret > 1) { 586 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 587 "'%s' must be a boolean value"), 588 nvpair_name(elem)); 589 return (-1); 590 } 591 break; 592 } 593 594 case DATA_TYPE_BOOLEAN_VALUE: 595 { 596 boolean_t value; 597 verify(nvpair_value_boolean_value(elem, &value) == 0); 598 ret = value; 599 break; 600 } 601 602 default: 603 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 604 "'%s' must be a boolean value"), 605 nvpair_name(elem)); | 549 if (zfs_spa_version(zhp, &spa_version) < 0) |
606 return (-1); | 550 return (-1); |
607 } | |
608 | 551 |
609 *val = ret; 610 return (0); 611} | 552 if (spa_version >= SPA_VERSION_REFRESERVATION) 553 *resv_prop = ZFS_PROP_REFRESERVATION; 554 else 555 *resv_prop = ZFS_PROP_RESERVATION; |
612 | 556 |
613static int 614prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 615 uint64_t *val) 616{ 617 uint64_t ret; 618 boolean_t isnone = B_FALSE; 619 620 switch (nvpair_type(elem)) { 621 case DATA_TYPE_STRING: 622 { 623 char *value; 624 (void) nvpair_value_string(elem, &value); 625 if (strcmp(value, "none") == 0) { 626 isnone = B_TRUE; 627 ret = 0; 628 } else if (nicestrtonum(hdl, value, &ret) != 0) { 629 return (-1); 630 } 631 break; 632 } 633 634 case DATA_TYPE_UINT64: 635 (void) nvpair_value_uint64(elem, &ret); 636 break; 637 638 default: 639 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 640 "'%s' must be a number"), 641 nvpair_name(elem)); 642 return (-1); 643 } 644 645 /* 646 * Quota special: force 'none' and don't allow 0. 647 */ 648 if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) { 649 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 650 "use 'none' to disable quota")); 651 return (-1); 652 } 653 654 *val = ret; | |
655 return (0); 656} 657 | 557 return (0); 558} 559 |
658static int 659prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop, 660 uint64_t *val) 661{ 662 char *propname = nvpair_name(elem); 663 char *value; 664 665 if (nvpair_type(elem) != DATA_TYPE_STRING) { 666 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 667 "'%s' must be a string"), propname); 668 return (-1); 669 } 670 671 (void) nvpair_value_string(elem, &value); 672 673 if (zfs_prop_string_to_index(prop, value, val) != 0) { 674 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 675 "'%s' must be one of '%s'"), propname, 676 zfs_prop_values(prop)); 677 return (-1); 678 } 679 680 return (0); 681} 682 | |
683/* | 560/* |
684 * Check if the bootfs name has the same pool name as it is set to. 685 * Assuming bootfs is a valid dataset name. 686 */ 687static boolean_t 688bootfs_poolname_valid(char *pool, char *bootfs) 689{ 690 char ch, *pname; 691 692 /* get the pool name from the bootfs name */ 693 pname = bootfs; 694 while (*bootfs && !isspace(*bootfs) && *bootfs != '/') 695 bootfs++; 696 697 ch = *bootfs; 698 *bootfs = 0; 699 700 if (strcmp(pool, pname) == 0) { 701 *bootfs = ch; 702 return (B_TRUE); 703 } 704 705 *bootfs = ch; 706 return (B_FALSE); 707} 708 709/* | |
710 * Given an nvlist of properties to set, validates that they are correct, and 711 * parses any numeric properties (index, boolean, etc) if they are specified as 712 * strings. 713 */ 714nvlist_t * | 561 * Given an nvlist of properties to set, validates that they are correct, and 562 * parses any numeric properties (index, boolean, etc) if they are specified as 563 * strings. 564 */ 565nvlist_t * |
715zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name, 716 nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) | 566zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, 567 uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) |
717{ 718 nvpair_t *elem; | 568{ 569 nvpair_t *elem; |
719 const char *propname; 720 zfs_prop_t prop; | |
721 uint64_t intval; 722 char *strval; | 570 uint64_t intval; 571 char *strval; |
572 zfs_prop_t prop; |
|
723 nvlist_t *ret; | 573 nvlist_t *ret; |
724 int isuser; | 574 int chosen_normal = -1; 575 int chosen_utf = -1; |
725 726 if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 727 (void) no_memory(hdl); 728 return (NULL); 729 } 730 | 576 577 if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { 578 (void) no_memory(hdl); 579 return (NULL); 580 } 581 |
731 if (type == ZFS_TYPE_SNAPSHOT) { 732 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 733 "snapshot properties cannot be modified")); 734 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 735 goto error; 736 } 737 | |
738 elem = NULL; 739 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { | 582 elem = NULL; 583 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { |
740 propname = nvpair_name(elem); | 584 const char *propname = nvpair_name(elem); |
741 742 /* 743 * Make sure this property is valid and applies to this type. 744 */ | 585 586 /* 587 * Make sure this property is valid and applies to this type. 588 */ |
745 if ((prop = zfs_name_to_prop_common(propname, type)) 746 == ZFS_PROP_INVAL) { 747 isuser = zfs_prop_user(propname); 748 if (!isuser || (isuser && (type & ZFS_TYPE_POOL))) { | 589 if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { 590 if (!zfs_prop_user(propname)) { |
749 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, | 591 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
750 "invalid property '%s'"), 751 propname); | 592 "invalid property '%s'"), propname); |
752 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 753 goto error; | 593 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 594 goto error; |
754 } else { 755 /* 756 * If this is a user property, make sure it's a 757 * string, and that it's less than 758 * ZAP_MAXNAMELEN. 759 */ 760 if (nvpair_type(elem) != DATA_TYPE_STRING) { 761 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 762 "'%s' must be a string"), 763 propname); 764 (void) zfs_error(hdl, EZFS_BADPROP, 765 errbuf); 766 goto error; 767 } | 595 } |
768 | 596 |
769 if (strlen(nvpair_name(elem)) >= 770 ZAP_MAXNAMELEN) { 771 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 772 "property name '%s' is too long"), 773 propname); 774 (void) zfs_error(hdl, EZFS_BADPROP, 775 errbuf); 776 goto error; 777 } | 597 /* 598 * If this is a user property, make sure it's a 599 * string, and that it's less than ZAP_MAXNAMELEN. 600 */ 601 if (nvpair_type(elem) != DATA_TYPE_STRING) { 602 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 603 "'%s' must be a string"), propname); 604 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 605 goto error; |
778 } 779 | 606 } 607 |
608 if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) { 609 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 610 "property name '%s' is too long"), 611 propname); 612 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 613 goto error; 614 } 615 |
|
780 (void) nvpair_value_string(elem, &strval); 781 if (nvlist_add_string(ret, propname, strval) != 0) { 782 (void) no_memory(hdl); 783 goto error; 784 } 785 continue; 786 } 787 | 616 (void) nvpair_value_string(elem, &strval); 617 if (nvlist_add_string(ret, propname, strval) != 0) { 618 (void) no_memory(hdl); 619 goto error; 620 } 621 continue; 622 } 623 |
788 /* 789 * Normalize the name, to get rid of shorthand abbrevations. 790 */ 791 propname = zfs_prop_to_name(prop); | 624 if (type == ZFS_TYPE_SNAPSHOT) { 625 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 626 "this property can not be modified for snapshots")); 627 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 628 goto error; 629 } |
792 793 if (!zfs_prop_valid_for_type(prop, type)) { 794 zfs_error_aux(hdl, 795 dgettext(TEXT_DOMAIN, "'%s' does not " 796 "apply to datasets of this type"), propname); 797 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 798 goto error; 799 } 800 801 if (zfs_prop_readonly(prop) && | 630 631 if (!zfs_prop_valid_for_type(prop, type)) { 632 zfs_error_aux(hdl, 633 dgettext(TEXT_DOMAIN, "'%s' does not " 634 "apply to datasets of this type"), propname); 635 (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); 636 goto error; 637 } 638 639 if (zfs_prop_readonly(prop) && |
802 (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) { | 640 (!zfs_prop_setonce(prop) || zhp != NULL)) { |
803 zfs_error_aux(hdl, 804 dgettext(TEXT_DOMAIN, "'%s' is readonly"), 805 propname); 806 (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 807 goto error; 808 } 809 | 641 zfs_error_aux(hdl, 642 dgettext(TEXT_DOMAIN, "'%s' is readonly"), 643 propname); 644 (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); 645 goto error; 646 } 647 |
648 if (zprop_parse_value(hdl, elem, prop, type, ret, 649 &strval, &intval, errbuf) != 0) 650 goto error; 651 |
|
810 /* | 652 /* |
811 * Convert any properties to the internal DSL value types. | 653 * Perform some additional checks for specific properties. |
812 */ | 654 */ |
813 strval = NULL; 814 switch (zfs_prop_get_type(prop)) { 815 case prop_type_boolean: 816 if (prop_parse_boolean(hdl, elem, &intval) != 0) { 817 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 818 goto error; 819 } 820 break; | 655 switch (prop) { 656 case ZFS_PROP_VERSION: 657 { 658 int version; |
821 | 659 |
822 case prop_type_string: 823 if (nvpair_type(elem) != DATA_TYPE_STRING) { | 660 if (zhp == NULL) 661 break; 662 version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); 663 if (intval < version) { |
824 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, | 664 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
825 "'%s' must be a string"), 826 propname); | 665 "Can not downgrade; already at version %u"), 666 version); |
827 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 828 goto error; 829 } | 667 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 668 goto error; 669 } |
830 (void) nvpair_value_string(elem, &strval); 831 if (strlen(strval) >= ZFS_MAXPROPLEN) { 832 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 833 "'%s' is too long"), propname); 834 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 835 goto error; 836 } | |
837 break; | 670 break; |
838 839 case prop_type_number: 840 if (prop_parse_number(hdl, elem, prop, &intval) != 0) { 841 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 842 goto error; 843 } 844 break; 845 846 case prop_type_index: 847 if (prop_parse_index(hdl, elem, prop, &intval) != 0) { 848 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 849 goto error; 850 } 851 break; 852 853 default: 854 abort(); | |
855 } 856 | 671 } 672 |
857 /* 858 * Add the result to our return set of properties. 859 */ 860 if (strval) { 861 if (nvlist_add_string(ret, propname, strval) != 0) { 862 (void) no_memory(hdl); 863 goto error; 864 } 865 } else if (nvlist_add_uint64(ret, propname, intval) != 0) { 866 (void) no_memory(hdl); 867 goto error; 868 } 869 870 /* 871 * Perform some additional checks for specific properties. 872 */ 873 switch (prop) { | |
874 case ZFS_PROP_RECORDSIZE: 875 case ZFS_PROP_VOLBLOCKSIZE: 876 /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 877 if (intval < SPA_MINBLOCKSIZE || 878 intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 879 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 880 "'%s' must be power of 2 from %u " 881 "to %uk"), propname, --- 13 unchanged lines hidden (view full) --- 895 propname); 896 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 897 goto error; 898 } 899 900 break; 901 902 case ZFS_PROP_MOUNTPOINT: | 673 case ZFS_PROP_RECORDSIZE: 674 case ZFS_PROP_VOLBLOCKSIZE: 675 /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ 676 if (intval < SPA_MINBLOCKSIZE || 677 intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { 678 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 679 "'%s' must be power of 2 from %u " 680 "to %uk"), propname, --- 13 unchanged lines hidden (view full) --- 694 propname); 695 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 696 goto error; 697 } 698 699 break; 700 701 case ZFS_PROP_MOUNTPOINT: |
702 { 703 namecheck_err_t why; 704 |
|
903 if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 904 strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 905 break; 906 | 705 if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 || 706 strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0) 707 break; 708 |
907 if (strval[0] != '/') { 908 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 909 "'%s' must be an absolute path, " 910 "'none', or 'legacy'"), propname); | 709 if (mountpoint_namecheck(strval, &why)) { 710 switch (why) { 711 case NAME_ERR_LEADING_SLASH: 712 zfs_error_aux(hdl, 713 dgettext(TEXT_DOMAIN, 714 "'%s' must be an absolute path, " 715 "'none', or 'legacy'"), propname); 716 break; 717 case NAME_ERR_TOOLONG: 718 zfs_error_aux(hdl, 719 dgettext(TEXT_DOMAIN, 720 "component of '%s' is too long"), 721 propname); 722 break; 723 } |
911 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 912 goto error; 913 } | 724 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 725 goto error; 726 } |
727 } 728 |
|
914 /*FALLTHRU*/ 915 | 729 /*FALLTHRU*/ 730 |
731 case ZFS_PROP_SHARESMB: |
|
916 case ZFS_PROP_SHARENFS: 917 /* | 732 case ZFS_PROP_SHARENFS: 733 /* |
918 * For the mountpoint and sharenfs properties, check if 919 * it can be set in a global/non-global zone based on | 734 * For the mountpoint and sharenfs or sharesmb 735 * properties, check if it can be set in a 736 * global/non-global zone based on |
920 * the zoned property value: 921 * 922 * global zone non-global zone 923 * -------------------------------------------------- 924 * zoned=on mountpoint (no) mountpoint (yes) 925 * sharenfs (no) sharenfs (no) | 737 * the zoned property value: 738 * 739 * global zone non-global zone 740 * -------------------------------------------------- 741 * zoned=on mountpoint (no) mountpoint (yes) 742 * sharenfs (no) sharenfs (no) |
743 * sharesmb (no) sharesmb (no) |
|
926 * 927 * zoned=off mountpoint (yes) N/A 928 * sharenfs (yes) | 744 * 745 * zoned=off mountpoint (yes) N/A 746 * sharenfs (yes) |
747 * sharesmb (yes) |
|
929 */ 930 if (zoned) { 931 if (getzoneid() == GLOBAL_ZONEID) { 932 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 933 "'%s' cannot be set on " 934 "dataset in a non-global zone"), 935 propname); 936 (void) zfs_error(hdl, EZFS_ZONED, 937 errbuf); 938 goto error; | 748 */ 749 if (zoned) { 750 if (getzoneid() == GLOBAL_ZONEID) { 751 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 752 "'%s' cannot be set on " 753 "dataset in a non-global zone"), 754 propname); 755 (void) zfs_error(hdl, EZFS_ZONED, 756 errbuf); 757 goto error; |
939 } else if (prop == ZFS_PROP_SHARENFS) { | 758 } else if (prop == ZFS_PROP_SHARENFS || 759 prop == ZFS_PROP_SHARESMB) { |
940 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 941 "'%s' cannot be set in " 942 "a non-global zone"), propname); 943 (void) zfs_error(hdl, EZFS_ZONED, 944 errbuf); 945 goto error; 946 } 947 } else if (getzoneid() != GLOBAL_ZONEID) { 948 /* 949 * If zoned property is 'off', this must be in 950 * a globle zone. If not, something is wrong. 951 */ 952 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 953 "'%s' cannot be set while dataset " 954 "'zoned' property is set"), propname); 955 (void) zfs_error(hdl, EZFS_ZONED, errbuf); 956 goto error; 957 } 958 | 760 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 761 "'%s' cannot be set in " 762 "a non-global zone"), propname); 763 (void) zfs_error(hdl, EZFS_ZONED, 764 errbuf); 765 goto error; 766 } 767 } else if (getzoneid() != GLOBAL_ZONEID) { 768 /* 769 * If zoned property is 'off', this must be in 770 * a globle zone. If not, something is wrong. 771 */ 772 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 773 "'%s' cannot be set while dataset " 774 "'zoned' property is set"), propname); 775 (void) zfs_error(hdl, EZFS_ZONED, errbuf); 776 goto error; 777 } 778 |
959 break; 960 961 case ZFS_PROP_BOOTFS: | |
962 /* | 779 /* |
963 * bootfs property value has to be a dataset name and 964 * the dataset has to be in the same pool as it sets to. | 780 * At this point, it is legitimate to set the 781 * property. Now we want to make sure that the 782 * property value is valid if it is sharenfs. |
965 */ | 783 */ |
966 if (strval[0] != '\0' && (!zfs_name_valid(strval, 967 ZFS_TYPE_FILESYSTEM) || !bootfs_poolname_valid( 968 pool_name, strval))) { | 784 if ((prop == ZFS_PROP_SHARENFS || 785 prop == ZFS_PROP_SHARESMB) && 786 strcmp(strval, "on") != 0 && 787 strcmp(strval, "off") != 0) { 788 zfs_share_proto_t proto; |
969 | 789 |
970 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' " 971 "is an invalid name"), strval); 972 (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); 973 goto error; | 790 if (prop == ZFS_PROP_SHARESMB) 791 proto = PROTO_SMB; 792 else 793 proto = PROTO_NFS; 794 795 /* 796 * Must be an valid sharing protocol 797 * option string so init the libshare 798 * in order to enable the parser and 799 * then parse the options. We use the 800 * control API since we don't care about 801 * the current configuration and don't 802 * want the overhead of loading it 803 * until we actually do something. 804 */ 805 806 if (zfs_init_libshare(hdl, 807 SA_INIT_CONTROL_API) != SA_OK) { 808 /* 809 * An error occurred so we can't do 810 * anything 811 */ 812 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 813 "'%s' cannot be set: problem " 814 "in share initialization"), 815 propname); 816 (void) zfs_error(hdl, EZFS_BADPROP, 817 errbuf); 818 goto error; 819 } 820 821 if (zfs_parse_options(strval, proto) != SA_OK) { 822 /* 823 * There was an error in parsing so 824 * deal with it by issuing an error 825 * message and leaving after 826 * uninitializing the the libshare 827 * interface. 828 */ 829 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 830 "'%s' cannot be set to invalid " 831 "options"), propname); 832 (void) zfs_error(hdl, EZFS_BADPROP, 833 errbuf); 834 zfs_uninit_libshare(hdl); 835 goto error; 836 } 837 zfs_uninit_libshare(hdl); |
974 } | 838 } |
839 |
|
975 break; | 840 break; |
841 case ZFS_PROP_UTF8ONLY: 842 chosen_utf = (int)intval; 843 break; 844 case ZFS_PROP_NORMALIZE: 845 chosen_normal = (int)intval; 846 break; |
|
976 } 977 978 /* 979 * For changes to existing volumes, we have some additional 980 * checks to enforce. 981 */ 982 if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 983 uint64_t volsize = zfs_prop_get_int(zhp, 984 ZFS_PROP_VOLSIZE); 985 uint64_t blocksize = zfs_prop_get_int(zhp, 986 ZFS_PROP_VOLBLOCKSIZE); 987 char buf[64]; 988 989 switch (prop) { 990 case ZFS_PROP_RESERVATION: | 847 } 848 849 /* 850 * For changes to existing volumes, we have some additional 851 * checks to enforce. 852 */ 853 if (type == ZFS_TYPE_VOLUME && zhp != NULL) { 854 uint64_t volsize = zfs_prop_get_int(zhp, 855 ZFS_PROP_VOLSIZE); 856 uint64_t blocksize = zfs_prop_get_int(zhp, 857 ZFS_PROP_VOLBLOCKSIZE); 858 char buf[64]; 859 860 switch (prop) { 861 case ZFS_PROP_RESERVATION: |
862 case ZFS_PROP_REFRESERVATION: |
|
991 if (intval > volsize) { 992 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 993 "'%s' is greater than current " 994 "volume size"), propname); 995 (void) zfs_error(hdl, EZFS_BADPROP, 996 errbuf); 997 goto error; 998 } --- 21 unchanged lines hidden (view full) --- 1020 goto error; 1021 } 1022 break; 1023 } 1024 } 1025 } 1026 1027 /* | 863 if (intval > volsize) { 864 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 865 "'%s' is greater than current " 866 "volume size"), propname); 867 (void) zfs_error(hdl, EZFS_BADPROP, 868 errbuf); 869 goto error; 870 } --- 21 unchanged lines hidden (view full) --- 892 goto error; 893 } 894 break; 895 } 896 } 897 } 898 899 /* |
900 * If normalization was chosen, but no UTF8 choice was made, 901 * enforce rejection of non-UTF8 names. 902 * 903 * If normalization was chosen, but rejecting non-UTF8 names 904 * was explicitly not chosen, it is an error. 905 */ 906 if (chosen_normal > 0 && chosen_utf < 0) { 907 if (nvlist_add_uint64(ret, 908 zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) { 909 (void) no_memory(hdl); 910 goto error; 911 } 912 } else if (chosen_normal > 0 && chosen_utf == 0) { 913 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 914 "'%s' must be set 'on' if normalization chosen"), 915 zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); 916 (void) zfs_error(hdl, EZFS_BADPROP, errbuf); 917 goto error; 918 } 919 920 /* |
|
1028 * If this is an existing volume, and someone is setting the volsize, 1029 * make sure that it matches the reservation, or add it if necessary. 1030 */ 1031 if (zhp != NULL && type == ZFS_TYPE_VOLUME && 1032 nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1033 &intval) == 0) { 1034 uint64_t old_volsize = zfs_prop_get_int(zhp, 1035 ZFS_PROP_VOLSIZE); | 921 * If this is an existing volume, and someone is setting the volsize, 922 * make sure that it matches the reservation, or add it if necessary. 923 */ 924 if (zhp != NULL && type == ZFS_TYPE_VOLUME && 925 nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE), 926 &intval) == 0) { 927 uint64_t old_volsize = zfs_prop_get_int(zhp, 928 ZFS_PROP_VOLSIZE); |
1036 uint64_t old_reservation = zfs_prop_get_int(zhp, 1037 ZFS_PROP_RESERVATION); | 929 uint64_t old_reservation; |
1038 uint64_t new_reservation; | 930 uint64_t new_reservation; |
931 zfs_prop_t resv_prop; |
|
1039 | 932 |
933 if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 934 goto error; 935 old_reservation = zfs_prop_get_int(zhp, resv_prop); 936 |
|
1040 if (old_volsize == old_reservation && | 937 if (old_volsize == old_reservation && |
1041 nvlist_lookup_uint64(ret, 1042 zfs_prop_to_name(ZFS_PROP_RESERVATION), | 938 nvlist_lookup_uint64(ret, zfs_prop_to_name(resv_prop), |
1043 &new_reservation) != 0) { 1044 if (nvlist_add_uint64(ret, | 939 &new_reservation) != 0) { 940 if (nvlist_add_uint64(ret, |
1045 zfs_prop_to_name(ZFS_PROP_RESERVATION), 1046 intval) != 0) { | 941 zfs_prop_to_name(resv_prop), intval) != 0) { |
1047 (void) no_memory(hdl); 1048 goto error; 1049 } 1050 } 1051 } | 942 (void) no_memory(hdl); 943 goto error; 944 } 945 } 946 } |
1052 | |
1053 return (ret); 1054 1055error: 1056 nvlist_free(ret); 1057 return (NULL); 1058} 1059 | 947 return (ret); 948 949error: 950 nvlist_free(ret); 951 return (NULL); 952} 953 |
954static int 955zfs_get_perm_who(const char *who, zfs_deleg_who_type_t *who_type, 956 uint64_t *ret_who) 957{ 958 struct passwd *pwd; 959 struct group *grp; 960 uid_t id; 961 962 if (*who_type == ZFS_DELEG_EVERYONE || *who_type == ZFS_DELEG_CREATE || 963 *who_type == ZFS_DELEG_NAMED_SET) { 964 *ret_who = -1; 965 return (0); 966 } 967 if (who == NULL && !(*who_type == ZFS_DELEG_EVERYONE)) 968 return (EZFS_BADWHO); 969 970 if (*who_type == ZFS_DELEG_WHO_UNKNOWN && 971 strcmp(who, "everyone") == 0) { 972 *ret_who = -1; 973 *who_type = ZFS_DELEG_EVERYONE; 974 return (0); 975 } 976 977 pwd = getpwnam(who); 978 grp = getgrnam(who); 979 980 if ((*who_type == ZFS_DELEG_USER) && pwd) { 981 *ret_who = pwd->pw_uid; 982 } else if ((*who_type == ZFS_DELEG_GROUP) && grp) { 983 *ret_who = grp->gr_gid; 984 } else if (pwd) { 985 *ret_who = pwd->pw_uid; 986 *who_type = ZFS_DELEG_USER; 987 } else if (grp) { 988 *ret_who = grp->gr_gid; 989 *who_type = ZFS_DELEG_GROUP; 990 } else { 991 char *end; 992 993 id = strtol(who, &end, 10); 994 if (errno != 0 || *end != '\0') { 995 return (EZFS_BADWHO); 996 } else { 997 *ret_who = id; 998 if (*who_type == ZFS_DELEG_WHO_UNKNOWN) 999 *who_type = ZFS_DELEG_USER; 1000 } 1001 } 1002 1003 return (0); 1004} 1005 1006static void 1007zfs_perms_add_to_nvlist(nvlist_t *who_nvp, char *name, nvlist_t *perms_nvp) 1008{ 1009 if (perms_nvp != NULL) { 1010 verify(nvlist_add_nvlist(who_nvp, 1011 name, perms_nvp) == 0); 1012 } else { 1013 verify(nvlist_add_boolean(who_nvp, name) == 0); 1014 } 1015} 1016 1017static void 1018helper(zfs_deleg_who_type_t who_type, uint64_t whoid, char *whostr, 1019 zfs_deleg_inherit_t inherit, nvlist_t *who_nvp, nvlist_t *perms_nvp, 1020 nvlist_t *sets_nvp) 1021{ 1022 boolean_t do_perms, do_sets; 1023 char name[ZFS_MAX_DELEG_NAME]; 1024 1025 do_perms = (nvlist_next_nvpair(perms_nvp, NULL) != NULL); 1026 do_sets = (nvlist_next_nvpair(sets_nvp, NULL) != NULL); 1027 1028 if (!do_perms && !do_sets) 1029 do_perms = do_sets = B_TRUE; 1030 1031 if (do_perms) { 1032 zfs_deleg_whokey(name, who_type, inherit, 1033 (who_type == ZFS_DELEG_NAMED_SET) ? 1034 whostr : (void *)&whoid); 1035 zfs_perms_add_to_nvlist(who_nvp, name, perms_nvp); 1036 } 1037 if (do_sets) { 1038 zfs_deleg_whokey(name, toupper(who_type), inherit, 1039 (who_type == ZFS_DELEG_NAMED_SET) ? 1040 whostr : (void *)&whoid); 1041 zfs_perms_add_to_nvlist(who_nvp, name, sets_nvp); 1042 } 1043} 1044 1045static void 1046zfs_perms_add_who_nvlist(nvlist_t *who_nvp, uint64_t whoid, void *whostr, 1047 nvlist_t *perms_nvp, nvlist_t *sets_nvp, 1048 zfs_deleg_who_type_t who_type, zfs_deleg_inherit_t inherit) 1049{ 1050 if (who_type == ZFS_DELEG_NAMED_SET || who_type == ZFS_DELEG_CREATE) { 1051 helper(who_type, whoid, whostr, 0, 1052 who_nvp, perms_nvp, sets_nvp); 1053 } else { 1054 if (inherit & ZFS_DELEG_PERM_LOCAL) { 1055 helper(who_type, whoid, whostr, ZFS_DELEG_LOCAL, 1056 who_nvp, perms_nvp, sets_nvp); 1057 } 1058 if (inherit & ZFS_DELEG_PERM_DESCENDENT) { 1059 helper(who_type, whoid, whostr, ZFS_DELEG_DESCENDENT, 1060 who_nvp, perms_nvp, sets_nvp); 1061 } 1062 } 1063} 1064 |
|
1060/* | 1065/* |
1066 * Construct nvlist to pass down to kernel for setting/removing permissions. 1067 * 1068 * The nvlist is constructed as a series of nvpairs with an optional embedded 1069 * nvlist of permissions to remove or set. The topmost nvpairs are the actual 1070 * base attribute named stored in the dsl. 1071 * Arguments: 1072 * 1073 * whostr: is a comma separated list of users, groups, or a single set name. 1074 * whostr may be null for everyone or create perms. 1075 * who_type: is the type of entry in whostr. Typically this will be 1076 * ZFS_DELEG_WHO_UNKNOWN. 1077 * perms: common separated list of permissions. May be null if user 1078 * is requested to remove permissions by who. 1079 * inherit: Specifies the inheritance of the permissions. Will be either 1080 * ZFS_DELEG_PERM_LOCAL and/or ZFS_DELEG_PERM_DESCENDENT. 1081 * nvp The constructed nvlist to pass to zfs_perm_set(). 1082 * The output nvp will look something like this. 1083 * ul$1234 -> {create ; destroy } 1084 * Ul$1234 -> { @myset } 1085 * s-$@myset - { snapshot; checksum; compression } 1086 */ 1087int 1088zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms, 1089 zfs_deleg_who_type_t who_type, zfs_deleg_inherit_t inherit, nvlist_t **nvp) 1090{ 1091 nvlist_t *who_nvp; 1092 nvlist_t *perms_nvp = NULL; 1093 nvlist_t *sets_nvp = NULL; 1094 char errbuf[1024]; 1095 char *who_tok, *perm; 1096 int error; 1097 1098 *nvp = NULL; 1099 1100 if (perms) { 1101 if ((error = nvlist_alloc(&perms_nvp, 1102 NV_UNIQUE_NAME, 0)) != 0) { 1103 return (1); 1104 } 1105 if ((error = nvlist_alloc(&sets_nvp, 1106 NV_UNIQUE_NAME, 0)) != 0) { 1107 nvlist_free(perms_nvp); 1108 return (1); 1109 } 1110 } 1111 1112 if ((error = nvlist_alloc(&who_nvp, NV_UNIQUE_NAME, 0)) != 0) { 1113 if (perms_nvp) 1114 nvlist_free(perms_nvp); 1115 if (sets_nvp) 1116 nvlist_free(sets_nvp); 1117 return (1); 1118 } 1119 1120 if (who_type == ZFS_DELEG_NAMED_SET) { 1121 namecheck_err_t why; 1122 char what; 1123 1124 if ((error = permset_namecheck(whostr, &why, &what)) != 0) { 1125 nvlist_free(who_nvp); 1126 if (perms_nvp) 1127 nvlist_free(perms_nvp); 1128 if (sets_nvp) 1129 nvlist_free(sets_nvp); 1130 1131 switch (why) { 1132 case NAME_ERR_NO_AT: 1133 zfs_error_aux(zhp->zfs_hdl, 1134 dgettext(TEXT_DOMAIN, 1135 "set definition must begin with an '@' " 1136 "character")); 1137 } 1138 return (zfs_error(zhp->zfs_hdl, 1139 EZFS_BADPERMSET, whostr)); 1140 } 1141 } 1142 1143 /* 1144 * Build up nvlist(s) of permissions. Two nvlists are maintained. 1145 * The first nvlist perms_nvp will have normal permissions and the 1146 * other sets_nvp will have only permssion set names in it. 1147 */ 1148 for (perm = strtok(perms, ","); perm; perm = strtok(NULL, ",")) { 1149 const char *perm_canonical = zfs_deleg_canonicalize_perm(perm); 1150 1151 if (perm_canonical) { 1152 verify(nvlist_add_boolean(perms_nvp, 1153 perm_canonical) == 0); 1154 } else if (perm[0] == '@') { 1155 verify(nvlist_add_boolean(sets_nvp, perm) == 0); 1156 } else { 1157 nvlist_free(who_nvp); 1158 nvlist_free(perms_nvp); 1159 nvlist_free(sets_nvp); 1160 return (zfs_error(zhp->zfs_hdl, EZFS_BADPERM, perm)); 1161 } 1162 } 1163 1164 if (whostr && who_type != ZFS_DELEG_CREATE) { 1165 who_tok = strtok(whostr, ","); 1166 if (who_tok == NULL) { 1167 nvlist_free(who_nvp); 1168 if (perms_nvp) 1169 nvlist_free(perms_nvp); 1170 if (sets_nvp) 1171 nvlist_free(sets_nvp); 1172 (void) snprintf(errbuf, sizeof (errbuf), 1173 dgettext(TEXT_DOMAIN, "Who string is NULL"), 1174 whostr); 1175 return (zfs_error(zhp->zfs_hdl, EZFS_BADWHO, errbuf)); 1176 } 1177 } 1178 1179 /* 1180 * Now create the nvlist(s) 1181 */ 1182 do { 1183 uint64_t who_id; 1184 1185 error = zfs_get_perm_who(who_tok, &who_type, 1186 &who_id); 1187 if (error) { 1188 nvlist_free(who_nvp); 1189 if (perms_nvp) 1190 nvlist_free(perms_nvp); 1191 if (sets_nvp) 1192 nvlist_free(sets_nvp); 1193 (void) snprintf(errbuf, sizeof (errbuf), 1194 dgettext(TEXT_DOMAIN, 1195 "Unable to determine uid/gid for " 1196 "%s "), who_tok); 1197 return (zfs_error(zhp->zfs_hdl, EZFS_BADWHO, errbuf)); 1198 } 1199 1200 /* 1201 * add entries for both local and descendent when required 1202 */ 1203 zfs_perms_add_who_nvlist(who_nvp, who_id, who_tok, 1204 perms_nvp, sets_nvp, who_type, inherit); 1205 1206 } while (who_tok = strtok(NULL, ",")); 1207 *nvp = who_nvp; 1208 return (0); 1209} 1210 1211static int 1212zfs_perm_set_common(zfs_handle_t *zhp, nvlist_t *nvp, boolean_t unset) 1213{ 1214 zfs_cmd_t zc = { 0 }; 1215 int error; 1216 char errbuf[1024]; 1217 1218 (void) snprintf(errbuf, sizeof (errbuf), 1219 dgettext(TEXT_DOMAIN, "Cannot update 'allows' for '%s'"), 1220 zhp->zfs_name); 1221 1222 if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, nvp)) 1223 return (-1); 1224 1225 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1226 zc.zc_perm_action = unset; 1227 1228 error = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SET_FSACL, &zc); 1229 if (error && errno == ENOTSUP) { 1230 (void) snprintf(errbuf, sizeof (errbuf), 1231 gettext("Pool must be upgraded to use 'allow/unallow'")); 1232 zcmd_free_nvlists(&zc); 1233 return (zfs_error(zhp->zfs_hdl, EZFS_BADVERSION, errbuf)); 1234 } else if (error) { 1235 return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf)); 1236 } 1237 zcmd_free_nvlists(&zc); 1238 1239 return (error); 1240} 1241 1242int 1243zfs_perm_set(zfs_handle_t *zhp, nvlist_t *nvp) 1244{ 1245 return (zfs_perm_set_common(zhp, nvp, B_FALSE)); 1246} 1247 1248int 1249zfs_perm_remove(zfs_handle_t *zhp, nvlist_t *perms) 1250{ 1251 return (zfs_perm_set_common(zhp, perms, B_TRUE)); 1252} 1253 1254static int 1255perm_compare(const void *arg1, const void *arg2) 1256{ 1257 const zfs_perm_node_t *node1 = arg1; 1258 const zfs_perm_node_t *node2 = arg2; 1259 int ret; 1260 1261 ret = strcmp(node1->z_pname, node2->z_pname); 1262 1263 if (ret > 0) 1264 return (1); 1265 if (ret < 0) 1266 return (-1); 1267 else 1268 return (0); 1269} 1270 1271static void 1272zfs_destroy_perm_tree(avl_tree_t *tree) 1273{ 1274 zfs_perm_node_t *permnode; 1275 void *cookie = NULL; 1276 1277 while ((permnode = avl_destroy_nodes(tree, &cookie)) != NULL) 1278 free(permnode); 1279 avl_destroy(tree); 1280} 1281 1282static void 1283zfs_destroy_tree(avl_tree_t *tree) 1284{ 1285 zfs_allow_node_t *allownode; 1286 void *cookie = NULL; 1287 1288 while ((allownode = avl_destroy_nodes(tree, &cookie)) != NULL) { 1289 zfs_destroy_perm_tree(&allownode->z_localdescend); 1290 zfs_destroy_perm_tree(&allownode->z_local); 1291 zfs_destroy_perm_tree(&allownode->z_descend); 1292 free(allownode); 1293 } 1294 avl_destroy(tree); 1295} 1296 1297void 1298zfs_free_allows(zfs_allow_t *allow) 1299{ 1300 zfs_allow_t *allownext; 1301 zfs_allow_t *freeallow; 1302 1303 allownext = allow; 1304 while (allownext) { 1305 zfs_destroy_tree(&allownext->z_sets); 1306 zfs_destroy_tree(&allownext->z_crperms); 1307 zfs_destroy_tree(&allownext->z_user); 1308 zfs_destroy_tree(&allownext->z_group); 1309 zfs_destroy_tree(&allownext->z_everyone); 1310 freeallow = allownext; 1311 allownext = allownext->z_next; 1312 free(freeallow); 1313 } 1314} 1315 1316static zfs_allow_t * 1317zfs_alloc_perm_tree(zfs_handle_t *zhp, zfs_allow_t *prev, char *setpoint) 1318{ 1319 zfs_allow_t *ptree; 1320 1321 if ((ptree = zfs_alloc(zhp->zfs_hdl, 1322 sizeof (zfs_allow_t))) == NULL) { 1323 return (NULL); 1324 } 1325 1326 (void) strlcpy(ptree->z_setpoint, setpoint, sizeof (ptree->z_setpoint)); 1327 avl_create(&ptree->z_sets, 1328 perm_compare, sizeof (zfs_allow_node_t), 1329 offsetof(zfs_allow_node_t, z_node)); 1330 avl_create(&ptree->z_crperms, 1331 perm_compare, sizeof (zfs_allow_node_t), 1332 offsetof(zfs_allow_node_t, z_node)); 1333 avl_create(&ptree->z_user, 1334 perm_compare, sizeof (zfs_allow_node_t), 1335 offsetof(zfs_allow_node_t, z_node)); 1336 avl_create(&ptree->z_group, 1337 perm_compare, sizeof (zfs_allow_node_t), 1338 offsetof(zfs_allow_node_t, z_node)); 1339 avl_create(&ptree->z_everyone, 1340 perm_compare, sizeof (zfs_allow_node_t), 1341 offsetof(zfs_allow_node_t, z_node)); 1342 1343 if (prev) 1344 prev->z_next = ptree; 1345 ptree->z_next = NULL; 1346 return (ptree); 1347} 1348 1349/* 1350 * Add permissions to the appropriate AVL permission tree. 1351 * The appropriate tree may not be the requested tree. 1352 * For example if ld indicates a local permission, but 1353 * same permission also exists as a descendent permission 1354 * then the permission will be removed from the descendent 1355 * tree and add the the local+descendent tree. 1356 */ 1357static int 1358zfs_coalesce_perm(zfs_handle_t *zhp, zfs_allow_node_t *allownode, 1359 char *perm, char ld) 1360{ 1361 zfs_perm_node_t pnode, *permnode, *permnode2; 1362 zfs_perm_node_t *newnode; 1363 avl_index_t where, where2; 1364 avl_tree_t *tree, *altree; 1365 1366 (void) strlcpy(pnode.z_pname, perm, sizeof (pnode.z_pname)); 1367 1368 if (ld == ZFS_DELEG_NA) { 1369 tree = &allownode->z_localdescend; 1370 altree = &allownode->z_descend; 1371 } else if (ld == ZFS_DELEG_LOCAL) { 1372 tree = &allownode->z_local; 1373 altree = &allownode->z_descend; 1374 } else { 1375 tree = &allownode->z_descend; 1376 altree = &allownode->z_local; 1377 } 1378 permnode = avl_find(tree, &pnode, &where); 1379 permnode2 = avl_find(altree, &pnode, &where2); 1380 1381 if (permnode2) { 1382 avl_remove(altree, permnode2); 1383 free(permnode2); 1384 if (permnode == NULL) { 1385 tree = &allownode->z_localdescend; 1386 } 1387 } 1388 1389 /* 1390 * Now insert new permission in either requested location 1391 * local/descendent or into ld when perm will exist in both. 1392 */ 1393 if (permnode == NULL) { 1394 if ((newnode = zfs_alloc(zhp->zfs_hdl, 1395 sizeof (zfs_perm_node_t))) == NULL) { 1396 return (-1); 1397 } 1398 *newnode = pnode; 1399 avl_add(tree, newnode); 1400 } 1401 return (0); 1402} 1403 1404/* 1405 * Uggh, this is going to be a bit complicated. 1406 * we have an nvlist coming out of the kernel that 1407 * will indicate where the permission is set and then 1408 * it will contain allow of the various "who's", and what 1409 * their permissions are. To further complicate this 1410 * we will then have to coalesce the local,descendent 1411 * and local+descendent permissions where appropriate. 1412 * The kernel only knows about a permission as being local 1413 * or descendent, but not both. 1414 * 1415 * In order to make this easier for zfs_main to deal with 1416 * a series of AVL trees will be used to maintain 1417 * all of this, primarily for sorting purposes as well 1418 * as the ability to quickly locate a specific entry. 1419 * 1420 * What we end up with are tree's for sets, create perms, 1421 * user, groups and everyone. With each of those trees 1422 * we have subtrees for local, descendent and local+descendent 1423 * permissions. 1424 */ 1425int 1426zfs_perm_get(zfs_handle_t *zhp, zfs_allow_t **zfs_perms) 1427{ 1428 zfs_cmd_t zc = { 0 }; 1429 int error; 1430 nvlist_t *nvlist; 1431 nvlist_t *permnv, *sourcenv; 1432 nvpair_t *who_pair, *source_pair; 1433 nvpair_t *perm_pair; 1434 char errbuf[1024]; 1435 zfs_allow_t *zallowp, *newallowp; 1436 char ld; 1437 char *nvpname; 1438 uid_t uid; 1439 gid_t gid; 1440 avl_tree_t *tree; 1441 avl_index_t where; 1442 1443 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1444 1445 if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 1446 return (-1); 1447 1448 while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { 1449 if (errno == ENOMEM) { 1450 if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, &zc) != 0) { 1451 zcmd_free_nvlists(&zc); 1452 return (-1); 1453 } 1454 } else if (errno == ENOTSUP) { 1455 zcmd_free_nvlists(&zc); 1456 (void) snprintf(errbuf, sizeof (errbuf), 1457 gettext("Pool must be upgraded to use 'allow'")); 1458 return (zfs_error(zhp->zfs_hdl, 1459 EZFS_BADVERSION, errbuf)); 1460 } else { 1461 zcmd_free_nvlists(&zc); 1462 return (-1); 1463 } 1464 } 1465 1466 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &nvlist) != 0) { 1467 zcmd_free_nvlists(&zc); 1468 return (-1); 1469 } 1470 1471 zcmd_free_nvlists(&zc); 1472 1473 source_pair = nvlist_next_nvpair(nvlist, NULL); 1474 1475 if (source_pair == NULL) { 1476 *zfs_perms = NULL; 1477 return (0); 1478 } 1479 1480 *zfs_perms = zfs_alloc_perm_tree(zhp, NULL, nvpair_name(source_pair)); 1481 if (*zfs_perms == NULL) { 1482 return (0); 1483 } 1484 1485 zallowp = *zfs_perms; 1486 1487 for (;;) { 1488 struct passwd *pwd; 1489 struct group *grp; 1490 zfs_allow_node_t *allownode; 1491 zfs_allow_node_t findallownode; 1492 zfs_allow_node_t *newallownode; 1493 1494 (void) strlcpy(zallowp->z_setpoint, 1495 nvpair_name(source_pair), 1496 sizeof (zallowp->z_setpoint)); 1497 1498 if ((error = nvpair_value_nvlist(source_pair, &sourcenv)) != 0) 1499 goto abort; 1500 1501 /* 1502 * Make sure nvlist is composed correctly 1503 */ 1504 if (zfs_deleg_verify_nvlist(sourcenv)) { 1505 goto abort; 1506 } 1507 1508 who_pair = nvlist_next_nvpair(sourcenv, NULL); 1509 if (who_pair == NULL) { 1510 goto abort; 1511 } 1512 1513 do { 1514 error = nvpair_value_nvlist(who_pair, &permnv); 1515 if (error) { 1516 goto abort; 1517 } 1518 1519 /* 1520 * First build up the key to use 1521 * for looking up in the various 1522 * who trees. 1523 */ 1524 ld = nvpair_name(who_pair)[1]; 1525 nvpname = nvpair_name(who_pair); 1526 switch (nvpair_name(who_pair)[0]) { 1527 case ZFS_DELEG_USER: 1528 case ZFS_DELEG_USER_SETS: 1529 tree = &zallowp->z_user; 1530 uid = atol(&nvpname[3]); 1531 pwd = getpwuid(uid); 1532 (void) snprintf(findallownode.z_key, 1533 sizeof (findallownode.z_key), "user %s", 1534 (pwd) ? pwd->pw_name : 1535 &nvpair_name(who_pair)[3]); 1536 break; 1537 case ZFS_DELEG_GROUP: 1538 case ZFS_DELEG_GROUP_SETS: 1539 tree = &zallowp->z_group; 1540 gid = atol(&nvpname[3]); 1541 grp = getgrgid(gid); 1542 (void) snprintf(findallownode.z_key, 1543 sizeof (findallownode.z_key), "group %s", 1544 (grp) ? grp->gr_name : 1545 &nvpair_name(who_pair)[3]); 1546 break; 1547 case ZFS_DELEG_CREATE: 1548 case ZFS_DELEG_CREATE_SETS: 1549 tree = &zallowp->z_crperms; 1550 (void) strlcpy(findallownode.z_key, "", 1551 sizeof (findallownode.z_key)); 1552 break; 1553 case ZFS_DELEG_EVERYONE: 1554 case ZFS_DELEG_EVERYONE_SETS: 1555 (void) snprintf(findallownode.z_key, 1556 sizeof (findallownode.z_key), "everyone"); 1557 tree = &zallowp->z_everyone; 1558 break; 1559 case ZFS_DELEG_NAMED_SET: 1560 case ZFS_DELEG_NAMED_SET_SETS: 1561 (void) snprintf(findallownode.z_key, 1562 sizeof (findallownode.z_key), "%s", 1563 &nvpair_name(who_pair)[3]); 1564 tree = &zallowp->z_sets; 1565 break; 1566 } 1567 1568 /* 1569 * Place who in tree 1570 */ 1571 allownode = avl_find(tree, &findallownode, &where); 1572 if (allownode == NULL) { 1573 if ((newallownode = zfs_alloc(zhp->zfs_hdl, 1574 sizeof (zfs_allow_node_t))) == NULL) { 1575 goto abort; 1576 } 1577 avl_create(&newallownode->z_localdescend, 1578 perm_compare, 1579 sizeof (zfs_perm_node_t), 1580 offsetof(zfs_perm_node_t, z_node)); 1581 avl_create(&newallownode->z_local, 1582 perm_compare, 1583 sizeof (zfs_perm_node_t), 1584 offsetof(zfs_perm_node_t, z_node)); 1585 avl_create(&newallownode->z_descend, 1586 perm_compare, 1587 sizeof (zfs_perm_node_t), 1588 offsetof(zfs_perm_node_t, z_node)); 1589 (void) strlcpy(newallownode->z_key, 1590 findallownode.z_key, 1591 sizeof (findallownode.z_key)); 1592 avl_insert(tree, newallownode, where); 1593 allownode = newallownode; 1594 } 1595 1596 /* 1597 * Now iterate over the permissions and 1598 * place them in the appropriate local, 1599 * descendent or local+descendent tree. 1600 * 1601 * The permissions are added to the tree 1602 * via zfs_coalesce_perm(). 1603 */ 1604 perm_pair = nvlist_next_nvpair(permnv, NULL); 1605 if (perm_pair == NULL) 1606 goto abort; 1607 do { 1608 if (zfs_coalesce_perm(zhp, allownode, 1609 nvpair_name(perm_pair), ld) != 0) 1610 goto abort; 1611 } while (perm_pair = nvlist_next_nvpair(permnv, 1612 perm_pair)); 1613 } while (who_pair = nvlist_next_nvpair(sourcenv, who_pair)); 1614 1615 source_pair = nvlist_next_nvpair(nvlist, source_pair); 1616 if (source_pair == NULL) 1617 break; 1618 1619 /* 1620 * allocate another node from the link list of 1621 * zfs_allow_t structures 1622 */ 1623 newallowp = zfs_alloc_perm_tree(zhp, zallowp, 1624 nvpair_name(source_pair)); 1625 if (newallowp == NULL) { 1626 goto abort; 1627 } 1628 zallowp = newallowp; 1629 } 1630 nvlist_free(nvlist); 1631 return (0); 1632abort: 1633 zfs_free_allows(*zfs_perms); 1634 nvlist_free(nvlist); 1635 return (-1); 1636} 1637 1638static char * 1639zfs_deleg_perm_note(zfs_deleg_note_t note) 1640{ 1641 /* 1642 * Don't put newlines on end of lines 1643 */ 1644 switch (note) { 1645 case ZFS_DELEG_NOTE_CREATE: 1646 return (dgettext(TEXT_DOMAIN, 1647 "Must also have the 'mount' ability")); 1648 case ZFS_DELEG_NOTE_DESTROY: 1649 return (dgettext(TEXT_DOMAIN, 1650 "Must also have the 'mount' ability")); 1651 case ZFS_DELEG_NOTE_SNAPSHOT: 1652 return (dgettext(TEXT_DOMAIN, 1653 "Must also have the 'mount' ability")); 1654 case ZFS_DELEG_NOTE_ROLLBACK: 1655 return (dgettext(TEXT_DOMAIN, 1656 "Must also have the 'mount' ability")); 1657 case ZFS_DELEG_NOTE_CLONE: 1658 return (dgettext(TEXT_DOMAIN, "Must also have the 'create' " 1659 "ability and 'mount'\n" 1660 "\t\t\t\tability in the origin file system")); 1661 case ZFS_DELEG_NOTE_PROMOTE: 1662 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount'\n" 1663 "\t\t\t\tand 'promote' ability in the origin file system")); 1664 case ZFS_DELEG_NOTE_RENAME: 1665 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount' " 1666 "and 'create' \n\t\t\t\tability in the new parent")); 1667 case ZFS_DELEG_NOTE_RECEIVE: 1668 return (dgettext(TEXT_DOMAIN, "Must also have the 'mount'" 1669 " and 'create' ability")); 1670 case ZFS_DELEG_NOTE_USERPROP: 1671 return (dgettext(TEXT_DOMAIN, 1672 "Allows changing any user property")); 1673 case ZFS_DELEG_NOTE_ALLOW: 1674 return (dgettext(TEXT_DOMAIN, 1675 "Must also have the permission that is being\n" 1676 "\t\t\t\tallowed")); 1677 case ZFS_DELEG_NOTE_MOUNT: 1678 return (dgettext(TEXT_DOMAIN, 1679 "Allows mount/umount of ZFS datasets")); 1680 case ZFS_DELEG_NOTE_SHARE: 1681 return (dgettext(TEXT_DOMAIN, 1682 "Allows sharing file systems over NFS or SMB\n" 1683 "\t\t\t\tprotocols")); 1684 case ZFS_DELEG_NOTE_NONE: 1685 default: 1686 return (dgettext(TEXT_DOMAIN, "")); 1687 } 1688} 1689 1690typedef enum { 1691 ZFS_DELEG_SUBCOMMAND, 1692 ZFS_DELEG_PROP, 1693 ZFS_DELEG_OTHER 1694} zfs_deleg_perm_type_t; 1695 1696/* 1697 * is the permission a subcommand or other? 1698 */ 1699zfs_deleg_perm_type_t 1700zfs_deleg_perm_type(const char *perm) 1701{ 1702 if (strcmp(perm, "userprop") == 0) 1703 return (ZFS_DELEG_OTHER); 1704 else 1705 return (ZFS_DELEG_SUBCOMMAND); 1706} 1707 1708static char * 1709zfs_deleg_perm_type_str(zfs_deleg_perm_type_t type) 1710{ 1711 switch (type) { 1712 case ZFS_DELEG_SUBCOMMAND: 1713 return (dgettext(TEXT_DOMAIN, "subcommand")); 1714 case ZFS_DELEG_PROP: 1715 return (dgettext(TEXT_DOMAIN, "property")); 1716 case ZFS_DELEG_OTHER: 1717 return (dgettext(TEXT_DOMAIN, "other")); 1718 } 1719 return (""); 1720} 1721 1722/*ARGSUSED*/ 1723static int 1724zfs_deleg_prop_cb(int prop, void *cb) 1725{ 1726 if (zfs_prop_delegatable(prop)) 1727 (void) fprintf(stderr, "%-15s %-15s\n", zfs_prop_to_name(prop), 1728 zfs_deleg_perm_type_str(ZFS_DELEG_PROP)); 1729 1730 return (ZPROP_CONT); 1731} 1732 1733void 1734zfs_deleg_permissions(void) 1735{ 1736 int i; 1737 1738 (void) fprintf(stderr, "\n%-15s %-15s\t%s\n\n", "NAME", 1739 "TYPE", "NOTES"); 1740 1741 /* 1742 * First print out the subcommands 1743 */ 1744 for (i = 0; zfs_deleg_perm_tab[i].z_perm != NULL; i++) { 1745 (void) fprintf(stderr, "%-15s %-15s\t%s\n", 1746 zfs_deleg_perm_tab[i].z_perm, 1747 zfs_deleg_perm_type_str( 1748 zfs_deleg_perm_type(zfs_deleg_perm_tab[i].z_perm)), 1749 zfs_deleg_perm_note(zfs_deleg_perm_tab[i].z_note)); 1750 } 1751 1752 (void) zprop_iter(zfs_deleg_prop_cb, NULL, B_FALSE, B_TRUE, 1753 ZFS_TYPE_DATASET|ZFS_TYPE_VOLUME); 1754} 1755 1756/* |
|
1061 * Given a property name and value, set the property for the given dataset. 1062 */ 1063int 1064zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1065{ 1066 zfs_cmd_t zc = { 0 }; 1067 int ret = -1; 1068 prop_changelist_t *cl = NULL; 1069 char errbuf[1024]; 1070 libzfs_handle_t *hdl = zhp->zfs_hdl; 1071 nvlist_t *nvl = NULL, *realprops; 1072 zfs_prop_t prop; | 1757 * Given a property name and value, set the property for the given dataset. 1758 */ 1759int 1760zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) 1761{ 1762 zfs_cmd_t zc = { 0 }; 1763 int ret = -1; 1764 prop_changelist_t *cl = NULL; 1765 char errbuf[1024]; 1766 libzfs_handle_t *hdl = zhp->zfs_hdl; 1767 nvlist_t *nvl = NULL, *realprops; 1768 zfs_prop_t prop; |
1769 boolean_t do_prefix; 1770 uint64_t idx; |
|
1073 1074 (void) snprintf(errbuf, sizeof (errbuf), 1075 dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1076 zhp->zfs_name); 1077 1078 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1079 nvlist_add_string(nvl, propname, propval) != 0) { 1080 (void) no_memory(hdl); 1081 goto error; 1082 } 1083 | 1771 1772 (void) snprintf(errbuf, sizeof (errbuf), 1773 dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), 1774 zhp->zfs_name); 1775 1776 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 1777 nvlist_add_string(nvl, propname, propval) != 0) { 1778 (void) no_memory(hdl); 1779 goto error; 1780 } 1781 |
1084 if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, NULL, nvl, | 1782 if ((realprops = zfs_valid_proplist(hdl, zhp->zfs_type, nvl, |
1085 zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1086 goto error; | 1783 zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL) 1784 goto error; |
1785 |
|
1087 nvlist_free(nvl); 1088 nvl = realprops; 1089 1090 prop = zfs_name_to_prop(propname); 1091 1092 /* We don't support those properties on FreeBSD. */ 1093 switch (prop) { 1094 case ZFS_PROP_SHAREISCSI: 1095 case ZFS_PROP_DEVICES: 1096 case ZFS_PROP_ACLMODE: 1097 case ZFS_PROP_ACLINHERIT: 1098 case ZFS_PROP_ISCSIOPTIONS: 1099 (void) snprintf(errbuf, sizeof (errbuf), 1100 "property '%s' not supported on FreeBSD", propname); 1101 ret = zfs_error(hdl, EZFS_PERM, errbuf); 1102 goto error; 1103 } 1104 | 1786 nvlist_free(nvl); 1787 nvl = realprops; 1788 1789 prop = zfs_name_to_prop(propname); 1790 1791 /* We don't support those properties on FreeBSD. */ 1792 switch (prop) { 1793 case ZFS_PROP_SHAREISCSI: 1794 case ZFS_PROP_DEVICES: 1795 case ZFS_PROP_ACLMODE: 1796 case ZFS_PROP_ACLINHERIT: 1797 case ZFS_PROP_ISCSIOPTIONS: 1798 (void) snprintf(errbuf, sizeof (errbuf), 1799 "property '%s' not supported on FreeBSD", propname); 1800 ret = zfs_error(hdl, EZFS_PERM, errbuf); 1801 goto error; 1802 } 1803 |
1105 if ((cl = changelist_gather(zhp, prop, 0)) == NULL) | 1804 if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) |
1106 goto error; 1107 1108 if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1109 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1110 "child dataset with inherited mountpoint is used " 1111 "in a non-global zone")); 1112 ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1113 goto error; 1114 } 1115 | 1805 goto error; 1806 1807 if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1808 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1809 "child dataset with inherited mountpoint is used " 1810 "in a non-global zone")); 1811 ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1812 goto error; 1813 } 1814 |
1116 if ((ret = changelist_prefix(cl)) != 0) | 1815 /* 1816 * If the dataset's canmount property is being set to noauto, 1817 * then we want to prevent unmounting & remounting it. 1818 */ 1819 do_prefix = !((prop == ZFS_PROP_CANMOUNT) && 1820 (zprop_string_to_index(prop, propval, &idx, 1821 ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO)); 1822 1823 if (do_prefix && (ret = changelist_prefix(cl)) != 0) |
1117 goto error; 1118 1119 /* 1120 * Execute the corresponding ioctl() to set this property. 1121 */ 1122 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1123 | 1824 goto error; 1825 1826 /* 1827 * Execute the corresponding ioctl() to set this property. 1828 */ 1829 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1830 |
1124 if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0) | 1831 if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0) |
1125 goto error; 1126 | 1832 goto error; 1833 |
1127 ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc); 1128 | 1834 ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); |
1129 if (ret != 0) { 1130 switch (errno) { 1131 1132 case ENOSPC: 1133 /* 1134 * For quotas and reservations, ENOSPC indicates 1135 * something different; setting a quota or reservation 1136 * doesn't use any disk space. 1137 */ 1138 switch (prop) { 1139 case ZFS_PROP_QUOTA: | 1835 if (ret != 0) { 1836 switch (errno) { 1837 1838 case ENOSPC: 1839 /* 1840 * For quotas and reservations, ENOSPC indicates 1841 * something different; setting a quota or reservation 1842 * doesn't use any disk space. 1843 */ 1844 switch (prop) { 1845 case ZFS_PROP_QUOTA: |
1846 case ZFS_PROP_REFQUOTA: |
|
1140 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1141 "size is less than current used or " 1142 "reserved space")); 1143 (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1144 break; 1145 1146 case ZFS_PROP_RESERVATION: | 1847 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1848 "size is less than current used or " 1849 "reserved space")); 1850 (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1851 break; 1852 1853 case ZFS_PROP_RESERVATION: |
1854 case ZFS_PROP_REFRESERVATION: |
|
1147 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1148 "size is greater than available space")); 1149 (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1150 break; 1151 1152 default: 1153 (void) zfs_standard_error(hdl, errno, errbuf); 1154 break; --- 8 unchanged lines hidden (view full) --- 1163 break; 1164 1165 case EROFS: 1166 (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1167 break; 1168 1169 case ENOTSUP: 1170 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, | 1855 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1856 "size is greater than available space")); 1857 (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); 1858 break; 1859 1860 default: 1861 (void) zfs_standard_error(hdl, errno, errbuf); 1862 break; --- 8 unchanged lines hidden (view full) --- 1871 break; 1872 1873 case EROFS: 1874 (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); 1875 break; 1876 1877 case ENOTSUP: 1878 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, |
1171 "pool must be upgraded to allow gzip compression")); | 1879 "pool and or dataset must be upgraded to set this " 1880 "property or value")); |
1172 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1173 break; 1174 | 1881 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); 1882 break; 1883 |
1884 case ERANGE: 1885 if (prop == ZFS_PROP_COMPRESSION) { 1886 (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1887 "property setting is not allowed on " 1888 "bootable datasets")); 1889 (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); 1890 } else { 1891 (void) zfs_standard_error(hdl, errno, errbuf); 1892 } 1893 break; 1894 |
|
1175 case EOVERFLOW: 1176 /* 1177 * This platform can't address a volume this big. 1178 */ 1179#ifdef _ILP32 1180 if (prop == ZFS_PROP_VOLSIZE) { 1181 (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1182 break; 1183 } 1184#endif 1185 /* FALLTHROUGH */ 1186 default: 1187 (void) zfs_standard_error(hdl, errno, errbuf); 1188 } 1189 } else { | 1895 case EOVERFLOW: 1896 /* 1897 * This platform can't address a volume this big. 1898 */ 1899#ifdef _ILP32 1900 if (prop == ZFS_PROP_VOLSIZE) { 1901 (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); 1902 break; 1903 } 1904#endif 1905 /* FALLTHROUGH */ 1906 default: 1907 (void) zfs_standard_error(hdl, errno, errbuf); 1908 } 1909 } else { |
1910 if (do_prefix) 1911 ret = changelist_postfix(cl); 1912 |
|
1190 /* 1191 * Refresh the statistics so the new property value 1192 * is reflected. 1193 */ | 1913 /* 1914 * Refresh the statistics so the new property value 1915 * is reflected. 1916 */ |
1194 if ((ret = changelist_postfix(cl)) == 0) | 1917 if (ret == 0) |
1195 (void) get_stats(zhp); 1196 } 1197 1198error: 1199 nvlist_free(nvl); 1200 zcmd_free_nvlists(&zc); 1201 if (cl) 1202 changelist_free(cl); --- 11 unchanged lines hidden (view full) --- 1214 prop_changelist_t *cl; 1215 libzfs_handle_t *hdl = zhp->zfs_hdl; 1216 char errbuf[1024]; 1217 zfs_prop_t prop; 1218 1219 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1220 "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1221 | 1918 (void) get_stats(zhp); 1919 } 1920 1921error: 1922 nvlist_free(nvl); 1923 zcmd_free_nvlists(&zc); 1924 if (cl) 1925 changelist_free(cl); --- 11 unchanged lines hidden (view full) --- 1937 prop_changelist_t *cl; 1938 libzfs_handle_t *hdl = zhp->zfs_hdl; 1939 char errbuf[1024]; 1940 zfs_prop_t prop; 1941 1942 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 1943 "cannot inherit %s for '%s'"), propname, zhp->zfs_name); 1944 |
1222 if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) { | 1945 if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) { |
1223 /* 1224 * For user properties, the amount of work we have to do is very 1225 * small, so just do it here. 1226 */ 1227 if (!zfs_prop_user(propname)) { 1228 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1229 "invalid property")); 1230 return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1231 } 1232 1233 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1234 (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1235 | 1946 /* 1947 * For user properties, the amount of work we have to do is very 1948 * small, so just do it here. 1949 */ 1950 if (!zfs_prop_user(propname)) { 1951 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1952 "invalid property")); 1953 return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 1954 } 1955 1956 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1957 (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); 1958 |
1236 if (ioctl(zhp->zfs_hdl->libzfs_fd, 1237 ZFS_IOC_SET_PROP, &zc) != 0) | 1959 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) |
1238 return (zfs_standard_error(hdl, errno, errbuf)); 1239 1240 return (0); 1241 } 1242 1243 /* 1244 * Verify that this property is inheritable. 1245 */ --- 21 unchanged lines hidden (view full) --- 1267 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1268 "dataset is used in a non-global zone")); 1269 return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1270 } 1271 1272 /* 1273 * Determine datasets which will be affected by this change, if any. 1274 */ | 1960 return (zfs_standard_error(hdl, errno, errbuf)); 1961 1962 return (0); 1963 } 1964 1965 /* 1966 * Verify that this property is inheritable. 1967 */ --- 21 unchanged lines hidden (view full) --- 1989 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1990 "dataset is used in a non-global zone")); 1991 return (zfs_error(hdl, EZFS_ZONED, errbuf)); 1992 } 1993 1994 /* 1995 * Determine datasets which will be affected by this change, if any. 1996 */ |
1275 if ((cl = changelist_gather(zhp, prop, 0)) == NULL) | 1997 if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL) |
1276 return (-1); 1277 1278 if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 1279 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1280 "child dataset with inherited mountpoint is used " 1281 "in a non-global zone")); 1282 ret = zfs_error(hdl, EZFS_ZONED, errbuf); 1283 goto error; 1284 } 1285 1286 if ((ret = changelist_prefix(cl)) != 0) 1287 goto error; 1288 | 1998 return (-1); 1999 2000 if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { 2001 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2002 "child dataset with inherited mountpoint is used " 2003 "in a non-global zone")); 2004 ret = zfs_error(hdl, EZFS_ZONED, errbuf); 2005 goto error; 2006 } 2007 2008 if ((ret = changelist_prefix(cl)) != 0) 2009 goto error; 2010 |
1289 if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, 1290 ZFS_IOC_SET_PROP, &zc)) != 0) { | 2011 if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { |
1291 return (zfs_standard_error(hdl, errno, errbuf)); 1292 } else { 1293 1294 if ((ret = changelist_postfix(cl)) != 0) 1295 goto error; 1296 1297 /* 1298 * Refresh the statistics so the new property is reflected. 1299 */ 1300 (void) get_stats(zhp); 1301 } 1302 1303error: 1304 changelist_free(cl); 1305 return (ret); 1306} 1307 | 2012 return (zfs_standard_error(hdl, errno, errbuf)); 2013 } else { 2014 2015 if ((ret = changelist_postfix(cl)) != 0) 2016 goto error; 2017 2018 /* 2019 * Refresh the statistics so the new property is reflected. 2020 */ 2021 (void) get_stats(zhp); 2022 } 2023 2024error: 2025 changelist_free(cl); 2026 return (ret); 2027} 2028 |
1308void 1309nicebool(int value, char *buf, size_t buflen) 1310{ 1311 if (value) 1312 (void) strlcpy(buf, "on", buflen); 1313 else 1314 (void) strlcpy(buf, "off", buflen); 1315} 1316 | |
1317/* 1318 * True DSL properties are stored in an nvlist. The following two functions 1319 * extract them appropriately. 1320 */ 1321static uint64_t 1322getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1323{ 1324 nvlist_t *nv; 1325 uint64_t value; 1326 1327 *source = NULL; 1328 if (nvlist_lookup_nvlist(zhp->zfs_props, 1329 zfs_prop_to_name(prop), &nv) == 0) { | 2029/* 2030 * True DSL properties are stored in an nvlist. The following two functions 2031 * extract them appropriately. 2032 */ 2033static uint64_t 2034getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 2035{ 2036 nvlist_t *nv; 2037 uint64_t value; 2038 2039 *source = NULL; 2040 if (nvlist_lookup_nvlist(zhp->zfs_props, 2041 zfs_prop_to_name(prop), &nv) == 0) { |
1330 verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0); 1331 (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); | 2042 verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0); 2043 (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); |
1332 } else { 1333 value = zfs_prop_default_numeric(prop); 1334 *source = ""; 1335 } 1336 1337 return (value); 1338} 1339 1340static char * 1341getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 1342{ 1343 nvlist_t *nv; 1344 char *value; 1345 1346 *source = NULL; 1347 if (nvlist_lookup_nvlist(zhp->zfs_props, 1348 zfs_prop_to_name(prop), &nv) == 0) { | 2044 } else { 2045 value = zfs_prop_default_numeric(prop); 2046 *source = ""; 2047 } 2048 2049 return (value); 2050} 2051 2052static char * 2053getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) 2054{ 2055 nvlist_t *nv; 2056 char *value; 2057 2058 *source = NULL; 2059 if (nvlist_lookup_nvlist(zhp->zfs_props, 2060 zfs_prop_to_name(prop), &nv) == 0) { |
1349 verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0); 1350 (void) nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source); | 2061 verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); 2062 (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); |
1351 } else { 1352 if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 1353 value = ""; 1354 *source = ""; 1355 } 1356 1357 return (value); 1358} 1359 1360/* 1361 * Internal function for getting a numeric property. Both zfs_prop_get() and 1362 * zfs_prop_get_int() are built using this interface. 1363 * 1364 * Certain properties can be overridden using 'mount -o'. In this case, scan 1365 * the contents of the /etc/mnttab entry, searching for the appropriate options. 1366 * If they differ from the on-disk values, report the current values and mark 1367 * the source "temporary". 1368 */ 1369static int | 2063 } else { 2064 if ((value = (char *)zfs_prop_default_string(prop)) == NULL) 2065 value = ""; 2066 *source = ""; 2067 } 2068 2069 return (value); 2070} 2071 2072/* 2073 * Internal function for getting a numeric property. Both zfs_prop_get() and 2074 * zfs_prop_get_int() are built using this interface. 2075 * 2076 * Certain properties can be overridden using 'mount -o'. In this case, scan 2077 * the contents of the /etc/mnttab entry, searching for the appropriate options. 2078 * If they differ from the on-disk values, report the current values and mark 2079 * the source "temporary". 2080 */ 2081static int |
1370get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, | 2082get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, |
1371 char **source, uint64_t *val) 1372{ | 2083 char **source, uint64_t *val) 2084{ |
2085 zfs_cmd_t zc = { 0 }; 2086 nvlist_t *zplprops = NULL; |
|
1373 struct mnttab mnt; 1374 char *mntopt_on = NULL; 1375 char *mntopt_off = NULL; 1376 1377 *source = NULL; 1378 1379 switch (prop) { 1380 case ZFS_PROP_ATIME: --- 20 unchanged lines hidden (view full) --- 1401 mntopt_on = MNTOPT_SETUID; 1402 mntopt_off = MNTOPT_NOSETUID; 1403 break; 1404 1405 case ZFS_PROP_XATTR: 1406 mntopt_on = MNTOPT_XATTR; 1407 mntopt_off = MNTOPT_NOXATTR; 1408 break; | 2087 struct mnttab mnt; 2088 char *mntopt_on = NULL; 2089 char *mntopt_off = NULL; 2090 2091 *source = NULL; 2092 2093 switch (prop) { 2094 case ZFS_PROP_ATIME: --- 20 unchanged lines hidden (view full) --- 2115 mntopt_on = MNTOPT_SETUID; 2116 mntopt_off = MNTOPT_NOSETUID; 2117 break; 2118 2119 case ZFS_PROP_XATTR: 2120 mntopt_on = MNTOPT_XATTR; 2121 mntopt_off = MNTOPT_NOXATTR; 2122 break; |
2123 2124 case ZFS_PROP_NBMAND: 2125 mntopt_on = MNTOPT_NBMAND; 2126 mntopt_off = MNTOPT_NONBMAND; 2127 break; |
|
1409 } 1410 1411 /* 1412 * Because looking up the mount options is potentially expensive 1413 * (iterating over all of /etc/mnttab), we defer its calculation until 1414 * we're looking up a property which requires its presence. 1415 */ 1416 if (!zhp->zfs_mntcheck && --- 22 unchanged lines hidden (view full) --- 1439 1440 switch (prop) { 1441 case ZFS_PROP_ATIME: 1442 case ZFS_PROP_DEVICES: 1443 case ZFS_PROP_EXEC: 1444 case ZFS_PROP_READONLY: 1445 case ZFS_PROP_SETUID: 1446 case ZFS_PROP_XATTR: | 2128 } 2129 2130 /* 2131 * Because looking up the mount options is potentially expensive 2132 * (iterating over all of /etc/mnttab), we defer its calculation until 2133 * we're looking up a property which requires its presence. 2134 */ 2135 if (!zhp->zfs_mntcheck && --- 22 unchanged lines hidden (view full) --- 2158 2159 switch (prop) { 2160 case ZFS_PROP_ATIME: 2161 case ZFS_PROP_DEVICES: 2162 case ZFS_PROP_EXEC: 2163 case ZFS_PROP_READONLY: 2164 case ZFS_PROP_SETUID: 2165 case ZFS_PROP_XATTR: |
2166 case ZFS_PROP_NBMAND: |
|
1447 *val = getprop_uint64(zhp, prop, source); 1448 1449 if (hasmntopt(&mnt, mntopt_on) && !*val) { 1450 *val = B_TRUE; 1451 if (src) | 2167 *val = getprop_uint64(zhp, prop, source); 2168 2169 if (hasmntopt(&mnt, mntopt_on) && !*val) { 2170 *val = B_TRUE; 2171 if (src) |
1452 *src = ZFS_SRC_TEMPORARY; | 2172 *src = ZPROP_SRC_TEMPORARY; |
1453 } else if (hasmntopt(&mnt, mntopt_off) && *val) { 1454 *val = B_FALSE; 1455 if (src) | 2173 } else if (hasmntopt(&mnt, mntopt_off) && *val) { 2174 *val = B_FALSE; 2175 if (src) |
1456 *src = ZFS_SRC_TEMPORARY; | 2176 *src = ZPROP_SRC_TEMPORARY; |
1457 } 1458 break; 1459 | 2177 } 2178 break; 2179 |
1460 case ZFS_PROP_RECORDSIZE: 1461 case ZFS_PROP_COMPRESSION: 1462 case ZFS_PROP_ZONED: 1463 case ZFS_PROP_CREATION: 1464 case ZFS_PROP_COMPRESSRATIO: 1465 case ZFS_PROP_REFERENCED: 1466 case ZFS_PROP_USED: 1467 case ZFS_PROP_CREATETXG: 1468 case ZFS_PROP_AVAILABLE: 1469 case ZFS_PROP_VOLSIZE: 1470 case ZFS_PROP_VOLBLOCKSIZE: 1471 *val = getprop_uint64(zhp, prop, source); 1472 break; 1473 | |
1474 case ZFS_PROP_CANMOUNT: 1475 *val = getprop_uint64(zhp, prop, source); | 2180 case ZFS_PROP_CANMOUNT: 2181 *val = getprop_uint64(zhp, prop, source); |
1476 if (*val == 0) | 2182 if (*val != ZFS_CANMOUNT_ON) |
1477 *source = zhp->zfs_name; 1478 else 1479 *source = ""; /* default */ 1480 break; 1481 1482 case ZFS_PROP_QUOTA: | 2183 *source = zhp->zfs_name; 2184 else 2185 *source = ""; /* default */ 2186 break; 2187 2188 case ZFS_PROP_QUOTA: |
2189 case ZFS_PROP_REFQUOTA: |
|
1483 case ZFS_PROP_RESERVATION: | 2190 case ZFS_PROP_RESERVATION: |
2191 case ZFS_PROP_REFRESERVATION: |
|
1484 *val = getprop_uint64(zhp, prop, source); 1485 if (*val == 0) 1486 *source = ""; /* default */ 1487 else 1488 *source = zhp->zfs_name; 1489 break; 1490 1491 case ZFS_PROP_MOUNTED: 1492 *val = (zhp->zfs_mntopts != NULL); 1493 break; 1494 1495 case ZFS_PROP_NUMCLONES: 1496 *val = zhp->zfs_dmustats.dds_num_clones; 1497 break; 1498 | 2192 *val = getprop_uint64(zhp, prop, source); 2193 if (*val == 0) 2194 *source = ""; /* default */ 2195 else 2196 *source = zhp->zfs_name; 2197 break; 2198 2199 case ZFS_PROP_MOUNTED: 2200 *val = (zhp->zfs_mntopts != NULL); 2201 break; 2202 2203 case ZFS_PROP_NUMCLONES: 2204 *val = zhp->zfs_dmustats.dds_num_clones; 2205 break; 2206 |
2207 case ZFS_PROP_VERSION: 2208 case ZFS_PROP_NORMALIZE: 2209 case ZFS_PROP_UTF8ONLY: 2210 case ZFS_PROP_CASE: 2211 if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || 2212 zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 2213 return (-1); 2214 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2215 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { 2216 zcmd_free_nvlists(&zc); 2217 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2218 "unable to get %s property"), 2219 zfs_prop_to_name(prop)); 2220 return (zfs_error(zhp->zfs_hdl, EZFS_BADVERSION, 2221 dgettext(TEXT_DOMAIN, "internal error"))); 2222 } 2223 if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 || 2224 nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), 2225 val) != 0) { 2226 zcmd_free_nvlists(&zc); 2227 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2228 "unable to get %s property"), 2229 zfs_prop_to_name(prop)); 2230 return (zfs_error(zhp->zfs_hdl, EZFS_NOMEM, 2231 dgettext(TEXT_DOMAIN, "internal error"))); 2232 } 2233 if (zplprops) 2234 nvlist_free(zplprops); 2235 zcmd_free_nvlists(&zc); 2236 break; 2237 |
|
1499 default: | 2238 default: |
1500 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1501 "cannot get non-numeric property")); 1502 return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 1503 dgettext(TEXT_DOMAIN, "internal error"))); | 2239 switch (zfs_prop_get_type(prop)) { 2240 case PROP_TYPE_NUMBER: 2241 case PROP_TYPE_INDEX: 2242 *val = getprop_uint64(zhp, prop, source); 2243 /* 2244 * If we tried to use a defalut value for a 2245 * readonly property, it means that it was not 2246 * present; return an error. 2247 */ 2248 if (zfs_prop_readonly(prop) && 2249 *source && (*source)[0] == '\0') { 2250 return (-1); 2251 } 2252 break; 2253 2254 case PROP_TYPE_STRING: 2255 default: 2256 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 2257 "cannot get non-numeric property")); 2258 return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, 2259 dgettext(TEXT_DOMAIN, "internal error"))); 2260 } |
1504 } 1505 1506 return (0); 1507} 1508 1509/* 1510 * Calculate the source type, given the raw source string. 1511 */ 1512static void | 2261 } 2262 2263 return (0); 2264} 2265 2266/* 2267 * Calculate the source type, given the raw source string. 2268 */ 2269static void |
1513get_source(zfs_handle_t *zhp, zfs_source_t *srctype, char *source, | 2270get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, |
1514 char *statbuf, size_t statlen) 1515{ | 2271 char *statbuf, size_t statlen) 2272{ |
1516 if (statbuf == NULL || *srctype == ZFS_SRC_TEMPORARY) | 2273 if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY) |
1517 return; 1518 1519 if (source == NULL) { | 2274 return; 2275 2276 if (source == NULL) { |
1520 *srctype = ZFS_SRC_NONE; | 2277 *srctype = ZPROP_SRC_NONE; |
1521 } else if (source[0] == '\0') { | 2278 } else if (source[0] == '\0') { |
1522 *srctype = ZFS_SRC_DEFAULT; | 2279 *srctype = ZPROP_SRC_DEFAULT; |
1523 } else { 1524 if (strcmp(source, zhp->zfs_name) == 0) { | 2280 } else { 2281 if (strcmp(source, zhp->zfs_name) == 0) { |
1525 *srctype = ZFS_SRC_LOCAL; | 2282 *srctype = ZPROP_SRC_LOCAL; |
1526 } else { 1527 (void) strlcpy(statbuf, source, statlen); | 2283 } else { 2284 (void) strlcpy(statbuf, source, statlen); |
1528 *srctype = ZFS_SRC_INHERITED; | 2285 *srctype = ZPROP_SRC_INHERITED; |
1529 } 1530 } 1531 1532} 1533 1534/* 1535 * Retrieve a property from the given object. If 'literal' is specified, then 1536 * numbers are left as exact values. Otherwise, numbers are converted to a 1537 * human-readable form. 1538 * 1539 * Returns 0 on success, or -1 on error. 1540 */ 1541int 1542zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, | 2286 } 2287 } 2288 2289} 2290 2291/* 2292 * Retrieve a property from the given object. If 'literal' is specified, then 2293 * numbers are left as exact values. Otherwise, numbers are converted to a 2294 * human-readable form. 2295 * 2296 * Returns 0 on success, or -1 on error. 2297 */ 2298int 2299zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, |
1543 zfs_source_t *src, char *statbuf, size_t statlen, boolean_t literal) | 2300 zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) |
1544{ 1545 char *source = NULL; 1546 uint64_t val; 1547 char *str; | 2301{ 2302 char *source = NULL; 2303 uint64_t val; 2304 char *str; |
1548 const char *root; | |
1549 const char *strval; 1550 1551 /* 1552 * Check to see if this property applies to our object 1553 */ 1554 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 1555 return (-1); 1556 1557 if (src) | 2305 const char *strval; 2306 2307 /* 2308 * Check to see if this property applies to our object 2309 */ 2310 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) 2311 return (-1); 2312 2313 if (src) |
1558 *src = ZFS_SRC_NONE; | 2314 *src = ZPROP_SRC_NONE; |
1559 1560 switch (prop) { | 2315 2316 switch (prop) { |
1561 case ZFS_PROP_ATIME: 1562 case ZFS_PROP_READONLY: 1563 case ZFS_PROP_SETUID: 1564 case ZFS_PROP_ZONED: 1565 case ZFS_PROP_DEVICES: 1566 case ZFS_PROP_EXEC: 1567 case ZFS_PROP_CANMOUNT: 1568 case ZFS_PROP_XATTR: 1569 /* 1570 * Basic boolean values are built on top of 1571 * get_numeric_property(). 1572 */ 1573 if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1574 return (-1); 1575 nicebool(val, propbuf, proplen); 1576 1577 break; 1578 1579 case ZFS_PROP_AVAILABLE: 1580 case ZFS_PROP_RECORDSIZE: 1581 case ZFS_PROP_CREATETXG: 1582 case ZFS_PROP_REFERENCED: 1583 case ZFS_PROP_USED: 1584 case ZFS_PROP_VOLSIZE: 1585 case ZFS_PROP_VOLBLOCKSIZE: 1586 case ZFS_PROP_NUMCLONES: 1587 /* 1588 * Basic numeric values are built on top of 1589 * get_numeric_property(). 1590 */ 1591 if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1592 return (-1); 1593 if (literal) 1594 (void) snprintf(propbuf, proplen, "%llu", 1595 (u_longlong_t)val); 1596 else 1597 zfs_nicenum(val, propbuf, proplen); 1598 break; 1599 1600 case ZFS_PROP_COMPRESSION: 1601 case ZFS_PROP_CHECKSUM: 1602 case ZFS_PROP_SNAPDIR: 1603#ifdef ZFS_NO_ACL 1604 case ZFS_PROP_ACLMODE: 1605 case ZFS_PROP_ACLINHERIT: 1606 case ZFS_PROP_COPIES: 1607 val = getprop_uint64(zhp, prop, &source); 1608 verify(zfs_prop_index_to_string(prop, val, &strval) == 0); 1609 (void) strlcpy(propbuf, strval, proplen); 1610 break; 1611#else /* ZFS_NO_ACL */ 1612 case ZFS_PROP_ACLMODE: 1613 case ZFS_PROP_ACLINHERIT: 1614 (void) strlcpy(propbuf, "<unsupported>", proplen); 1615 break; 1616#endif /* ZFS_NO_ACL */ 1617 | |
1618 case ZFS_PROP_CREATION: 1619 /* 1620 * 'creation' is a time_t stored in the statistics. We convert 1621 * this into a string unless 'literal' is specified. 1622 */ 1623 { 1624 val = getprop_uint64(zhp, prop, &source); 1625 time_t time = (time_t)val; --- 7 unchanged lines hidden (view full) --- 1633 } 1634 break; 1635 1636 case ZFS_PROP_MOUNTPOINT: 1637 /* 1638 * Getting the precise mountpoint can be tricky. 1639 * 1640 * - for 'none' or 'legacy', return those values. | 2317 case ZFS_PROP_CREATION: 2318 /* 2319 * 'creation' is a time_t stored in the statistics. We convert 2320 * this into a string unless 'literal' is specified. 2321 */ 2322 { 2323 val = getprop_uint64(zhp, prop, &source); 2324 time_t time = (time_t)val; --- 7 unchanged lines hidden (view full) --- 2332 } 2333 break; 2334 2335 case ZFS_PROP_MOUNTPOINT: 2336 /* 2337 * Getting the precise mountpoint can be tricky. 2338 * 2339 * - for 'none' or 'legacy', return those values. |
1641 * - for default mountpoints, construct it as /zfs/<dataset> | |
1642 * - for inherited mountpoints, we want to take everything 1643 * after our ancestor and append it to the inherited value. 1644 * 1645 * If the pool has an alternate root, we want to prepend that 1646 * root to any values we return. 1647 */ | 2340 * - for inherited mountpoints, we want to take everything 2341 * after our ancestor and append it to the inherited value. 2342 * 2343 * If the pool has an alternate root, we want to prepend that 2344 * root to any values we return. 2345 */ |
1648 root = zhp->zfs_root; | 2346 |
1649 str = getprop_string(zhp, prop, &source); 1650 | 2347 str = getprop_string(zhp, prop, &source); 2348 |
1651 if (str[0] == '\0') { 1652 (void) snprintf(propbuf, proplen, "%s/zfs/%s", 1653 root, zhp->zfs_name); 1654 } else if (str[0] == '/') { | 2349 if (str[0] == '/') { 2350 char buf[MAXPATHLEN]; 2351 char *root = buf; |
1655 const char *relpath = zhp->zfs_name + strlen(source); 1656 1657 if (relpath[0] == '/') 1658 relpath++; | 2352 const char *relpath = zhp->zfs_name + strlen(source); 2353 2354 if (relpath[0] == '/') 2355 relpath++; |
1659 if (str[1] == '\0') | 2356 2357 if ((zpool_get_prop(zhp->zpool_hdl, 2358 ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || 2359 (strcmp(root, "-") == 0)) 2360 root[0] = '\0'; 2361 /* 2362 * Special case an alternate root of '/'. This will 2363 * avoid having multiple leading slashes in the 2364 * mountpoint path. 2365 */ 2366 if (strcmp(root, "/") == 0) 2367 root++; 2368 2369 /* 2370 * If the mountpoint is '/' then skip over this 2371 * if we are obtaining either an alternate root or 2372 * an inherited mountpoint. 2373 */ 2374 if (str[1] == '\0' && (root[0] != '\0' || 2375 relpath[0] != '\0')) |
1660 str++; 1661 1662 if (relpath[0] == '\0') 1663 (void) snprintf(propbuf, proplen, "%s%s", 1664 root, str); 1665 else 1666 (void) snprintf(propbuf, proplen, "%s%s%s%s", 1667 root, str, relpath[0] == '@' ? "" : "/", 1668 relpath); 1669 } else { 1670 /* 'legacy' or 'none' */ 1671 (void) strlcpy(propbuf, str, proplen); 1672 } 1673 1674 break; 1675 | 2376 str++; 2377 2378 if (relpath[0] == '\0') 2379 (void) snprintf(propbuf, proplen, "%s%s", 2380 root, str); 2381 else 2382 (void) snprintf(propbuf, proplen, "%s%s%s%s", 2383 root, str, relpath[0] == '@' ? "" : "/", 2384 relpath); 2385 } else { 2386 /* 'legacy' or 'none' */ 2387 (void) strlcpy(propbuf, str, proplen); 2388 } 2389 2390 break; 2391 |
1676 case ZFS_PROP_SHARENFS: 1677 case ZFS_PROP_SHAREISCSI: 1678 case ZFS_PROP_ISCSIOPTIONS: 1679 (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1680 proplen); 1681 break; 1682 | |
1683 case ZFS_PROP_ORIGIN: 1684 (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 1685 proplen); 1686 /* 1687 * If there is no parent at all, return failure to indicate that 1688 * it doesn't apply to this dataset. 1689 */ 1690 if (propbuf[0] == '\0') 1691 return (-1); 1692 break; 1693 1694 case ZFS_PROP_QUOTA: | 2392 case ZFS_PROP_ORIGIN: 2393 (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), 2394 proplen); 2395 /* 2396 * If there is no parent at all, return failure to indicate that 2397 * it doesn't apply to this dataset. 2398 */ 2399 if (propbuf[0] == '\0') 2400 return (-1); 2401 break; 2402 2403 case ZFS_PROP_QUOTA: |
2404 case ZFS_PROP_REFQUOTA: |
|
1695 case ZFS_PROP_RESERVATION: | 2405 case ZFS_PROP_RESERVATION: |
2406 case ZFS_PROP_REFRESERVATION: 2407 |
|
1696 if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 1697 return (-1); 1698 1699 /* 1700 * If quota or reservation is 0, we translate this into 'none' 1701 * (unless literal is set), and indicate that it's the default 1702 * value. Otherwise, we print the number nicely and indicate 1703 * that its set locally. --- 57 unchanged lines hidden (view full) --- 1761 * The 'name' property is a pseudo-property derived from the 1762 * dataset name. It is presented as a real property to simplify 1763 * consumers. 1764 */ 1765 (void) strlcpy(propbuf, zhp->zfs_name, proplen); 1766 break; 1767 1768 default: | 2408 if (get_numeric_property(zhp, prop, src, &source, &val) != 0) 2409 return (-1); 2410 2411 /* 2412 * If quota or reservation is 0, we translate this into 'none' 2413 * (unless literal is set), and indicate that it's the default 2414 * value. Otherwise, we print the number nicely and indicate 2415 * that its set locally. --- 57 unchanged lines hidden (view full) --- 2473 * The 'name' property is a pseudo-property derived from the 2474 * dataset name. It is presented as a real property to simplify 2475 * consumers. 2476 */ 2477 (void) strlcpy(propbuf, zhp->zfs_name, proplen); 2478 break; 2479 2480 default: |
1769 abort(); | 2481 switch (zfs_prop_get_type(prop)) { 2482 case PROP_TYPE_NUMBER: 2483 if (get_numeric_property(zhp, prop, src, 2484 &source, &val) != 0) 2485 return (-1); 2486 if (literal) 2487 (void) snprintf(propbuf, proplen, "%llu", 2488 (u_longlong_t)val); 2489 else 2490 zfs_nicenum(val, propbuf, proplen); 2491 break; 2492 2493 case PROP_TYPE_STRING: 2494 (void) strlcpy(propbuf, 2495 getprop_string(zhp, prop, &source), proplen); 2496 break; 2497 2498 case PROP_TYPE_INDEX: 2499 if (get_numeric_property(zhp, prop, src, 2500 &source, &val) != 0) 2501 return (-1); 2502 if (zfs_prop_index_to_string(prop, val, &strval) != 0) 2503 return (-1); 2504 (void) strlcpy(propbuf, strval, proplen); 2505 break; 2506 2507 default: 2508 abort(); 2509 } |
1770 } 1771 1772 get_source(zhp, src, source, statbuf, statlen); 1773 1774 return (0); 1775} 1776 1777/* 1778 * Utility function to get the given numeric property. Does no validation that 1779 * the given property is the appropriate type; should only be used with 1780 * hard-coded property types. 1781 */ 1782uint64_t 1783zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 1784{ 1785 char *source; | 2510 } 2511 2512 get_source(zhp, src, source, statbuf, statlen); 2513 2514 return (0); 2515} 2516 2517/* 2518 * Utility function to get the given numeric property. Does no validation that 2519 * the given property is the appropriate type; should only be used with 2520 * hard-coded property types. 2521 */ 2522uint64_t 2523zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) 2524{ 2525 char *source; |
1786 zfs_source_t sourcetype = ZFS_SRC_NONE; | |
1787 uint64_t val; 1788 | 2526 uint64_t val; 2527 |
1789 (void) get_numeric_property(zhp, prop, &sourcetype, &source, &val); | 2528 (void) get_numeric_property(zhp, prop, NULL, &source, &val); |
1790 1791 return (val); 1792} 1793 | 2529 2530 return (val); 2531} 2532 |
2533int 2534zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) 2535{ 2536 char buf[64]; 2537 2538 zfs_nicenum(val, buf, sizeof (buf)); 2539 return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); 2540} 2541 |
|
1794/* 1795 * Similar to zfs_prop_get(), but returns the value as an integer. 1796 */ 1797int 1798zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, | 2542/* 2543 * Similar to zfs_prop_get(), but returns the value as an integer. 2544 */ 2545int 2546zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, |
1799 zfs_source_t *src, char *statbuf, size_t statlen) | 2547 zprop_source_t *src, char *statbuf, size_t statlen) |
1800{ 1801 char *source; 1802 1803 /* 1804 * Check to see if this property applies to our object 1805 */ | 2548{ 2549 char *source; 2550 2551 /* 2552 * Check to see if this property applies to our object 2553 */ |
1806 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) | 2554 if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { |
1807 return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 1808 dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 1809 zfs_prop_to_name(prop))); | 2555 return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, 2556 dgettext(TEXT_DOMAIN, "cannot get property '%s'"), 2557 zfs_prop_to_name(prop))); |
2558 } |
|
1810 1811 if (src) | 2559 2560 if (src) |
1812 *src = ZFS_SRC_NONE; | 2561 *src = ZPROP_SRC_NONE; |
1813 1814 if (get_numeric_property(zhp, prop, src, &source, value) != 0) 1815 return (-1); 1816 1817 get_source(zhp, src, source, statbuf, statlen); 1818 1819 return (0); 1820} --- 21 unchanged lines hidden (view full) --- 1842 */ 1843int 1844zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1845{ 1846 zfs_cmd_t zc = { 0 }; 1847 zfs_handle_t *nzhp; 1848 int ret; 1849 | 2562 2563 if (get_numeric_property(zhp, prop, src, &source, value) != 0) 2564 return (-1); 2565 2566 get_source(zhp, src, source, statbuf, statlen); 2567 2568 return (0); 2569} --- 21 unchanged lines hidden (view full) --- 2591 */ 2592int 2593zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2594{ 2595 zfs_cmd_t zc = { 0 }; 2596 zfs_handle_t *nzhp; 2597 int ret; 2598 |
2599 if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) 2600 return (0); 2601 |
|
1850 for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1851 ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 1852 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1853 /* 1854 * Ignore private dataset names. 1855 */ 1856 if (dataset_name_hidden(zc.zc_name)) 1857 continue; --- 27 unchanged lines hidden (view full) --- 1885 */ 1886int 1887zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 1888{ 1889 zfs_cmd_t zc = { 0 }; 1890 zfs_handle_t *nzhp; 1891 int ret; 1892 | 2602 for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2603 ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DATASET_LIST_NEXT, &zc) == 0; 2604 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 2605 /* 2606 * Ignore private dataset names. 2607 */ 2608 if (dataset_name_hidden(zc.zc_name)) 2609 continue; --- 27 unchanged lines hidden (view full) --- 2637 */ 2638int 2639zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) 2640{ 2641 zfs_cmd_t zc = { 0 }; 2642 zfs_handle_t *nzhp; 2643 int ret; 2644 |
2645 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) 2646 return (0); 2647 |
|
1893 for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 1894 ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 1895 &zc) == 0; 1896 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 1897 1898 if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 1899 zc.zc_name)) == NULL) 1900 continue; --- 42 unchanged lines hidden (view full) --- 1943 1944 (void) strncpy(buf, path, MIN(buflen, loc - path)); 1945 buf[loc - path] = '\0'; 1946 1947 return (0); 1948} 1949 1950/* | 2648 for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2649 ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, 2650 &zc) == 0; 2651 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name))) { 2652 2653 if ((nzhp = make_dataset_handle(zhp->zfs_hdl, 2654 zc.zc_name)) == NULL) 2655 continue; --- 42 unchanged lines hidden (view full) --- 2698 2699 (void) strncpy(buf, path, MIN(buflen, loc - path)); 2700 buf[loc - path] = '\0'; 2701 2702 return (0); 2703} 2704 2705/* |
1951 * Checks to make sure that the given path has a parent, and that it exists. We 1952 * also fetch the 'zoned' property, which is used to validate property settings 1953 * when creating new datasets. | 2706 * If accept_ancestor is false, then check to make sure that the given path has 2707 * a parent, and that it exists. If accept_ancestor is true, then find the 2708 * closest existing ancestor for the given path. In prefixlen return the 2709 * length of already existing prefix of the given path. We also fetch the 2710 * 'zoned' property, which is used to validate property settings when creating 2711 * new datasets. |
1954 */ 1955static int | 2712 */ 2713static int |
1956check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned) | 2714check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, 2715 boolean_t accept_ancestor, int *prefixlen) |
1957{ 1958 zfs_cmd_t zc = { 0 }; 1959 char parent[ZFS_MAXNAMELEN]; 1960 char *slash; 1961 zfs_handle_t *zhp; 1962 char errbuf[1024]; 1963 1964 (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", --- 14 unchanged lines hidden (view full) --- 1979 if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 1980 errno == ENOENT) { 1981 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1982 "no such pool '%s'"), zc.zc_name); 1983 return (zfs_error(hdl, EZFS_NOENT, errbuf)); 1984 } 1985 1986 /* check to see if the parent dataset exists */ | 2716{ 2717 zfs_cmd_t zc = { 0 }; 2718 char parent[ZFS_MAXNAMELEN]; 2719 char *slash; 2720 zfs_handle_t *zhp; 2721 char errbuf[1024]; 2722 2723 (void) snprintf(errbuf, sizeof (errbuf), "cannot create '%s'", --- 14 unchanged lines hidden (view full) --- 2738 if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 && 2739 errno == ENOENT) { 2740 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2741 "no such pool '%s'"), zc.zc_name); 2742 return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2743 } 2744 2745 /* check to see if the parent dataset exists */ |
1987 if ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 1988 switch (errno) { 1989 case ENOENT: | 2746 while ((zhp = make_dataset_handle(hdl, parent)) == NULL) { 2747 if (errno == ENOENT && accept_ancestor) { 2748 /* 2749 * Go deeper to find an ancestor, give up on top level. 2750 */ 2751 if (parent_name(parent, parent, sizeof (parent)) != 0) { 2752 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2753 "no such pool '%s'"), zc.zc_name); 2754 return (zfs_error(hdl, EZFS_NOENT, errbuf)); 2755 } 2756 } else if (errno == ENOENT) { |
1990 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1991 "parent does not exist")); 1992 return (zfs_error(hdl, EZFS_NOENT, errbuf)); | 2757 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2758 "parent does not exist")); 2759 return (zfs_error(hdl, EZFS_NOENT, errbuf)); |
1993 1994 default: | 2760 } else |
1995 return (zfs_standard_error(hdl, errno, errbuf)); | 2761 return (zfs_standard_error(hdl, errno, errbuf)); |
1996 } | |
1997 } 1998 1999 *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2000 /* we are in a non-global zone, but parent is in the global zone */ 2001 if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 2002 (void) zfs_standard_error(hdl, EPERM, errbuf); 2003 zfs_close(zhp); 2004 return (-1); --- 4 unchanged lines hidden (view full) --- 2009 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2010 "parent is not a filesystem")); 2011 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2012 zfs_close(zhp); 2013 return (-1); 2014 } 2015 2016 zfs_close(zhp); | 2762 } 2763 2764 *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); 2765 /* we are in a non-global zone, but parent is in the global zone */ 2766 if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) { 2767 (void) zfs_standard_error(hdl, EPERM, errbuf); 2768 zfs_close(zhp); 2769 return (-1); --- 4 unchanged lines hidden (view full) --- 2774 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2775 "parent is not a filesystem")); 2776 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); 2777 zfs_close(zhp); 2778 return (-1); 2779 } 2780 2781 zfs_close(zhp); |
2782 if (prefixlen != NULL) 2783 *prefixlen = strlen(parent); |
|
2017 return (0); 2018} 2019 2020/* | 2784 return (0); 2785} 2786 2787/* |
2788 * Finds whether the dataset of the given type(s) exists. 2789 */ 2790boolean_t 2791zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types) 2792{ 2793 zfs_handle_t *zhp; 2794 2795 if (!zfs_validate_name(hdl, path, types, B_FALSE)) 2796 return (B_FALSE); 2797 2798 /* 2799 * Try to get stats for the dataset, which will tell us if it exists. 2800 */ 2801 if ((zhp = make_dataset_handle(hdl, path)) != NULL) { 2802 int ds_type = zhp->zfs_type; 2803 2804 zfs_close(zhp); 2805 if (types & ds_type) 2806 return (B_TRUE); 2807 } 2808 return (B_FALSE); 2809} 2810 2811/* 2812 * Given a path to 'target', create all the ancestors between 2813 * the prefixlen portion of the path, and the target itself. 2814 * Fail if the initial prefixlen-ancestor does not already exist. 2815 */ 2816int 2817create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2818{ 2819 zfs_handle_t *h; 2820 char *cp; 2821 const char *opname; 2822 2823 /* make sure prefix exists */ 2824 cp = target + prefixlen; 2825 if (*cp != '/') { 2826 assert(strchr(cp, '/') == NULL); 2827 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2828 } else { 2829 *cp = '\0'; 2830 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2831 *cp = '/'; 2832 } 2833 if (h == NULL) 2834 return (-1); 2835 zfs_close(h); 2836 2837 /* 2838 * Attempt to create, mount, and share any ancestor filesystems, 2839 * up to the prefixlen-long one. 2840 */ 2841 for (cp = target + prefixlen + 1; 2842 cp = strchr(cp, '/'); *cp = '/', cp++) { 2843 char *logstr; 2844 2845 *cp = '\0'; 2846 2847 h = make_dataset_handle(hdl, target); 2848 if (h) { 2849 /* it already exists, nothing to do here */ 2850 zfs_close(h); 2851 continue; 2852 } 2853 2854 logstr = hdl->libzfs_log_str; 2855 hdl->libzfs_log_str = NULL; 2856 if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2857 NULL) != 0) { 2858 hdl->libzfs_log_str = logstr; 2859 opname = dgettext(TEXT_DOMAIN, "create"); 2860 goto ancestorerr; 2861 } 2862 2863 hdl->libzfs_log_str = logstr; 2864 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2865 if (h == NULL) { 2866 opname = dgettext(TEXT_DOMAIN, "open"); 2867 goto ancestorerr; 2868 } 2869 2870 if (zfs_mount(h, NULL, 0) != 0) { 2871 opname = dgettext(TEXT_DOMAIN, "mount"); 2872 goto ancestorerr; 2873 } 2874 2875 if (zfs_share(h) != 0) { 2876 opname = dgettext(TEXT_DOMAIN, "share"); 2877 goto ancestorerr; 2878 } 2879 2880 zfs_close(h); 2881 } 2882 2883 return (0); 2884 2885ancestorerr: 2886 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2887 "failed to %s ancestor '%s'"), opname, target); 2888 return (-1); 2889} 2890 2891/* 2892 * Creates non-existing ancestors of the given path. 2893 */ 2894int 2895zfs_create_ancestors(libzfs_handle_t *hdl, const char *path) 2896{ 2897 int prefix; 2898 uint64_t zoned; 2899 char *path_copy; 2900 int rc; 2901 2902 if (check_parents(hdl, path, &zoned, B_TRUE, &prefix) != 0) 2903 return (-1); 2904 2905 if ((path_copy = strdup(path)) != NULL) { 2906 rc = create_parents(hdl, path_copy, prefix); 2907 free(path_copy); 2908 } 2909 if (path_copy == NULL || rc != 0) 2910 return (-1); 2911 2912 return (0); 2913} 2914 2915/* |
|
2021 * Create a new filesystem or volume. 2022 */ 2023int 2024zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2025 nvlist_t *props) 2026{ 2027 zfs_cmd_t zc = { 0 }; 2028 int ret; 2029 uint64_t size = 0; 2030 uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 2031 char errbuf[1024]; 2032 uint64_t zoned; 2033 2034 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2035 "cannot create '%s'"), path); 2036 2037 /* validate the path, taking care to note the extended error message */ | 2916 * Create a new filesystem or volume. 2917 */ 2918int 2919zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, 2920 nvlist_t *props) 2921{ 2922 zfs_cmd_t zc = { 0 }; 2923 int ret; 2924 uint64_t size = 0; 2925 uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 2926 char errbuf[1024]; 2927 uint64_t zoned; 2928 2929 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2930 "cannot create '%s'"), path); 2931 2932 /* validate the path, taking care to note the extended error message */ |
2038 if (!zfs_validate_name(hdl, path, type)) | 2933 if (!zfs_validate_name(hdl, path, type, B_TRUE)) |
2039 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2040 2041 /* validate parents exist */ | 2934 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2935 2936 /* validate parents exist */ |
2042 if (check_parents(hdl, path, &zoned) != 0) | 2937 if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0) |
2043 return (-1); 2044 2045 /* 2046 * The failure modes when creating a dataset of a different type over 2047 * one that already exists is a little strange. In particular, if you 2048 * try to create a dataset on top of an existing dataset, the ioctl() 2049 * will return ENOENT, not EEXIST. To prevent this from happening, we 2050 * first try to see if the dataset exists. 2051 */ 2052 (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); | 2938 return (-1); 2939 2940 /* 2941 * The failure modes when creating a dataset of a different type over 2942 * one that already exists is a little strange. In particular, if you 2943 * try to create a dataset on top of an existing dataset, the ioctl() 2944 * will return ENOENT, not EEXIST. To prevent this from happening, we 2945 * first try to see if the dataset exists. 2946 */ 2947 (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); |
2053 if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { | 2948 if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { |
2054 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2055 "dataset already exists")); 2056 return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2057 } 2058 2059 if (type == ZFS_TYPE_VOLUME) 2060 zc.zc_objset_type = DMU_OST_ZVOL; 2061 else 2062 zc.zc_objset_type = DMU_OST_ZFS; 2063 | 2949 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2950 "dataset already exists")); 2951 return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2952 } 2953 2954 if (type == ZFS_TYPE_VOLUME) 2955 zc.zc_objset_type = DMU_OST_ZVOL; 2956 else 2957 zc.zc_objset_type = DMU_OST_ZFS; 2958 |
2064 if (props && (props = zfs_validate_properties(hdl, type, NULL, props, | 2959 if (props && (props = zfs_valid_proplist(hdl, type, props, |
2065 zoned, NULL, errbuf)) == 0) 2066 return (-1); 2067 2068 if (type == ZFS_TYPE_VOLUME) { 2069 /* 2070 * If we are creating a volume, the size and block size must 2071 * satisfy a few restraints. First, the blocksize must be a 2072 * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the --- 33 unchanged lines hidden (view full) --- 2106 nvlist_free(props); 2107 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2108 "volume size must be a multiple of volume block " 2109 "size")); 2110 return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2111 } 2112 } 2113 | 2960 zoned, NULL, errbuf)) == 0) 2961 return (-1); 2962 2963 if (type == ZFS_TYPE_VOLUME) { 2964 /* 2965 * If we are creating a volume, the size and block size must 2966 * satisfy a few restraints. First, the blocksize must be a 2967 * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the --- 33 unchanged lines hidden (view full) --- 3001 nvlist_free(props); 3002 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3003 "volume size must be a multiple of volume block " 3004 "size")); 3005 return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3006 } 3007 } 3008 |
2114 if (props && 2115 zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) | 3009 if (props && zcmd_write_src_nvlist(hdl, &zc, props) != 0) |
2116 return (-1); 2117 nvlist_free(props); 2118 2119 /* create the dataset */ | 3010 return (-1); 3011 nvlist_free(props); 3012 3013 /* create the dataset */ |
2120 ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); | 3014 ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); |
2121 2122 if (ret == 0 && type == ZFS_TYPE_VOLUME) { 2123 ret = zvol_create_link(hdl, path); 2124 if (ret) { 2125 (void) zfs_standard_error(hdl, errno, 2126 dgettext(TEXT_DOMAIN, 2127 "Volume successfully created, but device links " 2128 "were not created")); --- 24 unchanged lines hidden (view full) --- 2153 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2154 "volume block size must be power of 2 from " 2155 "%u to %uk"), 2156 (uint_t)SPA_MINBLOCKSIZE, 2157 (uint_t)SPA_MAXBLOCKSIZE >> 10); 2158 2159 return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 2160 | 3015 3016 if (ret == 0 && type == ZFS_TYPE_VOLUME) { 3017 ret = zvol_create_link(hdl, path); 3018 if (ret) { 3019 (void) zfs_standard_error(hdl, errno, 3020 dgettext(TEXT_DOMAIN, 3021 "Volume successfully created, but device links " 3022 "were not created")); --- 24 unchanged lines hidden (view full) --- 3047 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3048 "volume block size must be power of 2 from " 3049 "%u to %uk"), 3050 (uint_t)SPA_MINBLOCKSIZE, 3051 (uint_t)SPA_MAXBLOCKSIZE >> 10); 3052 3053 return (zfs_error(hdl, EZFS_BADPROP, errbuf)); 3054 |
3055 case ENOTSUP: 3056 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3057 "pool must be upgraded to set this " 3058 "property or value")); 3059 return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); |
|
2161#ifdef _ILP32 2162 case EOVERFLOW: 2163 /* 2164 * This platform can't address a volume this big. 2165 */ 2166 if (type == ZFS_TYPE_VOLUME) 2167 return (zfs_error(hdl, EZFS_VOLTOOBIG, 2168 errbuf)); --- 15 unchanged lines hidden (view full) --- 2184zfs_destroy(zfs_handle_t *zhp) 2185{ 2186 zfs_cmd_t zc = { 0 }; 2187 2188 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2189 2190 if (ZFS_IS_VOLUME(zhp)) { 2191 /* | 3060#ifdef _ILP32 3061 case EOVERFLOW: 3062 /* 3063 * This platform can't address a volume this big. 3064 */ 3065 if (type == ZFS_TYPE_VOLUME) 3066 return (zfs_error(hdl, EZFS_VOLTOOBIG, 3067 errbuf)); --- 15 unchanged lines hidden (view full) --- 3083zfs_destroy(zfs_handle_t *zhp) 3084{ 3085 zfs_cmd_t zc = { 0 }; 3086 3087 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3088 3089 if (ZFS_IS_VOLUME(zhp)) { 3090 /* |
2192 * Unconditionally unshare this zvol ignoring failure as it 2193 * indicates only that the volume wasn't shared initially. | 3091 * If user doesn't have permissions to unshare volume, then 3092 * abort the request. This would only happen for a 3093 * non-privileged user. |
2194 */ | 3094 */ |
2195 (void) zfs_unshare_iscsi(zhp); | 3095 if (zfs_unshare_iscsi(zhp) != 0) { 3096 return (-1); 3097 } |
2196 2197 if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 2198 return (-1); 2199 2200 zc.zc_objset_type = DMU_OST_ZVOL; 2201 } else { 2202 zc.zc_objset_type = DMU_OST_ZFS; 2203 } 2204 | 3098 3099 if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3100 return (-1); 3101 3102 zc.zc_objset_type = DMU_OST_ZVOL; 3103 } else { 3104 zc.zc_objset_type = DMU_OST_ZFS; 3105 } 3106 |
2205 if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc) != 0) { | 3107 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0) { |
2206 return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 2207 dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 2208 zhp->zfs_name)); 2209 } 2210 2211 remove_mountpoint(zhp); 2212 2213 return (0); --- 57 unchanged lines hidden (view full) --- 2271 return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 2272 dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 2273 zhp->zfs_name, snapname)); 2274 } 2275 2276 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2277 (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 2278 | 3108 return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3109 dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), 3110 zhp->zfs_name)); 3111 } 3112 3113 remove_mountpoint(zhp); 3114 3115 return (0); --- 57 unchanged lines hidden (view full) --- 3173 return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, 3174 dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), 3175 zhp->zfs_name, snapname)); 3176 } 3177 3178 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3179 (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); 3180 |
2279 ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc); | 3181 ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS, &zc); |
2280 if (ret != 0) { 2281 char errbuf[1024]; 2282 2283 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2284 "cannot destroy '%s@%s'"), zc.zc_name, snapname); 2285 2286 switch (errno) { 2287 case EEXIST: --- 25 unchanged lines hidden (view full) --- 2313 uint64_t zoned; 2314 2315 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2316 2317 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2318 "cannot create '%s'"), target); 2319 2320 /* validate the target name */ | 3182 if (ret != 0) { 3183 char errbuf[1024]; 3184 3185 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3186 "cannot destroy '%s@%s'"), zc.zc_name, snapname); 3187 3188 switch (errno) { 3189 case EEXIST: --- 25 unchanged lines hidden (view full) --- 3215 uint64_t zoned; 3216 3217 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 3218 3219 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3220 "cannot create '%s'"), target); 3221 3222 /* validate the target name */ |
2321 if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM)) | 3223 if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) |
2322 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2323 2324 /* validate parents exist */ | 3224 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3225 3226 /* validate parents exist */ |
2325 if (check_parents(hdl, target, &zoned) != 0) | 3227 if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0) |
2326 return (-1); 2327 2328 (void) parent_name(target, parent, sizeof (parent)); 2329 2330 /* do the clone */ 2331 if (ZFS_IS_VOLUME(zhp)) { 2332 zc.zc_objset_type = DMU_OST_ZVOL; 2333 type = ZFS_TYPE_VOLUME; 2334 } else { 2335 zc.zc_objset_type = DMU_OST_ZFS; 2336 type = ZFS_TYPE_FILESYSTEM; 2337 } 2338 2339 if (props) { | 3228 return (-1); 3229 3230 (void) parent_name(target, parent, sizeof (parent)); 3231 3232 /* do the clone */ 3233 if (ZFS_IS_VOLUME(zhp)) { 3234 zc.zc_objset_type = DMU_OST_ZVOL; 3235 type = ZFS_TYPE_VOLUME; 3236 } else { 3237 zc.zc_objset_type = DMU_OST_ZFS; 3238 type = ZFS_TYPE_FILESYSTEM; 3239 } 3240 3241 if (props) { |
2340 if ((props = zfs_validate_properties(hdl, type, NULL, props, 2341 zoned, zhp, errbuf)) == NULL) | 3242 if ((props = zfs_valid_proplist(hdl, type, props, zoned, 3243 zhp, errbuf)) == NULL) |
2342 return (-1); 2343 | 3244 return (-1); 3245 |
2344 if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) { | 3246 if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { |
2345 nvlist_free(props); 2346 return (-1); 2347 } 2348 2349 nvlist_free(props); 2350 } 2351 2352 (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 2353 (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); | 3247 nvlist_free(props); 3248 return (-1); 3249 } 3250 3251 nvlist_free(props); 3252 } 3253 3254 (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); 3255 (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); |
2354 ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc); | 3256 ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc); |
2355 2356 zcmd_free_nvlists(&zc); 2357 2358 if (ret != 0) { 2359 switch (errno) { 2360 2361 case ENOENT: 2362 /* --- 102 unchanged lines hidden (view full) --- 2465 "cannot promote '%s'"), zhp->zfs_name); 2466 2467 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 2468 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2469 "snapshots can not be promoted")); 2470 return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2471 } 2472 | 3257 3258 zcmd_free_nvlists(&zc); 3259 3260 if (ret != 0) { 3261 switch (errno) { 3262 3263 case ENOENT: 3264 /* --- 102 unchanged lines hidden (view full) --- 3367 "cannot promote '%s'"), zhp->zfs_name); 3368 3369 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 3370 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3371 "snapshots can not be promoted")); 3372 return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3373 } 3374 |
2473 (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent)); | 3375 (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); |
2474 if (parent[0] == '\0') { 2475 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2476 "not a cloned filesystem")); 2477 return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 2478 } 2479 cp = strchr(parent, '@'); 2480 *cp = '\0'; 2481 2482 /* Walk the snapshots we will be moving */ | 3376 if (parent[0] == '\0') { 3377 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3378 "not a cloned filesystem")); 3379 return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3380 } 3381 cp = strchr(parent, '@'); 3382 *cp = '\0'; 3383 3384 /* Walk the snapshots we will be moving */ |
2483 pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_clone_of, ZFS_TYPE_SNAPSHOT); | 3385 pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT); |
2484 if (pzhp == NULL) 2485 return (-1); 2486 pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 2487 zfs_close(pzhp); 2488 pd.cb_target = zhp->zfs_name; 2489 pd.cb_errbuf = errbuf; | 3386 if (pzhp == NULL) 3387 return (-1); 3388 pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); 3389 zfs_close(pzhp); 3390 pd.cb_target = zhp->zfs_name; 3391 pd.cb_errbuf = errbuf; |
2490 pzhp = zfs_open(hdl, parent, ZFS_TYPE_ANY); | 3392 pzhp = zfs_open(hdl, parent, ZFS_TYPE_DATASET); |
2491 if (pzhp == NULL) 2492 return (-1); 2493 (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 2494 sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 2495 ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 2496 if (ret != 0) { 2497 zfs_close(pzhp); 2498 return (-1); 2499 } 2500 2501 /* issue the ioctl */ | 3393 if (pzhp == NULL) 3394 return (-1); 3395 (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, 3396 sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); 3397 ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); 3398 if (ret != 0) { 3399 zfs_close(pzhp); 3400 return (-1); 3401 } 3402 3403 /* issue the ioctl */ |
2502 (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of, | 3404 (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, |
2503 sizeof (zc.zc_value)); 2504 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); | 3405 sizeof (zc.zc_value)); 3406 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); |
2505 ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc); | 3407 ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); |
2506 2507 if (ret != 0) { 2508 int save_errno = errno; 2509 2510 (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 2511 zfs_close(pzhp); 2512 2513 switch (save_errno) { --- 51 unchanged lines hidden (view full) --- 2565 2566 return (ret); 2567} 2568 2569/* 2570 * Takes a snapshot of the given dataset. 2571 */ 2572int | 3408 3409 if (ret != 0) { 3410 int save_errno = errno; 3411 3412 (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); 3413 zfs_close(pzhp); 3414 3415 switch (save_errno) { --- 51 unchanged lines hidden (view full) --- 3467 3468 return (ret); 3469} 3470 3471/* 3472 * Takes a snapshot of the given dataset. 3473 */ 3474int |
2573zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) | 3475zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, 3476 nvlist_t *props) |
2574{ 2575 const char *delim; | 3477{ 3478 const char *delim; |
2576 char *parent; | 3479 char parent[ZFS_MAXNAMELEN]; |
2577 zfs_handle_t *zhp; 2578 zfs_cmd_t zc = { 0 }; 2579 int ret; 2580 char errbuf[1024]; 2581 2582 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2583 "cannot snapshot '%s'"), path); 2584 2585 /* validate the target name */ | 3480 zfs_handle_t *zhp; 3481 zfs_cmd_t zc = { 0 }; 3482 int ret; 3483 char errbuf[1024]; 3484 3485 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3486 "cannot snapshot '%s'"), path); 3487 3488 /* validate the target name */ |
2586 if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT)) | 3489 if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) |
2587 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2588 | 3490 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3491 |
3492 if (props) { 3493 if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, 3494 props, B_FALSE, NULL, errbuf)) == NULL) 3495 return (-1); 3496 3497 if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { 3498 nvlist_free(props); 3499 return (-1); 3500 } 3501 3502 nvlist_free(props); 3503 } 3504 |
|
2589 /* make sure the parent exists and is of the appropriate type */ 2590 delim = strchr(path, '@'); | 3505 /* make sure the parent exists and is of the appropriate type */ 3506 delim = strchr(path, '@'); |
2591 if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) 2592 return (-1); | |
2593 (void) strncpy(parent, path, delim - path); 2594 parent[delim - path] = '\0'; 2595 2596 if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 2597 ZFS_TYPE_VOLUME)) == NULL) { | 3507 (void) strncpy(parent, path, delim - path); 3508 parent[delim - path] = '\0'; 3509 3510 if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | 3511 ZFS_TYPE_VOLUME)) == NULL) { |
2598 free(parent); | 3512 zcmd_free_nvlists(&zc); |
2599 return (-1); 2600 } 2601 2602 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2603 (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); | 3513 return (-1); 3514 } 3515 3516 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3517 (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); |
3518 if (ZFS_IS_VOLUME(zhp)) 3519 zc.zc_objset_type = DMU_OST_ZVOL; 3520 else 3521 zc.zc_objset_type = DMU_OST_ZFS; |
|
2604 zc.zc_cookie = recursive; | 3522 zc.zc_cookie = recursive; |
2605 ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc); | 3523 ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc); |
2606 | 3524 |
3525 zcmd_free_nvlists(&zc); 3526 |
|
2607 /* 2608 * if it was recursive, the one that actually failed will be in 2609 * zc.zc_name. 2610 */ | 3527 /* 3528 * if it was recursive, the one that actually failed will be in 3529 * zc.zc_name. 3530 */ |
2611 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2612 "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); | 3531 if (ret != 0) 3532 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 3533 "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); 3534 |
2613 if (ret == 0 && recursive) { 2614 struct createdata cd; 2615 2616 cd.cd_snapname = delim + 1; 2617 cd.cd_ifexists = B_FALSE; 2618 (void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd); 2619 } 2620 if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 2621 ret = zvol_create_link(zhp->zfs_hdl, path); 2622 if (ret != 0) { | 3535 if (ret == 0 && recursive) { 3536 struct createdata cd; 3537 3538 cd.cd_snapname = delim + 1; 3539 cd.cd_ifexists = B_FALSE; 3540 (void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd); 3541 } 3542 if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { 3543 ret = zvol_create_link(zhp->zfs_hdl, path); 3544 if (ret != 0) { |
2623 (void) ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY, 2624 &zc); | 3545 (void) zfs_standard_error(hdl, errno, 3546 dgettext(TEXT_DOMAIN, 3547 "Volume successfully snapshotted, but device links " 3548 "were not created")); 3549 zfs_close(zhp); 3550 return (-1); |
2625 } 2626 } 2627 2628 if (ret != 0) 2629 (void) zfs_standard_error(hdl, errno, errbuf); 2630 | 3551 } 3552 } 3553 3554 if (ret != 0) 3555 (void) zfs_standard_error(hdl, errno, errbuf); 3556 |
2631 free(parent); | |
2632 zfs_close(zhp); 2633 2634 return (ret); 2635} 2636 2637/* | 3557 zfs_close(zhp); 3558 3559 return (ret); 3560} 3561 3562/* |
2638 * Dumps a backup of the given snapshot (incremental from fromsnap if it's not 2639 * NULL) to the file descriptor specified by outfd. 2640 */ 2641int 2642zfs_send(zfs_handle_t *zhp, const char *fromsnap, int outfd) 2643{ 2644 zfs_cmd_t zc = { 0 }; 2645 char errbuf[1024]; 2646 libzfs_handle_t *hdl = zhp->zfs_hdl; 2647 2648 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT); 2649 2650 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 2651 if (fromsnap) 2652 (void) strlcpy(zc.zc_value, fromsnap, sizeof (zc.zc_name)); 2653 zc.zc_cookie = outfd; 2654 2655 if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SENDBACKUP, &zc) != 0) { 2656 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2657 "cannot send '%s'"), zhp->zfs_name); 2658 2659 switch (errno) { 2660 2661 case EXDEV: 2662 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2663 "not an earlier snapshot from the same fs")); 2664 return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); 2665 2666 case EDQUOT: 2667 case EFBIG: 2668 case EIO: 2669 case ENOLINK: 2670 case ENOSPC: 2671 case ENXIO: 2672 case EPIPE: 2673 case ERANGE: 2674 case EFAULT: 2675 case EROFS: 2676 zfs_error_aux(hdl, strerror(errno)); 2677 return (zfs_error(hdl, EZFS_BADBACKUP, errbuf)); 2678 2679 default: 2680 return (zfs_standard_error(hdl, errno, errbuf)); 2681 } 2682 } 2683 2684 return (0); 2685} 2686 2687/* 2688 * Create ancestors of 'target', but not target itself, and not 2689 * ancestors whose names are shorter than prefixlen. Die if 2690 * prefixlen-ancestor does not exist. 2691 */ 2692static int 2693create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) 2694{ 2695 zfs_handle_t *h; 2696 char *cp; 2697 2698 /* make sure prefix exists */ 2699 cp = strchr(target + prefixlen, '/'); 2700 *cp = '\0'; 2701 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2702 *cp = '/'; 2703 if (h == NULL) 2704 return (-1); 2705 zfs_close(h); 2706 2707 /* 2708 * Attempt to create, mount, and share any ancestor filesystems, 2709 * up to the prefixlen-long one. 2710 */ 2711 for (cp = target + prefixlen + 1; 2712 cp = strchr(cp, '/'); *cp = '/', cp++) { 2713 const char *opname; 2714 2715 *cp = '\0'; 2716 2717 h = make_dataset_handle(hdl, target); 2718 if (h) { 2719 /* it already exists, nothing to do here */ 2720 zfs_close(h); 2721 continue; 2722 } 2723 2724 opname = dgettext(TEXT_DOMAIN, "create"); 2725 if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, 2726 NULL) != 0) 2727 goto ancestorerr; 2728 2729 opname = dgettext(TEXT_DOMAIN, "open"); 2730 h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); 2731 if (h == NULL) 2732 goto ancestorerr; 2733 2734 opname = dgettext(TEXT_DOMAIN, "mount"); 2735 if (zfs_mount(h, NULL, 0) != 0) 2736 goto ancestorerr; 2737 2738 opname = dgettext(TEXT_DOMAIN, "share"); 2739 if (zfs_share(h) != 0) 2740 goto ancestorerr; 2741 2742 zfs_close(h); 2743 2744 continue; 2745ancestorerr: 2746 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2747 "failed to %s ancestor '%s'"), opname, target); 2748 return (-1); 2749 } 2750 2751 return (0); 2752} 2753 2754/* 2755 * Restores a backup of tosnap from the file descriptor specified by infd. 2756 */ 2757int 2758zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix, 2759 int verbose, int dryrun, boolean_t force, int infd) 2760{ 2761 zfs_cmd_t zc = { 0 }; 2762 time_t begin_time; 2763 int ioctl_err, err, bytes, size, choplen; 2764 char *cp; 2765 dmu_replay_record_t drr; 2766 struct drr_begin *drrb = &zc.zc_begin_record; 2767 char errbuf[1024]; 2768 prop_changelist_t *clp; 2769 char chopprefix[ZFS_MAXNAMELEN]; 2770 2771 begin_time = time(NULL); 2772 2773 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, 2774 "cannot receive")); 2775 2776 /* read in the BEGIN record */ 2777 cp = (char *)&drr; 2778 bytes = 0; 2779 do { 2780 size = read(infd, cp, sizeof (drr) - bytes); 2781 cp += size; 2782 bytes += size; 2783 } while (size > 0); 2784 2785 if (size < 0 || bytes != sizeof (drr)) { 2786 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2787 "stream (failed to read first record)")); 2788 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2789 } 2790 2791 zc.zc_begin_record = drr.drr_u.drr_begin; 2792 2793 if (drrb->drr_magic != DMU_BACKUP_MAGIC && 2794 drrb->drr_magic != BSWAP_64(DMU_BACKUP_MAGIC)) { 2795 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2796 "stream (bad magic number)")); 2797 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2798 } 2799 2800 if (drrb->drr_version != DMU_BACKUP_VERSION && 2801 drrb->drr_version != BSWAP_64(DMU_BACKUP_VERSION)) { 2802 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only version " 2803 "0x%llx is supported (stream is version 0x%llx)"), 2804 DMU_BACKUP_VERSION, drrb->drr_version); 2805 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2806 } 2807 2808 if (strchr(drr.drr_u.drr_begin.drr_toname, '@') == NULL) { 2809 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2810 "stream (bad snapshot name)")); 2811 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf)); 2812 } 2813 /* 2814 * Determine how much of the snapshot name stored in the stream 2815 * we are going to tack on to the name they specified on the 2816 * command line, and how much we are going to chop off. 2817 * 2818 * If they specified a snapshot, chop the entire name stored in 2819 * the stream. 2820 */ 2821 (void) strcpy(chopprefix, drr.drr_u.drr_begin.drr_toname); 2822 if (isprefix) { 2823 /* 2824 * They specified a fs with -d, we want to tack on 2825 * everything but the pool name stored in the stream 2826 */ 2827 if (strchr(tosnap, '@')) { 2828 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid " 2829 "argument - snapshot not allowed with -d")); 2830 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2831 } 2832 cp = strchr(chopprefix, '/'); 2833 if (cp == NULL) 2834 cp = strchr(chopprefix, '@'); 2835 *cp = '\0'; 2836 } else if (strchr(tosnap, '@') == NULL) { 2837 /* 2838 * If they specified a filesystem without -d, we want to 2839 * tack on everything after the fs specified in the 2840 * first name from the stream. 2841 */ 2842 cp = strchr(chopprefix, '@'); 2843 *cp = '\0'; 2844 } 2845 choplen = strlen(chopprefix); 2846 2847 /* 2848 * Determine name of destination snapshot, store in zc_value. 2849 */ 2850 (void) strcpy(zc.zc_value, tosnap); 2851 (void) strncat(zc.zc_value, drr.drr_u.drr_begin.drr_toname+choplen, 2852 sizeof (zc.zc_value)); 2853 if (!zfs_validate_name(hdl, zc.zc_value, ZFS_TYPE_SNAPSHOT)) 2854 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 2855 2856 (void) strcpy(zc.zc_name, zc.zc_value); 2857 if (drrb->drr_fromguid) { 2858 /* incremental backup stream */ 2859 zfs_handle_t *h; 2860 2861 /* do the recvbackup ioctl to the containing fs */ 2862 *strchr(zc.zc_name, '@') = '\0'; 2863 2864 /* make sure destination fs exists */ 2865 h = zfs_open(hdl, zc.zc_name, 2866 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2867 if (h == NULL) 2868 return (-1); 2869 if (!dryrun) { 2870 /* 2871 * We need to unmount all the dependents of the dataset 2872 * and the dataset itself. If it's a volume 2873 * then remove device link. 2874 */ 2875 if (h->zfs_type == ZFS_TYPE_FILESYSTEM) { 2876 clp = changelist_gather(h, ZFS_PROP_NAME, 0); 2877 if (clp == NULL) 2878 return (-1); 2879 if (changelist_prefix(clp) != 0) { 2880 changelist_free(clp); 2881 return (-1); 2882 } 2883 } else { 2884 (void) zvol_remove_link(hdl, h->zfs_name); 2885 } 2886 } 2887 zfs_close(h); 2888 } else { 2889 /* full backup stream */ 2890 2891 /* Make sure destination fs does not exist */ 2892 *strchr(zc.zc_name, '@') = '\0'; 2893 if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0) { 2894 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2895 "destination '%s' exists"), zc.zc_name); 2896 return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2897 } 2898 2899 if (strchr(zc.zc_name, '/') == NULL) { 2900 /* 2901 * they're trying to do a recv into a 2902 * nonexistant topmost filesystem. 2903 */ 2904 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2905 "destination does not exist"), zc.zc_name); 2906 return (zfs_error(hdl, EZFS_EXISTS, errbuf)); 2907 } 2908 2909 /* Do the recvbackup ioctl to the fs's parent. */ 2910 *strrchr(zc.zc_name, '/') = '\0'; 2911 2912 if (isprefix && (err = create_parents(hdl, 2913 zc.zc_value, strlen(tosnap))) != 0) { 2914 return (zfs_error(hdl, EZFS_BADRESTORE, errbuf)); 2915 } 2916 2917 } 2918 2919 zc.zc_cookie = infd; 2920 zc.zc_guid = force; 2921 if (verbose) { 2922 (void) printf("%s %s stream of %s into %s\n", 2923 dryrun ? "would receive" : "receiving", 2924 drrb->drr_fromguid ? "incremental" : "full", 2925 drr.drr_u.drr_begin.drr_toname, 2926 zc.zc_value); 2927 (void) fflush(stdout); 2928 } 2929 if (dryrun) 2930 return (0); 2931 err = ioctl_err = ioctl(hdl->libzfs_fd, ZFS_IOC_RECVBACKUP, &zc); 2932 if (ioctl_err != 0) { 2933 switch (errno) { 2934 case ENODEV: 2935 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2936 "most recent snapshot does not match incremental " 2937 "source")); 2938 (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2939 break; 2940 case ETXTBSY: 2941 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2942 "destination has been modified since most recent " 2943 "snapshot")); 2944 (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf); 2945 break; 2946 case EEXIST: 2947 if (drrb->drr_fromguid == 0) { 2948 /* it's the containing fs that exists */ 2949 cp = strchr(zc.zc_value, '@'); 2950 *cp = '\0'; 2951 } 2952 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2953 "destination already exists")); 2954 (void) zfs_error_fmt(hdl, EZFS_EXISTS, 2955 dgettext(TEXT_DOMAIN, "cannot restore to %s"), 2956 zc.zc_value); 2957 break; 2958 case EINVAL: 2959 (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2960 break; 2961 case ECKSUM: 2962 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2963 "invalid stream (checksum mismatch)")); 2964 (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf); 2965 break; 2966 default: 2967 (void) zfs_standard_error(hdl, errno, errbuf); 2968 } 2969 } 2970 2971 /* 2972 * Mount or recreate the /dev links for the target filesystem 2973 * (if created, or if we tore them down to do an incremental 2974 * restore), and the /dev links for the new snapshot (if 2975 * created). Also mount any children of the target filesystem 2976 * if we did an incremental receive. 2977 */ 2978 cp = strchr(zc.zc_value, '@'); 2979 if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) { 2980 zfs_handle_t *h; 2981 2982 *cp = '\0'; 2983 h = zfs_open(hdl, zc.zc_value, 2984 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 2985 *cp = '@'; 2986 if (h) { 2987 if (h->zfs_type == ZFS_TYPE_VOLUME) { 2988 err = zvol_create_link(hdl, h->zfs_name); 2989 if (err == 0 && ioctl_err == 0) 2990 err = zvol_create_link(hdl, 2991 zc.zc_value); 2992 } else { 2993 if (drrb->drr_fromguid) { 2994 err = changelist_postfix(clp); 2995 changelist_free(clp); 2996 } else { 2997 err = zfs_mount(h, NULL, 0); 2998 } 2999 } 3000 zfs_close(h); 3001 } 3002 } 3003 3004 if (err || ioctl_err) 3005 return (-1); 3006 3007 if (verbose) { 3008 char buf1[64]; 3009 char buf2[64]; 3010 uint64_t bytes = zc.zc_cookie; 3011 time_t delta = time(NULL) - begin_time; 3012 if (delta == 0) 3013 delta = 1; 3014 zfs_nicenum(bytes, buf1, sizeof (buf1)); 3015 zfs_nicenum(bytes/delta, buf2, sizeof (buf1)); 3016 3017 (void) printf("received %sb stream in %lu seconds (%sb/sec)\n", 3018 buf1, delta, buf2); 3019 } 3020 3021 return (0); 3022} 3023 3024/* | |
3025 * Destroy any more recent snapshots. We invoke this callback on any dependents 3026 * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3027 * is a dependent and we should just destroy it without checking the transaction 3028 * group. 3029 */ 3030typedef struct rollback_data { 3031 const char *cb_target; /* the snapshot */ 3032 uint64_t cb_create; /* creation time reference */ | 3563 * Destroy any more recent snapshots. We invoke this callback on any dependents 3564 * of the snapshot first. If the 'cb_dependent' member is non-zero, then this 3565 * is a dependent and we should just destroy it without checking the transaction 3566 * group. 3567 */ 3568typedef struct rollback_data { 3569 const char *cb_target; /* the snapshot */ 3570 uint64_t cb_create; /* creation time reference */ |
3033 prop_changelist_t *cb_clp; /* changelist pointer */ 3034 int cb_error; | 3571 boolean_t cb_error; |
3035 boolean_t cb_dependent; | 3572 boolean_t cb_dependent; |
3573 boolean_t cb_force; |
|
3036} rollback_data_t; 3037 3038static int 3039rollback_destroy(zfs_handle_t *zhp, void *data) 3040{ 3041 rollback_data_t *cbp = data; 3042 3043 if (!cbp->cb_dependent) { 3044 if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3045 zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3046 zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3047 cbp->cb_create) { | 3574} rollback_data_t; 3575 3576static int 3577rollback_destroy(zfs_handle_t *zhp, void *data) 3578{ 3579 rollback_data_t *cbp = data; 3580 3581 if (!cbp->cb_dependent) { 3582 if (strcmp(zhp->zfs_name, cbp->cb_target) != 0 && 3583 zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && 3584 zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > 3585 cbp->cb_create) { |
3586 char *logstr; |
|
3048 3049 cbp->cb_dependent = B_TRUE; | 3587 3588 cbp->cb_dependent = B_TRUE; |
3050 if (zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, 3051 cbp) != 0) 3052 cbp->cb_error = 1; | 3589 cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE, 3590 rollback_destroy, cbp); |
3053 cbp->cb_dependent = B_FALSE; 3054 | 3591 cbp->cb_dependent = B_FALSE; 3592 |
3055 if (zfs_destroy(zhp) != 0) 3056 cbp->cb_error = 1; 3057 else 3058 changelist_remove(zhp, cbp->cb_clp); | 3593 logstr = zhp->zfs_hdl->libzfs_log_str; 3594 zhp->zfs_hdl->libzfs_log_str = NULL; 3595 cbp->cb_error |= zfs_destroy(zhp); 3596 zhp->zfs_hdl->libzfs_log_str = logstr; |
3059 } 3060 } else { | 3597 } 3598 } else { |
3599 /* We must destroy this clone; first unmount it */ 3600 prop_changelist_t *clp; 3601 3602 clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 3603 cbp->cb_force ? MS_FORCE: 0); 3604 if (clp == NULL || changelist_prefix(clp) != 0) { 3605 cbp->cb_error = B_TRUE; 3606 zfs_close(zhp); 3607 return (0); 3608 } |
|
3061 if (zfs_destroy(zhp) != 0) | 3609 if (zfs_destroy(zhp) != 0) |
3062 cbp->cb_error = 1; | 3610 cbp->cb_error = B_TRUE; |
3063 else | 3611 else |
3064 changelist_remove(zhp, cbp->cb_clp); | 3612 changelist_remove(clp, zhp->zfs_name); 3613 (void) changelist_postfix(clp); 3614 changelist_free(clp); |
3065 } 3066 3067 zfs_close(zhp); 3068 return (0); 3069} 3070 3071/* | 3615 } 3616 3617 zfs_close(zhp); 3618 return (0); 3619} 3620 3621/* |
3072 * Rollback the dataset to its latest snapshot. 3073 */ 3074static int 3075do_rollback(zfs_handle_t *zhp) 3076{ 3077 int ret; 3078 zfs_cmd_t zc = { 0 }; 3079 3080 assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3081 zhp->zfs_type == ZFS_TYPE_VOLUME); 3082 3083 if (zhp->zfs_type == ZFS_TYPE_VOLUME && 3084 zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3085 return (-1); 3086 3087 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3088 3089 if (ZFS_IS_VOLUME(zhp)) 3090 zc.zc_objset_type = DMU_OST_ZVOL; 3091 else 3092 zc.zc_objset_type = DMU_OST_ZFS; 3093 3094 /* 3095 * We rely on the consumer to verify that there are no newer snapshots 3096 * for the given dataset. Given these constraints, we can simply pass 3097 * the name on to the ioctl() call. There is still an unlikely race 3098 * condition where the user has taken a snapshot since we verified that 3099 * this was the most recent. 3100 */ 3101 if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_ROLLBACK, 3102 &zc)) != 0) { 3103 (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3104 dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3105 zhp->zfs_name); 3106 } else if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3107 ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); 3108 } 3109 3110 return (ret); 3111} 3112 3113/* | |
3114 * Given a dataset, rollback to a specific snapshot, discarding any 3115 * data changes since then and making it the active dataset. 3116 * 3117 * Any snapshots more recent than the target are destroyed, along with 3118 * their dependents. 3119 */ 3120int | 3622 * Given a dataset, rollback to a specific snapshot, discarding any 3623 * data changes since then and making it the active dataset. 3624 * 3625 * Any snapshots more recent than the target are destroyed, along with 3626 * their dependents. 3627 */ 3628int |
3121zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, int flag) | 3629zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) |
3122{ | 3630{ |
3123 int ret; | |
3124 rollback_data_t cb = { 0 }; | 3631 rollback_data_t cb = { 0 }; |
3125 prop_changelist_t *clp; | 3632 int err; 3633 zfs_cmd_t zc = { 0 }; 3634 boolean_t restore_resv = 0; 3635 uint64_t old_volsize, new_volsize; 3636 zfs_prop_t resv_prop; |
3126 | 3637 |
3127 /* 3128 * Unmount all dependendents of the dataset and the dataset itself. 3129 * The list we need to gather is the same as for doing rename 3130 */ 3131 clp = changelist_gather(zhp, ZFS_PROP_NAME, flag ? MS_FORCE: 0); 3132 if (clp == NULL) 3133 return (-1); | 3638 assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM || 3639 zhp->zfs_type == ZFS_TYPE_VOLUME); |
3134 | 3640 |
3135 if ((ret = changelist_prefix(clp)) != 0) 3136 goto out; 3137 | |
3138 /* 3139 * Destroy all recent snapshots and its dependends. 3140 */ | 3641 /* 3642 * Destroy all recent snapshots and its dependends. 3643 */ |
3644 cb.cb_force = force; |
|
3141 cb.cb_target = snap->zfs_name; 3142 cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); | 3645 cb.cb_target = snap->zfs_name; 3646 cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); |
3143 cb.cb_clp = clp; | |
3144 (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3145 | 3647 (void) zfs_iter_children(zhp, rollback_destroy, &cb); 3648 |
3146 if ((ret = cb.cb_error) != 0) { 3147 (void) changelist_postfix(clp); 3148 goto out; 3149 } | 3649 if (cb.cb_error) 3650 return (-1); |
3150 3151 /* 3152 * Now that we have verified that the snapshot is the latest, 3153 * rollback to the given snapshot. 3154 */ | 3651 3652 /* 3653 * Now that we have verified that the snapshot is the latest, 3654 * rollback to the given snapshot. 3655 */ |
3155 ret = do_rollback(zhp); | |
3156 | 3656 |
3157 if (ret != 0) { 3158 (void) changelist_postfix(clp); 3159 goto out; | 3657 if (zhp->zfs_type == ZFS_TYPE_VOLUME) { 3658 if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) 3659 return (-1); 3660 if (zfs_which_resv_prop(zhp, &resv_prop) < 0) 3661 return (-1); 3662 old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3663 restore_resv = 3664 (old_volsize == zfs_prop_get_int(zhp, resv_prop)); |
3160 } 3161 | 3665 } 3666 |
3667 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3668 3669 if (ZFS_IS_VOLUME(zhp)) 3670 zc.zc_objset_type = DMU_OST_ZVOL; 3671 else 3672 zc.zc_objset_type = DMU_OST_ZFS; 3673 |
|
3162 /* | 3674 /* |
3163 * We only want to re-mount the filesystem if it was mounted in the 3164 * first place. | 3675 * We rely on zfs_iter_children() to verify that there are no 3676 * newer snapshots for the given dataset. Therefore, we can 3677 * simply pass the name on to the ioctl() call. There is still 3678 * an unlikely race condition where the user has taken a 3679 * snapshot since we verified that this was the most recent. 3680 * |
3165 */ | 3681 */ |
3166 ret = changelist_postfix(clp); | 3682 if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) { 3683 (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, 3684 dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), 3685 zhp->zfs_name); 3686 return (err); 3687 } |
3167 | 3688 |
3168out: 3169 changelist_free(clp); 3170 return (ret); | 3689 /* 3690 * For volumes, if the pre-rollback volsize matched the pre- 3691 * rollback reservation and the volsize has changed then set 3692 * the reservation property to the post-rollback volsize. 3693 * Make a new handle since the rollback closed the dataset. 3694 */ 3695 if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && 3696 (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { 3697 if (err = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name)) { 3698 zfs_close(zhp); 3699 return (err); 3700 } 3701 if (restore_resv) { 3702 new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); 3703 if (old_volsize != new_volsize) 3704 err = zfs_prop_set_int(zhp, resv_prop, 3705 new_volsize); 3706 } 3707 zfs_close(zhp); 3708 } 3709 return (err); |
3171} 3172 3173/* 3174 * Iterate over all dependents for a given dataset. This includes both 3175 * hierarchical dependents (children) and data dependents (snapshots and 3176 * clones). The bulk of the processing occurs in get_dependents() in 3177 * libzfs_graph.c. 3178 */ --- 26 unchanged lines hidden (view full) --- 3205 3206 return (ret); 3207} 3208 3209/* 3210 * Renames the given dataset. 3211 */ 3212int | 3710} 3711 3712/* 3713 * Iterate over all dependents for a given dataset. This includes both 3714 * hierarchical dependents (children) and data dependents (snapshots and 3715 * clones). The bulk of the processing occurs in get_dependents() in 3716 * libzfs_graph.c. 3717 */ --- 26 unchanged lines hidden (view full) --- 3744 3745 return (ret); 3746} 3747 3748/* 3749 * Renames the given dataset. 3750 */ 3751int |
3213zfs_rename(zfs_handle_t *zhp, const char *target, int recursive) | 3752zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) |
3214{ 3215 int ret; 3216 zfs_cmd_t zc = { 0 }; 3217 char *delim; 3218 prop_changelist_t *cl = NULL; 3219 zfs_handle_t *zhrp = NULL; 3220 char *parentname = NULL; 3221 char parent[ZFS_MAXNAMELEN]; --- 35 unchanged lines hidden (view full) --- 3257 != 0 || zhp->zfs_name[delim - target] != '@') { 3258 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3259 "snapshots must be part of same " 3260 "dataset")); 3261 return (zfs_error(hdl, EZFS_CROSSTARGET, 3262 errbuf)); 3263 } 3264 } | 3753{ 3754 int ret; 3755 zfs_cmd_t zc = { 0 }; 3756 char *delim; 3757 prop_changelist_t *cl = NULL; 3758 zfs_handle_t *zhrp = NULL; 3759 char *parentname = NULL; 3760 char parent[ZFS_MAXNAMELEN]; --- 35 unchanged lines hidden (view full) --- 3796 != 0 || zhp->zfs_name[delim - target] != '@') { 3797 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3798 "snapshots must be part of same " 3799 "dataset")); 3800 return (zfs_error(hdl, EZFS_CROSSTARGET, 3801 errbuf)); 3802 } 3803 } |
3265 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) | 3804 if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) |
3266 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3267 } else { 3268 if (recursive) { 3269 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3270 "recursive rename must be a snapshot")); 3271 return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3272 } 3273 | 3805 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3806 } else { 3807 if (recursive) { 3808 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3809 "recursive rename must be a snapshot")); 3810 return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); 3811 } 3812 |
3274 if (!zfs_validate_name(hdl, target, zhp->zfs_type)) | 3813 if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) |
3275 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3276 uint64_t unused; 3277 3278 /* validate parents */ | 3814 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); 3815 uint64_t unused; 3816 3817 /* validate parents */ |
3279 if (check_parents(hdl, target, &unused) != 0) | 3818 if (check_parents(hdl, target, &unused, B_FALSE, NULL) != 0) |
3280 return (-1); 3281 3282 (void) parent_name(target, parent, sizeof (parent)); 3283 3284 /* make sure we're in the same pool */ 3285 verify((delim = strchr(target, '/')) != NULL); 3286 if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3287 zhp->zfs_name[delim - target] != '/') { --- 20 unchanged lines hidden (view full) --- 3308 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3309 "dataset is used in a non-global zone")); 3310 return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3311 } 3312 3313 if (recursive) { 3314 struct destroydata dd; 3315 | 3819 return (-1); 3820 3821 (void) parent_name(target, parent, sizeof (parent)); 3822 3823 /* make sure we're in the same pool */ 3824 verify((delim = strchr(target, '/')) != NULL); 3825 if (strncmp(zhp->zfs_name, target, delim - target) != 0 || 3826 zhp->zfs_name[delim - target] != '/') { --- 20 unchanged lines hidden (view full) --- 3847 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3848 "dataset is used in a non-global zone")); 3849 return (zfs_error(hdl, EZFS_ZONED, errbuf)); 3850 } 3851 3852 if (recursive) { 3853 struct destroydata dd; 3854 |
3316 parentname = strdup(zhp->zfs_name); | 3855 parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); 3856 if (parentname == NULL) { 3857 ret = -1; 3858 goto error; 3859 } |
3317 delim = strchr(parentname, '@'); 3318 *delim = '\0'; | 3860 delim = strchr(parentname, '@'); 3861 *delim = '\0'; |
3319 zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_ANY); | 3862 zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); |
3320 if (zhrp == NULL) { | 3863 if (zhrp == NULL) { |
3321 return (-1); | 3864 ret = -1; 3865 goto error; |
3322 } 3323 3324 dd.snapname = delim + 1; 3325 dd.gotone = B_FALSE; | 3866 } 3867 3868 dd.snapname = delim + 1; 3869 dd.gotone = B_FALSE; |
3326 dd.closezhp = B_FALSE; | 3870 dd.closezhp = B_TRUE; |
3327 3328 /* We remove any zvol links prior to renaming them */ 3329 ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd); 3330 if (ret) { 3331 goto error; 3332 } 3333 } else { | 3871 3872 /* We remove any zvol links prior to renaming them */ 3873 ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd); 3874 if (ret) { 3875 goto error; 3876 } 3877 } else { |
3334 if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0)) == NULL) | 3878 if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL) |
3335 return (-1); 3336 3337 if (changelist_haszonedchild(cl)) { 3338 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3339 "child dataset with inherited mountpoint is used " 3340 "in a non-global zone")); 3341 (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3342 goto error; --- 8 unchanged lines hidden (view full) --- 3351 else 3352 zc.zc_objset_type = DMU_OST_ZFS; 3353 3354 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3355 (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3356 3357 zc.zc_cookie = recursive; 3358 | 3879 return (-1); 3880 3881 if (changelist_haszonedchild(cl)) { 3882 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3883 "child dataset with inherited mountpoint is used " 3884 "in a non-global zone")); 3885 (void) zfs_error(hdl, EZFS_ZONED, errbuf); 3886 goto error; --- 8 unchanged lines hidden (view full) --- 3895 else 3896 zc.zc_objset_type = DMU_OST_ZFS; 3897 3898 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); 3899 (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); 3900 3901 zc.zc_cookie = recursive; 3902 |
3359 if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) { | 3903 if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) { |
3360 /* 3361 * if it was recursive, the one that actually failed will 3362 * be in zc.zc_name 3363 */ 3364 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, | 3904 /* 3905 * if it was recursive, the one that actually failed will 3906 * be in zc.zc_name 3907 */ 3908 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, |
3365 "cannot rename to '%s'"), zc.zc_name); | 3909 "cannot rename '%s'"), zc.zc_name); |
3366 3367 if (recursive && errno == EEXIST) { 3368 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3369 "a child dataset already has a snapshot " 3370 "with the new name")); | 3910 3911 if (recursive && errno == EEXIST) { 3912 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3913 "a child dataset already has a snapshot " 3914 "with the new name")); |
3371 (void) zfs_error(hdl, EZFS_CROSSTARGET, errbuf); | 3915 (void) zfs_error(hdl, EZFS_EXISTS, errbuf); |
3372 } else { 3373 (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3374 } 3375 3376 /* 3377 * On failure, we still want to remount any filesystems that 3378 * were previously mounted, so we don't alter the system state. 3379 */ --- 47 unchanged lines hidden (view full) --- 3427} 3428 3429static int 3430zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists) 3431{ 3432 zfs_cmd_t zc = { 0 }; 3433#if 0 3434 di_devlink_handle_t dhdl; | 3916 } else { 3917 (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); 3918 } 3919 3920 /* 3921 * On failure, we still want to remount any filesystems that 3922 * were previously mounted, so we don't alter the system state. 3923 */ --- 47 unchanged lines hidden (view full) --- 3971} 3972 3973static int 3974zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists) 3975{ 3976 zfs_cmd_t zc = { 0 }; 3977#if 0 3978 di_devlink_handle_t dhdl; |
3979 priv_set_t *priv_effective; 3980 int privileged; |
|
3435#endif 3436 3437 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3438 3439 /* 3440 * Issue the appropriate ioctl. 3441 */ 3442 if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { --- 22 unchanged lines hidden (view full) --- 3465 return (zfs_standard_error_fmt(hdl, errno, 3466 dgettext(TEXT_DOMAIN, "cannot create device links " 3467 "for '%s'"), dataset)); 3468 } 3469 } 3470 3471#if 0 3472 /* | 3981#endif 3982 3983 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 3984 3985 /* 3986 * Issue the appropriate ioctl. 3987 */ 3988 if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { --- 22 unchanged lines hidden (view full) --- 4011 return (zfs_standard_error_fmt(hdl, errno, 4012 dgettext(TEXT_DOMAIN, "cannot create device links " 4013 "for '%s'"), dataset)); 4014 } 4015 } 4016 4017#if 0 4018 /* |
3473 * Call devfsadm and wait for the links to magically appear. | 4019 * If privileged call devfsadm and wait for the links to 4020 * magically appear. 4021 * Otherwise, print out an informational message. |
3474 */ | 4022 */ |
3475 if ((dhdl = di_devlink_init(ZFS_DRIVER, DI_MAKE_LINK)) == NULL) { 3476 zfs_error_aux(hdl, strerror(errno)); 3477 (void) zfs_error_fmt(hdl, EZFS_DEVLINKS, 3478 dgettext(TEXT_DOMAIN, "cannot create device links " 3479 "for '%s'"), dataset); 3480 (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 3481 return (-1); | 4023 4024 priv_effective = priv_allocset(); 4025 (void) getppriv(PRIV_EFFECTIVE, priv_effective); 4026 privileged = (priv_isfullset(priv_effective) == B_TRUE); 4027 priv_freeset(priv_effective); 4028 4029 if (privileged) { 4030 if ((dhdl = di_devlink_init(ZFS_DRIVER, 4031 DI_MAKE_LINK)) == NULL) { 4032 zfs_error_aux(hdl, strerror(errno)); 4033 (void) zfs_error_fmt(hdl, errno, 4034 dgettext(TEXT_DOMAIN, "cannot create device links " 4035 "for '%s'"), dataset); 4036 (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); 4037 return (-1); 4038 } else { 4039 (void) di_devlink_fini(&dhdl); 4040 } |
3482 } else { | 4041 } else { |
3483 (void) di_devlink_fini(&dhdl); | 4042 char pathname[MAXPATHLEN]; 4043 struct stat64 statbuf; 4044 int i; 4045 4046#define MAX_WAIT 10 4047 4048 /* 4049 * This is the poor mans way of waiting for the link 4050 * to show up. If after 10 seconds we still don't 4051 * have it, then print out a message. 4052 */ 4053 (void) snprintf(pathname, sizeof (pathname), "/dev/zvol/dsk/%s", 4054 dataset); 4055 4056 for (i = 0; i != MAX_WAIT; i++) { 4057 if (stat64(pathname, &statbuf) == 0) 4058 break; 4059 (void) sleep(1); 4060 } 4061 if (i == MAX_WAIT) 4062 (void) printf(gettext("%s may not be immediately " 4063 "available\n"), pathname); |
3484 } 3485#endif 3486 3487 return (0); 3488} 3489 3490/* 3491 * Remove a minor node for the given zvol and the associated /dev links. --- 27 unchanged lines hidden (view full) --- 3519 3520nvlist_t * 3521zfs_get_user_props(zfs_handle_t *zhp) 3522{ 3523 return (zhp->zfs_user_props); 3524} 3525 3526/* | 4064 } 4065#endif 4066 4067 return (0); 4068} 4069 4070/* 4071 * Remove a minor node for the given zvol and the associated /dev links. --- 27 unchanged lines hidden (view full) --- 4099 4100nvlist_t * 4101zfs_get_user_props(zfs_handle_t *zhp) 4102{ 4103 return (zhp->zfs_user_props); 4104} 4105 4106/* |
3527 * Given a comma-separated list of properties, contruct a property list 3528 * containing both user-defined and native properties. This function will 3529 * return a NULL list if 'all' is specified, which can later be expanded on a 3530 * per-dataset basis by zfs_expand_proplist(). 3531 */ 3532int 3533zfs_get_proplist_common(libzfs_handle_t *hdl, char *fields, 3534 zfs_proplist_t **listp, zfs_type_t type) 3535{ 3536 size_t len; 3537 char *s, *p; 3538 char c; 3539 zfs_prop_t prop; 3540 zfs_proplist_t *entry; 3541 zfs_proplist_t **last; 3542 3543 *listp = NULL; 3544 last = listp; 3545 3546 /* 3547 * If 'all' is specified, return a NULL list. 3548 */ 3549 if (strcmp(fields, "all") == 0) 3550 return (0); 3551 3552 /* 3553 * If no fields were specified, return an error. 3554 */ 3555 if (fields[0] == '\0') { 3556 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3557 "no properties specified")); 3558 return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, 3559 "bad property list"))); 3560 } 3561 3562 /* 3563 * It would be nice to use getsubopt() here, but the inclusion of column 3564 * aliases makes this more effort than it's worth. 3565 */ 3566 s = fields; 3567 while (*s != '\0') { 3568 if ((p = strchr(s, ',')) == NULL) { 3569 len = strlen(s); 3570 p = s + len; 3571 } else { 3572 len = p - s; 3573 } 3574 3575 /* 3576 * Check for empty options. 3577 */ 3578 if (len == 0) { 3579 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3580 "empty property name")); 3581 return (zfs_error(hdl, EZFS_BADPROP, 3582 dgettext(TEXT_DOMAIN, "bad property list"))); 3583 } 3584 3585 /* 3586 * Check all regular property names. 3587 */ 3588 c = s[len]; 3589 s[len] = '\0'; 3590 prop = zfs_name_to_prop_common(s, type); 3591 3592 if (prop != ZFS_PROP_INVAL && 3593 !zfs_prop_valid_for_type(prop, type)) 3594 prop = ZFS_PROP_INVAL; 3595 3596 /* 3597 * When no property table entry can be found, return failure if 3598 * this is a pool property or if this isn't a user-defined 3599 * dataset property, 3600 */ 3601 if (prop == ZFS_PROP_INVAL && 3602 (type & ZFS_TYPE_POOL || !zfs_prop_user(s))) { 3603 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3604 "invalid property '%s'"), s); 3605 return (zfs_error(hdl, EZFS_BADPROP, 3606 dgettext(TEXT_DOMAIN, "bad property list"))); 3607 } 3608 3609 if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL) 3610 return (-1); 3611 3612 entry->pl_prop = prop; 3613 if (prop == ZFS_PROP_INVAL) { 3614 if ((entry->pl_user_prop = 3615 zfs_strdup(hdl, s)) == NULL) { 3616 free(entry); 3617 return (-1); 3618 } 3619 entry->pl_width = strlen(s); 3620 } else { 3621 entry->pl_width = zfs_prop_width(prop, 3622 &entry->pl_fixed); 3623 } 3624 3625 *last = entry; 3626 last = &entry->pl_next; 3627 3628 s = p; 3629 if (c == ',') 3630 s++; 3631 } 3632 3633 return (0); 3634} 3635 3636int 3637zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp) 3638{ 3639 return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_ANY)); 3640} 3641 3642void 3643zfs_free_proplist(zfs_proplist_t *pl) 3644{ 3645 zfs_proplist_t *next; 3646 3647 while (pl != NULL) { 3648 next = pl->pl_next; 3649 free(pl->pl_user_prop); 3650 free(pl); 3651 pl = next; 3652 } 3653} 3654 3655typedef struct expand_data { 3656 zfs_proplist_t **last; 3657 libzfs_handle_t *hdl; 3658} expand_data_t; 3659 3660static zfs_prop_t 3661zfs_expand_proplist_cb(zfs_prop_t prop, void *cb) 3662{ 3663 zfs_proplist_t *entry; 3664 expand_data_t *edp = cb; 3665 3666 if ((entry = zfs_alloc(edp->hdl, sizeof (zfs_proplist_t))) == NULL) 3667 return (ZFS_PROP_INVAL); 3668 3669 entry->pl_prop = prop; 3670 entry->pl_width = zfs_prop_width(prop, &entry->pl_fixed); 3671 entry->pl_all = B_TRUE; 3672 3673 *(edp->last) = entry; 3674 edp->last = &entry->pl_next; 3675 3676 return (ZFS_PROP_CONT); 3677} 3678 3679int 3680zfs_expand_proplist_common(libzfs_handle_t *hdl, zfs_proplist_t **plp, 3681 zfs_type_t type) 3682{ 3683 zfs_proplist_t *entry; 3684 zfs_proplist_t **last; 3685 expand_data_t exp; 3686 3687 if (*plp == NULL) { 3688 /* 3689 * If this is the very first time we've been called for an 'all' 3690 * specification, expand the list to include all native 3691 * properties. 3692 */ 3693 last = plp; 3694 3695 exp.last = last; 3696 exp.hdl = hdl; 3697 3698 if (zfs_prop_iter_common(zfs_expand_proplist_cb, &exp, type, 3699 B_FALSE) == ZFS_PROP_INVAL) 3700 return (-1); 3701 3702 /* 3703 * Add 'name' to the beginning of the list, which is handled 3704 * specially. 3705 */ 3706 if ((entry = zfs_alloc(hdl, 3707 sizeof (zfs_proplist_t))) == NULL) 3708 return (-1); 3709 3710 entry->pl_prop = ZFS_PROP_NAME; 3711 entry->pl_width = zfs_prop_width(ZFS_PROP_NAME, 3712 &entry->pl_fixed); 3713 entry->pl_all = B_TRUE; 3714 entry->pl_next = *plp; 3715 *plp = entry; 3716 } 3717 return (0); 3718} 3719 3720/* | |
3721 * This function is used by 'zfs list' to determine the exact set of columns to 3722 * display, and their maximum widths. This does two main things: 3723 * 3724 * - If this is a list of all properties, then expand the list to include 3725 * all native properties, and set a flag so that for each dataset we look 3726 * for new unique user properties and add them to the list. 3727 * 3728 * - For non fixed-width properties, keep track of the maximum width seen 3729 * so that we can size the column appropriately. 3730 */ 3731int | 4107 * This function is used by 'zfs list' to determine the exact set of columns to 4108 * display, and their maximum widths. This does two main things: 4109 * 4110 * - If this is a list of all properties, then expand the list to include 4111 * all native properties, and set a flag so that for each dataset we look 4112 * for new unique user properties and add them to the list. 4113 * 4114 * - For non fixed-width properties, keep track of the maximum width seen 4115 * so that we can size the column appropriately. 4116 */ 4117int |
3732zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp) | 4118zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp) |
3733{ 3734 libzfs_handle_t *hdl = zhp->zfs_hdl; | 4119{ 4120 libzfs_handle_t *hdl = zhp->zfs_hdl; |
3735 zfs_proplist_t *entry; 3736 zfs_proplist_t **last, **start; | 4121 zprop_list_t *entry; 4122 zprop_list_t **last, **start; |
3737 nvlist_t *userprops, *propval; 3738 nvpair_t *elem; 3739 char *strval; 3740 char buf[ZFS_MAXPROPLEN]; 3741 | 4123 nvlist_t *userprops, *propval; 4124 nvpair_t *elem; 4125 char *strval; 4126 char buf[ZFS_MAXPROPLEN]; 4127 |
3742 if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_ANY) != 0) | 4128 if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0) |
3743 return (-1); 3744 3745 userprops = zfs_get_user_props(zhp); 3746 3747 entry = *plp; 3748 if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 3749 /* 3750 * Go through and add any user properties as necessary. We 3751 * start by incrementing our list pointer to the first 3752 * non-native property. 3753 */ 3754 start = plp; 3755 while (*start != NULL) { | 4129 return (-1); 4130 4131 userprops = zfs_get_user_props(zhp); 4132 4133 entry = *plp; 4134 if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) { 4135 /* 4136 * Go through and add any user properties as necessary. We 4137 * start by incrementing our list pointer to the first 4138 * non-native property. 4139 */ 4140 start = plp; 4141 while (*start != NULL) { |
3756 if ((*start)->pl_prop == ZFS_PROP_INVAL) | 4142 if ((*start)->pl_prop == ZPROP_INVAL) |
3757 break; 3758 start = &(*start)->pl_next; 3759 } 3760 3761 elem = NULL; 3762 while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 3763 /* 3764 * See if we've already found this property in our list. 3765 */ 3766 for (last = start; *last != NULL; 3767 last = &(*last)->pl_next) { 3768 if (strcmp((*last)->pl_user_prop, 3769 nvpair_name(elem)) == 0) 3770 break; 3771 } 3772 3773 if (*last == NULL) { 3774 if ((entry = zfs_alloc(hdl, | 4143 break; 4144 start = &(*start)->pl_next; 4145 } 4146 4147 elem = NULL; 4148 while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) { 4149 /* 4150 * See if we've already found this property in our list. 4151 */ 4152 for (last = start; *last != NULL; 4153 last = &(*last)->pl_next) { 4154 if (strcmp((*last)->pl_user_prop, 4155 nvpair_name(elem)) == 0) 4156 break; 4157 } 4158 4159 if (*last == NULL) { 4160 if ((entry = zfs_alloc(hdl, |
3775 sizeof (zfs_proplist_t))) == NULL || | 4161 sizeof (zprop_list_t))) == NULL || |
3776 ((entry->pl_user_prop = zfs_strdup(hdl, 3777 nvpair_name(elem)))) == NULL) { 3778 free(entry); 3779 return (-1); 3780 } 3781 | 4162 ((entry->pl_user_prop = zfs_strdup(hdl, 4163 nvpair_name(elem)))) == NULL) { 4164 free(entry); 4165 return (-1); 4166 } 4167 |
3782 entry->pl_prop = ZFS_PROP_INVAL; | 4168 entry->pl_prop = ZPROP_INVAL; |
3783 entry->pl_width = strlen(nvpair_name(elem)); 3784 entry->pl_all = B_TRUE; 3785 *last = entry; 3786 } 3787 } 3788 } 3789 3790 /* 3791 * Now go through and check the width of any non-fixed columns 3792 */ 3793 for (entry = *plp; entry != NULL; entry = entry->pl_next) { 3794 if (entry->pl_fixed) 3795 continue; 3796 | 4169 entry->pl_width = strlen(nvpair_name(elem)); 4170 entry->pl_all = B_TRUE; 4171 *last = entry; 4172 } 4173 } 4174 } 4175 4176 /* 4177 * Now go through and check the width of any non-fixed columns 4178 */ 4179 for (entry = *plp; entry != NULL; entry = entry->pl_next) { 4180 if (entry->pl_fixed) 4181 continue; 4182 |
3797 if (entry->pl_prop != ZFS_PROP_INVAL) { | 4183 if (entry->pl_prop != ZPROP_INVAL) { |
3798 if (zfs_prop_get(zhp, entry->pl_prop, 3799 buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 3800 if (strlen(buf) > entry->pl_width) 3801 entry->pl_width = strlen(buf); 3802 } 3803 } else if (nvlist_lookup_nvlist(userprops, 3804 entry->pl_user_prop, &propval) == 0) { 3805 verify(nvlist_lookup_string(propval, | 4184 if (zfs_prop_get(zhp, entry->pl_prop, 4185 buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) { 4186 if (strlen(buf) > entry->pl_width) 4187 entry->pl_width = strlen(buf); 4188 } 4189 } else if (nvlist_lookup_nvlist(userprops, 4190 entry->pl_user_prop, &propval) == 0) { 4191 verify(nvlist_lookup_string(propval, |
3806 ZFS_PROP_VALUE, &strval) == 0); | 4192 ZPROP_VALUE, &strval) == 0); |
3807 if (strlen(strval) > entry->pl_width) 3808 entry->pl_width = strlen(strval); 3809 } 3810 } 3811 3812 return (0); 3813} 3814 | 4193 if (strlen(strval) > entry->pl_width) 4194 entry->pl_width = strlen(strval); 4195 } 4196 } 4197 4198 return (0); 4199} 4200 |
4201#ifdef TODO 4202int 4203zfs_iscsi_perm_check(libzfs_handle_t *hdl, char *dataset, ucred_t *cred) 4204{ 4205 zfs_cmd_t zc = { 0 }; 4206 nvlist_t *nvp; 4207 gid_t gid; 4208 uid_t uid; 4209 const gid_t *groups; 4210 int group_cnt; 4211 int error; 4212 4213 if (nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0) != 0) 4214 return (no_memory(hdl)); 4215 4216 uid = ucred_geteuid(cred); 4217 gid = ucred_getegid(cred); 4218 group_cnt = ucred_getgroups(cred, &groups); 4219 4220 if (uid == (uid_t)-1 || gid == (uid_t)-1 || group_cnt == (uid_t)-1) 4221 return (1); 4222 4223 if (nvlist_add_uint32(nvp, ZFS_DELEG_PERM_UID, uid) != 0) { 4224 nvlist_free(nvp); 4225 return (1); 4226 } 4227 4228 if (nvlist_add_uint32(nvp, ZFS_DELEG_PERM_GID, gid) != 0) { 4229 nvlist_free(nvp); 4230 return (1); 4231 } 4232 4233 if (nvlist_add_uint32_array(nvp, 4234 ZFS_DELEG_PERM_GROUPS, (uint32_t *)groups, group_cnt) != 0) { 4235 nvlist_free(nvp); 4236 return (1); 4237 } 4238 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4239 4240 if (zcmd_write_src_nvlist(hdl, &zc, nvp)) 4241 return (-1); 4242 4243 error = ioctl(hdl->libzfs_fd, ZFS_IOC_ISCSI_PERM_CHECK, &zc); 4244 nvlist_free(nvp); 4245 return (error); 4246} 4247#endif 4248 4249int 4250zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, 4251 void *export, void *sharetab, int sharemax, zfs_share_op_t operation) 4252{ 4253 zfs_cmd_t zc = { 0 }; 4254 int error; 4255 4256 (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); 4257 (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); 4258 zc.zc_share.z_sharedata = (uint64_t)(uintptr_t)sharetab; 4259 zc.zc_share.z_exportdata = (uint64_t)(uintptr_t)export; 4260 zc.zc_share.z_sharetype = operation; 4261 zc.zc_share.z_sharemax = sharemax; 4262 4263 error = ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); 4264 return (error); 4265} 4266 |
|
3815/* 3816 * Attach/detach the given filesystem to/from the given jail. 3817 */ 3818int 3819zfs_jail(zfs_handle_t *zhp, int jailid, int attach) 3820{ 3821 libzfs_handle_t *hdl = zhp->zfs_hdl; 3822 zfs_cmd_t zc = { 0 }; --- 33 unchanged lines hidden --- | 4267/* 4268 * Attach/detach the given filesystem to/from the given jail. 4269 */ 4270int 4271zfs_jail(zfs_handle_t *zhp, int jailid, int attach) 4272{ 4273 libzfs_handle_t *hdl = zhp->zfs_hdl; 4274 zfs_cmd_t zc = { 0 }; --- 33 unchanged lines hidden --- |