Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/cmd/zfs/zfs_main.c
48287 views
1
// SPDX-License-Identifier: CDDL-1.0
2
/*
3
* CDDL HEADER START
4
*
5
* The contents of this file are subject to the terms of the
6
* Common Development and Distribution License (the "License").
7
* You may not use this file except in compliance with the License.
8
*
9
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10
* or https://opensource.org/licenses/CDDL-1.0.
11
* See the License for the specific language governing permissions
12
* and limitations under the License.
13
*
14
* When distributing Covered Code, include this CDDL HEADER in each
15
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16
* If applicable, add the following below this CDDL HEADER, with the
17
* fields enclosed by brackets "[]" replaced with your own identifying
18
* information: Portions Copyright [yyyy] [name of copyright owner]
19
*
20
* CDDL HEADER END
21
*/
22
23
/*
24
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
25
* Copyright (c) 2011, 2020 by Delphix. All rights reserved.
26
* Copyright 2012 Milan Jurik. All rights reserved.
27
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
28
* Copyright (c) 2013 Steven Hartland. All rights reserved.
29
* Copyright 2016 Igor Kozhukhov <[email protected]>.
30
* Copyright 2016 Nexenta Systems, Inc.
31
* Copyright (c) 2019 Datto Inc.
32
* Copyright (c) 2019, loli10K <[email protected]>
33
* Copyright 2019 Joyent, Inc.
34
* Copyright (c) 2019, 2020 by Christian Schwarz. All rights reserved.
35
*/
36
37
#include <assert.h>
38
#include <ctype.h>
39
#include <sys/debug.h>
40
#include <dirent.h>
41
#include <errno.h>
42
#include <getopt.h>
43
#include <libgen.h>
44
#include <libintl.h>
45
#include <libuutil.h>
46
#include <libnvpair.h>
47
#include <locale.h>
48
#include <stddef.h>
49
#include <stdio.h>
50
#include <stdlib.h>
51
#include <string.h>
52
#include <unistd.h>
53
#include <fcntl.h>
54
#include <zone.h>
55
#include <grp.h>
56
#include <pwd.h>
57
#include <umem.h>
58
#include <pthread.h>
59
#include <signal.h>
60
#include <sys/list.h>
61
#include <sys/mkdev.h>
62
#include <sys/mntent.h>
63
#include <sys/mnttab.h>
64
#include <sys/mount.h>
65
#include <sys/stat.h>
66
#include <sys/fs/zfs.h>
67
#include <sys/systeminfo.h>
68
#include <sys/types.h>
69
#include <time.h>
70
#include <sys/zfs_project.h>
71
72
#include <libzfs.h>
73
#include <libzfs_core.h>
74
#include <zfs_prop.h>
75
#include <zfs_deleg.h>
76
#include <libzutil.h>
77
#ifdef HAVE_IDMAP
78
#include <aclutils.h>
79
#include <directory.h>
80
#endif /* HAVE_IDMAP */
81
82
#include "zfs_iter.h"
83
#include "zfs_util.h"
84
#include "zfs_comutil.h"
85
#include "zfs_projectutil.h"
86
87
libzfs_handle_t *g_zfs;
88
89
static char history_str[HIS_MAX_RECORD_LEN];
90
static boolean_t log_history = B_TRUE;
91
92
static int zfs_do_clone(int argc, char **argv);
93
static int zfs_do_create(int argc, char **argv);
94
static int zfs_do_destroy(int argc, char **argv);
95
static int zfs_do_get(int argc, char **argv);
96
static int zfs_do_inherit(int argc, char **argv);
97
static int zfs_do_list(int argc, char **argv);
98
static int zfs_do_mount(int argc, char **argv);
99
static int zfs_do_rename(int argc, char **argv);
100
static int zfs_do_rollback(int argc, char **argv);
101
static int zfs_do_set(int argc, char **argv);
102
static int zfs_do_upgrade(int argc, char **argv);
103
static int zfs_do_snapshot(int argc, char **argv);
104
static int zfs_do_unmount(int argc, char **argv);
105
static int zfs_do_share(int argc, char **argv);
106
static int zfs_do_unshare(int argc, char **argv);
107
static int zfs_do_send(int argc, char **argv);
108
static int zfs_do_receive(int argc, char **argv);
109
static int zfs_do_promote(int argc, char **argv);
110
static int zfs_do_userspace(int argc, char **argv);
111
static int zfs_do_allow(int argc, char **argv);
112
static int zfs_do_unallow(int argc, char **argv);
113
static int zfs_do_hold(int argc, char **argv);
114
static int zfs_do_holds(int argc, char **argv);
115
static int zfs_do_release(int argc, char **argv);
116
static int zfs_do_diff(int argc, char **argv);
117
static int zfs_do_bookmark(int argc, char **argv);
118
static int zfs_do_channel_program(int argc, char **argv);
119
static int zfs_do_load_key(int argc, char **argv);
120
static int zfs_do_unload_key(int argc, char **argv);
121
static int zfs_do_change_key(int argc, char **argv);
122
static int zfs_do_project(int argc, char **argv);
123
static int zfs_do_version(int argc, char **argv);
124
static int zfs_do_redact(int argc, char **argv);
125
static int zfs_do_rewrite(int argc, char **argv);
126
static int zfs_do_wait(int argc, char **argv);
127
128
#ifdef __FreeBSD__
129
static int zfs_do_jail(int argc, char **argv);
130
static int zfs_do_unjail(int argc, char **argv);
131
#endif
132
133
#ifdef __linux__
134
static int zfs_do_zone(int argc, char **argv);
135
static int zfs_do_unzone(int argc, char **argv);
136
#endif
137
138
static int zfs_do_help(int argc, char **argv);
139
140
enum zfs_options {
141
ZFS_OPTION_JSON_NUMS_AS_INT = 1024
142
};
143
144
/*
145
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
146
*/
147
148
#ifdef DEBUG
149
const char *
150
_umem_debug_init(void)
151
{
152
return ("default,verbose"); /* $UMEM_DEBUG setting */
153
}
154
155
const char *
156
_umem_logging_init(void)
157
{
158
return ("fail,contents"); /* $UMEM_LOGGING setting */
159
}
160
#endif
161
162
typedef enum {
163
HELP_CLONE,
164
HELP_CREATE,
165
HELP_DESTROY,
166
HELP_GET,
167
HELP_INHERIT,
168
HELP_UPGRADE,
169
HELP_LIST,
170
HELP_MOUNT,
171
HELP_PROMOTE,
172
HELP_RECEIVE,
173
HELP_RENAME,
174
HELP_ROLLBACK,
175
HELP_SEND,
176
HELP_SET,
177
HELP_SHARE,
178
HELP_SNAPSHOT,
179
HELP_UNMOUNT,
180
HELP_UNSHARE,
181
HELP_ALLOW,
182
HELP_UNALLOW,
183
HELP_USERSPACE,
184
HELP_GROUPSPACE,
185
HELP_PROJECTSPACE,
186
HELP_PROJECT,
187
HELP_HOLD,
188
HELP_HOLDS,
189
HELP_RELEASE,
190
HELP_DIFF,
191
HELP_BOOKMARK,
192
HELP_CHANNEL_PROGRAM,
193
HELP_LOAD_KEY,
194
HELP_UNLOAD_KEY,
195
HELP_CHANGE_KEY,
196
HELP_VERSION,
197
HELP_REDACT,
198
HELP_REWRITE,
199
HELP_JAIL,
200
HELP_UNJAIL,
201
HELP_WAIT,
202
HELP_ZONE,
203
HELP_UNZONE,
204
} zfs_help_t;
205
206
typedef struct zfs_command {
207
const char *name;
208
int (*func)(int argc, char **argv);
209
zfs_help_t usage;
210
} zfs_command_t;
211
212
/*
213
* Master command table. Each ZFS command has a name, associated function, and
214
* usage message. The usage messages need to be internationalized, so we have
215
* to have a function to return the usage message based on a command index.
216
*
217
* These commands are organized according to how they are displayed in the usage
218
* message. An empty command (one with a NULL name) indicates an empty line in
219
* the generic usage message.
220
*/
221
static zfs_command_t command_table[] = {
222
{ "version", zfs_do_version, HELP_VERSION },
223
{ NULL },
224
{ "create", zfs_do_create, HELP_CREATE },
225
{ "destroy", zfs_do_destroy, HELP_DESTROY },
226
{ NULL },
227
{ "snapshot", zfs_do_snapshot, HELP_SNAPSHOT },
228
{ "rollback", zfs_do_rollback, HELP_ROLLBACK },
229
{ "clone", zfs_do_clone, HELP_CLONE },
230
{ "promote", zfs_do_promote, HELP_PROMOTE },
231
{ "rename", zfs_do_rename, HELP_RENAME },
232
{ "bookmark", zfs_do_bookmark, HELP_BOOKMARK },
233
{ "diff", zfs_do_diff, HELP_DIFF },
234
{ NULL },
235
{ "list", zfs_do_list, HELP_LIST },
236
{ NULL },
237
{ "set", zfs_do_set, HELP_SET },
238
{ "get", zfs_do_get, HELP_GET },
239
{ "inherit", zfs_do_inherit, HELP_INHERIT },
240
{ "upgrade", zfs_do_upgrade, HELP_UPGRADE },
241
{ NULL },
242
{ "userspace", zfs_do_userspace, HELP_USERSPACE },
243
{ "groupspace", zfs_do_userspace, HELP_GROUPSPACE },
244
{ "projectspace", zfs_do_userspace, HELP_PROJECTSPACE },
245
{ NULL },
246
{ "project", zfs_do_project, HELP_PROJECT },
247
{ NULL },
248
{ "mount", zfs_do_mount, HELP_MOUNT },
249
{ "unmount", zfs_do_unmount, HELP_UNMOUNT },
250
{ "share", zfs_do_share, HELP_SHARE },
251
{ "unshare", zfs_do_unshare, HELP_UNSHARE },
252
{ NULL },
253
{ "send", zfs_do_send, HELP_SEND },
254
{ "receive", zfs_do_receive, HELP_RECEIVE },
255
{ "redact", zfs_do_redact, HELP_REDACT },
256
{ NULL },
257
{ "allow", zfs_do_allow, HELP_ALLOW },
258
{ "unallow", zfs_do_unallow, HELP_UNALLOW },
259
{ NULL },
260
{ "hold", zfs_do_hold, HELP_HOLD },
261
{ "holds", zfs_do_holds, HELP_HOLDS },
262
{ "release", zfs_do_release, HELP_RELEASE },
263
{ NULL },
264
{ "load-key", zfs_do_load_key, HELP_LOAD_KEY },
265
{ "unload-key", zfs_do_unload_key, HELP_UNLOAD_KEY },
266
{ "change-key", zfs_do_change_key, HELP_CHANGE_KEY },
267
{ NULL },
268
{ "program", zfs_do_channel_program, HELP_CHANNEL_PROGRAM },
269
{ "rewrite", zfs_do_rewrite, HELP_REWRITE },
270
{ "wait", zfs_do_wait, HELP_WAIT },
271
272
#ifdef __FreeBSD__
273
{ NULL },
274
{ "jail", zfs_do_jail, HELP_JAIL },
275
{ "unjail", zfs_do_unjail, HELP_UNJAIL },
276
#endif
277
278
#ifdef __linux__
279
{ NULL },
280
{ "zone", zfs_do_zone, HELP_ZONE },
281
{ "unzone", zfs_do_unzone, HELP_UNZONE },
282
#endif
283
};
284
285
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
286
287
#define MAX_CMD_LEN 256
288
289
zfs_command_t *current_command;
290
291
static const char *
292
get_usage(zfs_help_t idx)
293
{
294
switch (idx) {
295
case HELP_CLONE:
296
return (gettext("\tclone [-p] [-o property=value] ... "
297
"<snapshot> <filesystem|volume>\n"));
298
case HELP_CREATE:
299
return (gettext("\tcreate [-Pnpuv] [-o property=value] ... "
300
"<filesystem>\n"
301
"\tcreate [-Pnpsv] [-b blocksize] [-o property=value] ... "
302
"-V <size> <volume>\n"));
303
case HELP_DESTROY:
304
return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
305
"\tdestroy [-dnpRrv] "
306
"<filesystem|volume>@<snap>[%<snap>][,...]\n"
307
"\tdestroy <filesystem|volume>#<bookmark>\n"));
308
case HELP_GET:
309
return (gettext("\tget [-rHp] [-j [--json-int]] [-d max] "
310
"[-o \"all\" | field[,...]]\n"
311
"\t [-t type[,...]] [-s source[,...]]\n"
312
"\t <\"all\" | property[,...]> "
313
"[filesystem|volume|snapshot|bookmark] ...\n"));
314
case HELP_INHERIT:
315
return (gettext("\tinherit [-rS] <property> "
316
"<filesystem|volume|snapshot> ...\n"));
317
case HELP_UPGRADE:
318
return (gettext("\tupgrade [-v]\n"
319
"\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
320
case HELP_LIST:
321
return (gettext("\tlist [-Hp] [-j [--json-int]] [-r|-d max] "
322
"[-o property[,...]] [-s property]...\n\t "
323
"[-S property]... [-t type[,...]] "
324
"[filesystem|volume|snapshot] ...\n"));
325
case HELP_MOUNT:
326
return (gettext("\tmount [-j]\n"
327
"\tmount [-flvO] [-o opts] <-a|-R filesystem|"
328
"filesystem>\n"));
329
case HELP_PROMOTE:
330
return (gettext("\tpromote <clone-filesystem>\n"));
331
case HELP_RECEIVE:
332
return (gettext("\treceive [-vMnsFhu] "
333
"[-o <property>=<value>] ... [-x <property>] ...\n"
334
"\t <filesystem|volume|snapshot>\n"
335
"\treceive [-vMnsFhu] [-o <property>=<value>] ... "
336
"[-x <property>] ... \n"
337
"\t [-d | -e] <filesystem>\n"
338
"\treceive -A <filesystem|volume>\n"));
339
case HELP_RENAME:
340
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
341
"<filesystem|volume|snapshot>\n"
342
"\trename -p [-f] <filesystem|volume> <filesystem|volume>\n"
343
"\trename -u [-f] <filesystem> <filesystem>\n"
344
"\trename -r <snapshot> <snapshot>\n"));
345
case HELP_ROLLBACK:
346
return (gettext("\trollback [-rRf] <snapshot>\n"));
347
case HELP_SEND:
348
return (gettext("\tsend [-DLPbcehnpsVvw] "
349
"[-i|-I snapshot]\n"
350
"\t [-R [-X dataset[,dataset]...]] <snapshot>\n"
351
"\tsend [-DnVvPLecw] [-i snapshot|bookmark] "
352
"<filesystem|volume|snapshot>\n"
353
"\tsend [-DnPpVvLec] [-i bookmark|snapshot] "
354
"--redact <bookmark> <snapshot>\n"
355
"\tsend [-nVvPe] -t <receive_resume_token>\n"
356
"\tsend [-PnVv] --saved filesystem\n"));
357
case HELP_SET:
358
return (gettext("\tset [-u] <property=value> ... "
359
"<filesystem|volume|snapshot> ...\n"));
360
case HELP_SHARE:
361
return (gettext("\tshare [-l] <-a [nfs|smb] | filesystem>\n"));
362
case HELP_SNAPSHOT:
363
return (gettext("\tsnapshot [-r] [-o property=value] ... "
364
"<filesystem|volume>@<snap> ...\n"));
365
case HELP_UNMOUNT:
366
return (gettext("\tunmount [-fu] "
367
"<-a | filesystem|mountpoint>\n"));
368
case HELP_UNSHARE:
369
return (gettext("\tunshare "
370
"<-a [nfs|smb] | filesystem|mountpoint>\n"));
371
case HELP_ALLOW:
372
return (gettext("\tallow <filesystem|volume>\n"
373
"\tallow [-ldug] "
374
"<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
375
"\t <filesystem|volume>\n"
376
"\tallow [-ld] -e <perm|@setname>[,...] "
377
"<filesystem|volume>\n"
378
"\tallow -c <perm|@setname>[,...] <filesystem|volume>\n"
379
"\tallow -s @setname <perm|@setname>[,...] "
380
"<filesystem|volume>\n"));
381
case HELP_UNALLOW:
382
return (gettext("\tunallow [-rldug] "
383
"<\"everyone\"|user|group>[,...]\n"
384
"\t [<perm|@setname>[,...]] <filesystem|volume>\n"
385
"\tunallow [-rld] -e [<perm|@setname>[,...]] "
386
"<filesystem|volume>\n"
387
"\tunallow [-r] -c [<perm|@setname>[,...]] "
388
"<filesystem|volume>\n"
389
"\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
390
"<filesystem|volume>\n"));
391
case HELP_USERSPACE:
392
return (gettext("\tuserspace [-Hinp] [-o field[,...]] "
393
"[-s field] ...\n"
394
"\t [-S field] ... [-t type[,...]] "
395
"<filesystem|snapshot|path>\n"));
396
case HELP_GROUPSPACE:
397
return (gettext("\tgroupspace [-Hinp] [-o field[,...]] "
398
"[-s field] ...\n"
399
"\t [-S field] ... [-t type[,...]] "
400
"<filesystem|snapshot|path>\n"));
401
case HELP_PROJECTSPACE:
402
return (gettext("\tprojectspace [-Hp] [-o field[,...]] "
403
"[-s field] ... \n"
404
"\t [-S field] ... <filesystem|snapshot|path>\n"));
405
case HELP_PROJECT:
406
return (gettext("\tproject [-d|-r] <directory|file ...>\n"
407
"\tproject -c [-0] [-d|-r] [-p id] <directory|file ...>\n"
408
"\tproject -C [-k] [-r] <directory ...>\n"
409
"\tproject [-p id] [-r] [-s] <directory ...>\n"));
410
case HELP_HOLD:
411
return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
412
case HELP_HOLDS:
413
return (gettext("\tholds [-rHp] <snapshot> ...\n"));
414
case HELP_RELEASE:
415
return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
416
case HELP_DIFF:
417
return (gettext("\tdiff [-FHth] <snapshot> "
418
"[snapshot|filesystem]\n"));
419
case HELP_BOOKMARK:
420
return (gettext("\tbookmark <snapshot|bookmark> "
421
"<newbookmark>\n"));
422
case HELP_CHANNEL_PROGRAM:
423
return (gettext("\tprogram [-jn] [-t <instruction limit>] "
424
"[-m <memory limit (b)>]\n"
425
"\t <pool> <program file> [lua args...]\n"));
426
case HELP_LOAD_KEY:
427
return (gettext("\tload-key [-rn] [-L <keylocation>] "
428
"<-a | filesystem|volume>\n"));
429
case HELP_UNLOAD_KEY:
430
return (gettext("\tunload-key [-r] "
431
"<-a | filesystem|volume>\n"));
432
case HELP_CHANGE_KEY:
433
return (gettext("\tchange-key [-l] [-o keyformat=<value>]\n"
434
"\t [-o keylocation=<value>] [-o pbkdf2iters=<value>]\n"
435
"\t <filesystem|volume>\n"
436
"\tchange-key -i [-l] <filesystem|volume>\n"));
437
case HELP_VERSION:
438
return (gettext("\tversion [-j]\n"));
439
case HELP_REDACT:
440
return (gettext("\tredact <snapshot> <bookmark> "
441
"<redaction_snapshot> ...\n"));
442
case HELP_REWRITE:
443
return (gettext("\trewrite [-Prvx] [-o <offset>] [-l <length>] "
444
"<directory|file ...>\n"));
445
case HELP_JAIL:
446
return (gettext("\tjail <jailid|jailname> <filesystem>\n"));
447
case HELP_UNJAIL:
448
return (gettext("\tunjail <jailid|jailname> <filesystem>\n"));
449
case HELP_WAIT:
450
return (gettext("\twait [-t <activity>] <filesystem>\n"));
451
case HELP_ZONE:
452
return (gettext("\tzone <nsfile> <filesystem>\n"));
453
case HELP_UNZONE:
454
return (gettext("\tunzone <nsfile> <filesystem>\n"));
455
default:
456
__builtin_unreachable();
457
}
458
}
459
460
void
461
nomem(void)
462
{
463
(void) fprintf(stderr, gettext("internal error: out of memory\n"));
464
exit(1);
465
}
466
467
/*
468
* Utility function to guarantee malloc() success.
469
*/
470
471
void *
472
safe_malloc(size_t size)
473
{
474
void *data;
475
476
if ((data = calloc(1, size)) == NULL)
477
nomem();
478
479
return (data);
480
}
481
482
static void *
483
safe_realloc(void *data, size_t size)
484
{
485
void *newp;
486
if ((newp = realloc(data, size)) == NULL) {
487
free(data);
488
nomem();
489
}
490
491
return (newp);
492
}
493
494
static char *
495
safe_strdup(const char *str)
496
{
497
char *dupstr = strdup(str);
498
499
if (dupstr == NULL)
500
nomem();
501
502
return (dupstr);
503
}
504
505
/*
506
* Callback routine that will print out information for each of
507
* the properties.
508
*/
509
static int
510
usage_prop_cb(int prop, void *cb)
511
{
512
FILE *fp = cb;
513
514
(void) fprintf(fp, "\t%-22s ", zfs_prop_to_name(prop));
515
516
if (zfs_prop_readonly(prop))
517
(void) fprintf(fp, " NO ");
518
else
519
(void) fprintf(fp, "YES ");
520
521
if (zfs_prop_inheritable(prop))
522
(void) fprintf(fp, " YES ");
523
else
524
(void) fprintf(fp, " NO ");
525
526
(void) fprintf(fp, "%s\n", zfs_prop_values(prop) ?: "-");
527
528
return (ZPROP_CONT);
529
}
530
531
/*
532
* Display usage message. If we're inside a command, display only the usage for
533
* that command. Otherwise, iterate over the entire command table and display
534
* a complete usage message.
535
*/
536
static __attribute__((noreturn)) void
537
usage(boolean_t requested)
538
{
539
int i;
540
boolean_t show_properties = B_FALSE;
541
FILE *fp = requested ? stdout : stderr;
542
543
if (current_command == NULL) {
544
545
(void) fprintf(fp, gettext("usage: zfs command args ...\n"));
546
(void) fprintf(fp,
547
gettext("where 'command' is one of the following:\n\n"));
548
549
for (i = 0; i < NCOMMAND; i++) {
550
if (command_table[i].name == NULL)
551
(void) fprintf(fp, "\n");
552
else
553
(void) fprintf(fp, "%s",
554
get_usage(command_table[i].usage));
555
}
556
557
(void) fprintf(fp, gettext("\nEach dataset is of the form: "
558
"pool/[dataset/]*dataset[@name]\n"));
559
} else {
560
(void) fprintf(fp, gettext("usage:\n"));
561
(void) fprintf(fp, "%s", get_usage(current_command->usage));
562
}
563
564
if (current_command != NULL &&
565
(strcmp(current_command->name, "set") == 0 ||
566
strcmp(current_command->name, "get") == 0 ||
567
strcmp(current_command->name, "inherit") == 0 ||
568
strcmp(current_command->name, "list") == 0))
569
show_properties = B_TRUE;
570
571
if (show_properties) {
572
(void) fprintf(fp, "%s",
573
gettext("\nThe following properties are supported:\n"));
574
575
(void) fprintf(fp, "\n\t%-21s %s %s %s\n\n",
576
"PROPERTY", "EDIT", "INHERIT", "VALUES");
577
578
/* Iterate over all properties */
579
(void) zprop_iter(usage_prop_cb, fp, B_FALSE, B_TRUE,
580
ZFS_TYPE_DATASET);
581
582
(void) fprintf(fp, "\t%-22s ", "userused@...");
583
(void) fprintf(fp, " NO NO <size>\n");
584
(void) fprintf(fp, "\t%-22s ", "groupused@...");
585
(void) fprintf(fp, " NO NO <size>\n");
586
(void) fprintf(fp, "\t%-22s ", "projectused@...");
587
(void) fprintf(fp, " NO NO <size>\n");
588
(void) fprintf(fp, "\t%-22s ", "userobjused@...");
589
(void) fprintf(fp, " NO NO <size>\n");
590
(void) fprintf(fp, "\t%-22s ", "groupobjused@...");
591
(void) fprintf(fp, " NO NO <size>\n");
592
(void) fprintf(fp, "\t%-22s ", "projectobjused@...");
593
(void) fprintf(fp, " NO NO <size>\n");
594
(void) fprintf(fp, "\t%-22s ", "userquota@...");
595
(void) fprintf(fp, "YES NO <size> | none\n");
596
(void) fprintf(fp, "\t%-22s ", "groupquota@...");
597
(void) fprintf(fp, "YES NO <size> | none\n");
598
(void) fprintf(fp, "\t%-22s ", "projectquota@...");
599
(void) fprintf(fp, "YES NO <size> | none\n");
600
(void) fprintf(fp, "\t%-22s ", "userobjquota@...");
601
(void) fprintf(fp, "YES NO <size> | none\n");
602
(void) fprintf(fp, "\t%-22s ", "groupobjquota@...");
603
(void) fprintf(fp, "YES NO <size> | none\n");
604
(void) fprintf(fp, "\t%-22s ", "projectobjquota@...");
605
(void) fprintf(fp, "YES NO <size> | none\n");
606
(void) fprintf(fp, "\t%-22s ", "written@<snap>");
607
(void) fprintf(fp, " NO NO <size>\n");
608
(void) fprintf(fp, "\t%-22s ", "written#<bookmark>");
609
(void) fprintf(fp, " NO NO <size>\n");
610
611
(void) fprintf(fp, gettext("\nSizes are specified in bytes "
612
"with standard units such as K, M, G, etc.\n"));
613
(void) fprintf(fp, "%s", gettext("\nUser-defined properties "
614
"can be specified by using a name containing a colon "
615
"(:).\n"));
616
(void) fprintf(fp, gettext("\nThe {user|group|project}"
617
"[obj]{used|quota}@ properties must be appended with\n"
618
"a user|group|project specifier of one of these forms:\n"
619
" POSIX name (eg: \"matt\")\n"
620
" POSIX id (eg: \"126829\")\n"
621
" SMB name@domain (eg: \"matt@sun\")\n"
622
" SMB SID (eg: \"S-1-234-567-89\")\n"));
623
} else {
624
(void) fprintf(fp,
625
gettext("\nFor the property list, run: %s\n"),
626
"zfs set|get");
627
(void) fprintf(fp,
628
gettext("\nFor the delegated permission list, run: %s\n"),
629
"zfs allow|unallow");
630
(void) fprintf(fp,
631
gettext("\nFor further help on a command or topic, "
632
"run: %s\n"), "zfs help [<topic>]");
633
}
634
635
/*
636
* See comments at end of main().
637
*/
638
if (getenv("ZFS_ABORT") != NULL) {
639
(void) printf("dumping core by request\n");
640
abort();
641
}
642
643
exit(requested ? 0 : 2);
644
}
645
646
/*
647
* Take a property=value argument string and add it to the given nvlist.
648
* Modifies the argument inplace.
649
*/
650
static boolean_t
651
parseprop(nvlist_t *props, char *propname)
652
{
653
char *propval;
654
655
if ((propval = strchr(propname, '=')) == NULL) {
656
(void) fprintf(stderr, gettext("missing "
657
"'=' for property=value argument\n"));
658
return (B_FALSE);
659
}
660
*propval = '\0';
661
propval++;
662
if (nvlist_exists(props, propname)) {
663
(void) fprintf(stderr, gettext("property '%s' "
664
"specified multiple times\n"), propname);
665
return (B_FALSE);
666
}
667
if (nvlist_add_string(props, propname, propval) != 0)
668
nomem();
669
return (B_TRUE);
670
}
671
672
/*
673
* Take a property name argument and add it to the given nvlist.
674
* Modifies the argument inplace.
675
*/
676
static boolean_t
677
parsepropname(nvlist_t *props, char *propname)
678
{
679
if (strchr(propname, '=') != NULL) {
680
(void) fprintf(stderr, gettext("invalid character "
681
"'=' in property argument\n"));
682
return (B_FALSE);
683
}
684
if (nvlist_exists(props, propname)) {
685
(void) fprintf(stderr, gettext("property '%s' "
686
"specified multiple times\n"), propname);
687
return (B_FALSE);
688
}
689
if (nvlist_add_boolean(props, propname) != 0)
690
nomem();
691
return (B_TRUE);
692
}
693
694
static int
695
parse_depth(char *opt, int *flags)
696
{
697
char *tmp;
698
int depth;
699
700
depth = (int)strtol(opt, &tmp, 0);
701
if (*tmp) {
702
(void) fprintf(stderr,
703
gettext("%s is not an integer\n"), optarg);
704
usage(B_FALSE);
705
}
706
if (depth < 0) {
707
(void) fprintf(stderr,
708
gettext("Depth can not be negative.\n"));
709
usage(B_FALSE);
710
}
711
*flags |= (ZFS_ITER_DEPTH_LIMIT|ZFS_ITER_RECURSE);
712
return (depth);
713
}
714
715
#define PROGRESS_DELAY 2 /* seconds */
716
717
static const char *pt_reverse =
718
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
719
static time_t pt_begin;
720
static char *pt_header = NULL;
721
static boolean_t pt_shown;
722
723
static void
724
start_progress_timer(void)
725
{
726
pt_begin = time(NULL) + PROGRESS_DELAY;
727
pt_shown = B_FALSE;
728
}
729
730
static void
731
set_progress_header(const char *header)
732
{
733
assert(pt_header == NULL);
734
pt_header = safe_strdup(header);
735
if (pt_shown) {
736
(void) printf("%s: ", header);
737
(void) fflush(stdout);
738
}
739
}
740
741
static void
742
update_progress(const char *update)
743
{
744
if (!pt_shown && time(NULL) > pt_begin) {
745
int len = strlen(update);
746
747
(void) printf("%s: %s%*.*s", pt_header, update, len, len,
748
pt_reverse);
749
(void) fflush(stdout);
750
pt_shown = B_TRUE;
751
} else if (pt_shown) {
752
int len = strlen(update);
753
754
(void) printf("%s%*.*s", update, len, len, pt_reverse);
755
(void) fflush(stdout);
756
}
757
}
758
759
static void
760
finish_progress(const char *done)
761
{
762
if (pt_shown) {
763
(void) puts(done);
764
(void) fflush(stdout);
765
}
766
free(pt_header);
767
pt_header = NULL;
768
}
769
770
static int
771
zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type)
772
{
773
zfs_handle_t *zhp = NULL;
774
int ret = 0;
775
776
zhp = zfs_open(hdl, dataset, type);
777
if (zhp == NULL)
778
return (1);
779
780
/*
781
* Volumes may neither be mounted or shared. Potentially in the
782
* future filesystems detected on these volumes could be mounted.
783
*/
784
if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
785
zfs_close(zhp);
786
return (0);
787
}
788
789
/*
790
* Mount and/or share the new filesystem as appropriate. We provide a
791
* verbose error message to let the user know that their filesystem was
792
* in fact created, even if we failed to mount or share it.
793
*
794
* If the user doesn't want the dataset automatically mounted, then
795
* skip the mount/share step
796
*/
797
if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type, B_FALSE) &&
798
zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON) {
799
if (zfs_mount_delegation_check()) {
800
(void) fprintf(stderr, gettext("filesystem "
801
"successfully created, but it may only be "
802
"mounted by root\n"));
803
ret = 1;
804
} else if (zfs_mount(zhp, NULL, 0) != 0) {
805
(void) fprintf(stderr, gettext("filesystem "
806
"successfully created, but not mounted\n"));
807
ret = 1;
808
} else if (zfs_share(zhp, NULL) != 0) {
809
(void) fprintf(stderr, gettext("filesystem "
810
"successfully created, but not shared\n"));
811
ret = 1;
812
}
813
zfs_commit_shares(NULL);
814
}
815
816
zfs_close(zhp);
817
818
return (ret);
819
}
820
821
/*
822
* zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
823
*
824
* Given an existing dataset, create a writable copy whose initial contents
825
* are the same as the source. The newly created dataset maintains a
826
* dependency on the original; the original cannot be destroyed so long as
827
* the clone exists.
828
*
829
* The '-p' flag creates all the non-existing ancestors of the target first.
830
*/
831
static int
832
zfs_do_clone(int argc, char **argv)
833
{
834
zfs_handle_t *zhp = NULL;
835
boolean_t parents = B_FALSE;
836
nvlist_t *props;
837
int ret = 0;
838
int c;
839
840
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
841
nomem();
842
843
/* check options */
844
while ((c = getopt(argc, argv, "o:p")) != -1) {
845
switch (c) {
846
case 'o':
847
if (!parseprop(props, optarg)) {
848
nvlist_free(props);
849
return (1);
850
}
851
break;
852
case 'p':
853
parents = B_TRUE;
854
break;
855
case '?':
856
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
857
optopt);
858
goto usage;
859
}
860
}
861
862
argc -= optind;
863
argv += optind;
864
865
/* check number of arguments */
866
if (argc < 1) {
867
(void) fprintf(stderr, gettext("missing source dataset "
868
"argument\n"));
869
goto usage;
870
}
871
if (argc < 2) {
872
(void) fprintf(stderr, gettext("missing target dataset "
873
"argument\n"));
874
goto usage;
875
}
876
if (argc > 2) {
877
(void) fprintf(stderr, gettext("too many arguments\n"));
878
goto usage;
879
}
880
881
/* open the source dataset */
882
if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) {
883
nvlist_free(props);
884
return (1);
885
}
886
887
if (parents && zfs_name_valid(argv[1], ZFS_TYPE_FILESYSTEM |
888
ZFS_TYPE_VOLUME)) {
889
/*
890
* Now create the ancestors of the target dataset. If the
891
* target already exists and '-p' option was used we should not
892
* complain.
893
*/
894
if (zfs_dataset_exists(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM |
895
ZFS_TYPE_VOLUME)) {
896
zfs_close(zhp);
897
nvlist_free(props);
898
return (0);
899
}
900
if (zfs_create_ancestors(g_zfs, argv[1]) != 0) {
901
zfs_close(zhp);
902
nvlist_free(props);
903
return (1);
904
}
905
}
906
907
/* pass to libzfs */
908
ret = zfs_clone(zhp, argv[1], props);
909
910
/* create the mountpoint if necessary */
911
if (ret == 0) {
912
if (log_history) {
913
(void) zpool_log_history(g_zfs, history_str);
914
log_history = B_FALSE;
915
}
916
917
/*
918
* Dataset cloned successfully, mount/share failures are
919
* non-fatal.
920
*/
921
(void) zfs_mount_and_share(g_zfs, argv[1], ZFS_TYPE_DATASET);
922
}
923
924
zfs_close(zhp);
925
nvlist_free(props);
926
927
return (!!ret);
928
929
usage:
930
ASSERT0P(zhp);
931
nvlist_free(props);
932
usage(B_FALSE);
933
return (-1);
934
}
935
936
/*
937
* Calculate the minimum allocation size based on the top-level vdevs.
938
*/
939
static uint64_t
940
calculate_volblocksize(nvlist_t *config)
941
{
942
uint64_t asize = SPA_MINBLOCKSIZE;
943
nvlist_t *tree, **vdevs;
944
uint_t nvdevs;
945
946
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree) != 0 ||
947
nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN,
948
&vdevs, &nvdevs) != 0) {
949
return (ZVOL_DEFAULT_BLOCKSIZE);
950
}
951
952
for (int i = 0; i < nvdevs; i++) {
953
nvlist_t *nv = vdevs[i];
954
uint64_t ashift, ndata, nparity;
955
956
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ASHIFT, &ashift) != 0)
957
continue;
958
959
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_DRAID_NDATA,
960
&ndata) == 0) {
961
/* dRAID minimum allocation width */
962
asize = MAX(asize, ndata * (1ULL << ashift));
963
} else if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
964
&nparity) == 0) {
965
/* raidz minimum allocation width */
966
if (nparity == 1)
967
asize = MAX(asize, 2 * (1ULL << ashift));
968
else
969
asize = MAX(asize, 4 * (1ULL << ashift));
970
} else {
971
/* mirror or (non-redundant) leaf vdev */
972
asize = MAX(asize, 1ULL << ashift);
973
}
974
}
975
976
return (asize);
977
}
978
979
/*
980
* Return a default volblocksize for the pool which always uses more than
981
* half of the data sectors. This primarily applies to dRAID which always
982
* writes full stripe widths.
983
*/
984
static uint64_t
985
default_volblocksize(zpool_handle_t *zhp, nvlist_t *props)
986
{
987
uint64_t volblocksize, asize = SPA_MINBLOCKSIZE;
988
989
nvlist_t *config = zpool_get_config(zhp, NULL);
990
991
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_MAX_ALLOC, &asize) != 0)
992
asize = calculate_volblocksize(config);
993
994
/*
995
* Calculate the target volblocksize such that more than half
996
* of the asize is used. The following table is for 4k sectors.
997
*
998
* n asize blksz used | n asize blksz used
999
* -------------------------+---------------------------------
1000
* 1 4,096 8,192 100% | 9 36,864 32,768 88%
1001
* 2 8,192 8,192 100% | 10 40,960 32,768 80%
1002
* 3 12,288 8,192 66% | 11 45,056 32,768 72%
1003
* 4 16,384 16,384 100% | 12 49,152 32,768 66%
1004
* 5 20,480 16,384 80% | 13 53,248 32,768 61%
1005
* 6 24,576 16,384 66% | 14 57,344 32,768 57%
1006
* 7 28,672 16,384 57% | 15 61,440 32,768 53%
1007
* 8 32,768 32,768 100% | 16 65,536 65,636 100%
1008
*
1009
* This is primarily a concern for dRAID which always allocates
1010
* a full stripe width. For dRAID the default stripe width is
1011
* n=8 in which case the volblocksize is set to 32k. Ignoring
1012
* compression there are no unused sectors. This same reasoning
1013
* applies to raidz[2,3] so target 4 sectors to minimize waste.
1014
*/
1015
uint64_t tgt_volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
1016
while (tgt_volblocksize * 2 <= asize)
1017
tgt_volblocksize *= 2;
1018
1019
const char *prop = zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE);
1020
if (nvlist_lookup_uint64(props, prop, &volblocksize) == 0) {
1021
1022
/* Issue a warning when a non-optimal size is requested. */
1023
if (volblocksize < ZVOL_DEFAULT_BLOCKSIZE) {
1024
(void) fprintf(stderr, gettext("Warning: "
1025
"volblocksize (%llu) is less than the default "
1026
"minimum block size (%llu).\nTo reduce wasted "
1027
"space a volblocksize of %llu is recommended.\n"),
1028
(u_longlong_t)volblocksize,
1029
(u_longlong_t)ZVOL_DEFAULT_BLOCKSIZE,
1030
(u_longlong_t)tgt_volblocksize);
1031
} else if (volblocksize < tgt_volblocksize) {
1032
(void) fprintf(stderr, gettext("Warning: "
1033
"volblocksize (%llu) is much less than the "
1034
"minimum allocation\nunit (%llu), which wastes "
1035
"at least %llu%% of space. To reduce wasted "
1036
"space,\nuse a larger volblocksize (%llu is "
1037
"recommended), fewer dRAID data disks\n"
1038
"per group, or smaller sector size (ashift).\n"),
1039
(u_longlong_t)volblocksize, (u_longlong_t)asize,
1040
(u_longlong_t)((100 * (asize - volblocksize)) /
1041
asize), (u_longlong_t)tgt_volblocksize);
1042
}
1043
} else {
1044
volblocksize = tgt_volblocksize;
1045
fnvlist_add_uint64(props, prop, volblocksize);
1046
}
1047
1048
return (volblocksize);
1049
}
1050
1051
/*
1052
* zfs create [-Pnpv] [-o prop=value] ... fs
1053
* zfs create [-Pnpsv] [-b blocksize] [-o prop=value] ... -V vol size
1054
*
1055
* Create a new dataset. This command can be used to create filesystems
1056
* and volumes. Snapshot creation is handled by 'zfs snapshot'.
1057
* For volumes, the user must specify a size to be used.
1058
*
1059
* The '-s' flag applies only to volumes, and indicates that we should not try
1060
* to set the reservation for this volume. By default we set a reservation
1061
* equal to the size for any volume. For pools with SPA_VERSION >=
1062
* SPA_VERSION_REFRESERVATION, we set a refreservation instead.
1063
*
1064
* The '-p' flag creates all the non-existing ancestors of the target first.
1065
*
1066
* The '-n' flag is no-op (dry run) mode. This will perform a user-space sanity
1067
* check of arguments and properties, but does not check for permissions,
1068
* available space, etc.
1069
*
1070
* The '-u' flag prevents the newly created file system from being mounted.
1071
*
1072
* The '-v' flag is for verbose output.
1073
*
1074
* The '-P' flag is used for parseable output. It implies '-v'.
1075
*/
1076
static int
1077
zfs_do_create(int argc, char **argv)
1078
{
1079
zfs_type_t type = ZFS_TYPE_FILESYSTEM;
1080
zpool_handle_t *zpool_handle = NULL;
1081
nvlist_t *real_props = NULL;
1082
uint64_t volsize = 0;
1083
int c;
1084
boolean_t noreserve = B_FALSE;
1085
boolean_t bflag = B_FALSE;
1086
boolean_t parents = B_FALSE;
1087
boolean_t dryrun = B_FALSE;
1088
boolean_t nomount = B_FALSE;
1089
boolean_t verbose = B_FALSE;
1090
boolean_t parseable = B_FALSE;
1091
int ret = 1;
1092
nvlist_t *props;
1093
uint64_t intval;
1094
const char *strval;
1095
1096
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
1097
nomem();
1098
1099
/* check options */
1100
while ((c = getopt(argc, argv, ":PV:b:nso:puv")) != -1) {
1101
switch (c) {
1102
case 'V':
1103
type = ZFS_TYPE_VOLUME;
1104
if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
1105
(void) fprintf(stderr, gettext("bad volume "
1106
"size '%s': %s\n"), optarg,
1107
libzfs_error_description(g_zfs));
1108
goto error;
1109
}
1110
1111
if (nvlist_add_uint64(props,
1112
zfs_prop_to_name(ZFS_PROP_VOLSIZE), intval) != 0)
1113
nomem();
1114
volsize = intval;
1115
break;
1116
case 'P':
1117
verbose = B_TRUE;
1118
parseable = B_TRUE;
1119
break;
1120
case 'p':
1121
parents = B_TRUE;
1122
break;
1123
case 'b':
1124
bflag = B_TRUE;
1125
if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
1126
(void) fprintf(stderr, gettext("bad volume "
1127
"block size '%s': %s\n"), optarg,
1128
libzfs_error_description(g_zfs));
1129
goto error;
1130
}
1131
1132
if (nvlist_add_uint64(props,
1133
zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1134
intval) != 0)
1135
nomem();
1136
break;
1137
case 'n':
1138
dryrun = B_TRUE;
1139
break;
1140
case 'o':
1141
if (!parseprop(props, optarg))
1142
goto error;
1143
break;
1144
case 's':
1145
noreserve = B_TRUE;
1146
break;
1147
case 'u':
1148
nomount = B_TRUE;
1149
break;
1150
case 'v':
1151
verbose = B_TRUE;
1152
break;
1153
case ':':
1154
(void) fprintf(stderr, gettext("missing size "
1155
"argument\n"));
1156
goto badusage;
1157
case '?':
1158
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1159
optopt);
1160
goto badusage;
1161
}
1162
}
1163
1164
if ((bflag || noreserve) && type != ZFS_TYPE_VOLUME) {
1165
(void) fprintf(stderr, gettext("'-s' and '-b' can only be "
1166
"used when creating a volume\n"));
1167
goto badusage;
1168
}
1169
if (nomount && type != ZFS_TYPE_FILESYSTEM) {
1170
(void) fprintf(stderr, gettext("'-u' can only be "
1171
"used when creating a filesystem\n"));
1172
goto badusage;
1173
}
1174
1175
argc -= optind;
1176
argv += optind;
1177
1178
/* check number of arguments */
1179
if (argc == 0) {
1180
(void) fprintf(stderr, gettext("missing %s argument\n"),
1181
zfs_type_to_name(type));
1182
goto badusage;
1183
}
1184
if (argc > 1) {
1185
(void) fprintf(stderr, gettext("too many arguments\n"));
1186
goto badusage;
1187
}
1188
1189
if (dryrun || type == ZFS_TYPE_VOLUME) {
1190
char msg[ZFS_MAX_DATASET_NAME_LEN * 2];
1191
char *p;
1192
1193
if ((p = strchr(argv[0], '/')) != NULL)
1194
*p = '\0';
1195
zpool_handle = zpool_open(g_zfs, argv[0]);
1196
if (p != NULL)
1197
*p = '/';
1198
if (zpool_handle == NULL)
1199
goto error;
1200
1201
(void) snprintf(msg, sizeof (msg),
1202
dryrun ? gettext("cannot verify '%s'") :
1203
gettext("cannot create '%s'"), argv[0]);
1204
if (props && (real_props = zfs_valid_proplist(g_zfs, type,
1205
props, 0, NULL, zpool_handle, B_TRUE, msg)) == NULL) {
1206
zpool_close(zpool_handle);
1207
goto error;
1208
}
1209
}
1210
1211
if (type == ZFS_TYPE_VOLUME) {
1212
const char *prop = zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE);
1213
uint64_t volblocksize = default_volblocksize(zpool_handle,
1214
real_props);
1215
1216
if (volblocksize != ZVOL_DEFAULT_BLOCKSIZE &&
1217
nvlist_lookup_string(props, prop, &strval) != 0) {
1218
char *tmp;
1219
if (asprintf(&tmp, "%llu",
1220
(u_longlong_t)volblocksize) == -1)
1221
nomem();
1222
nvlist_add_string(props, prop, tmp);
1223
free(tmp);
1224
}
1225
1226
/*
1227
* If volsize is not a multiple of volblocksize, round it
1228
* up to the nearest multiple of the volblocksize.
1229
*/
1230
if (volsize % volblocksize) {
1231
volsize = P2ROUNDUP_TYPED(volsize, volblocksize,
1232
uint64_t);
1233
1234
if (nvlist_add_uint64(props,
1235
zfs_prop_to_name(ZFS_PROP_VOLSIZE), volsize) != 0) {
1236
nvlist_free(props);
1237
nomem();
1238
}
1239
}
1240
}
1241
1242
if (type == ZFS_TYPE_VOLUME && !noreserve) {
1243
uint64_t spa_version;
1244
zfs_prop_t resv_prop;
1245
1246
spa_version = zpool_get_prop_int(zpool_handle,
1247
ZPOOL_PROP_VERSION, NULL);
1248
if (spa_version >= SPA_VERSION_REFRESERVATION)
1249
resv_prop = ZFS_PROP_REFRESERVATION;
1250
else
1251
resv_prop = ZFS_PROP_RESERVATION;
1252
1253
volsize = zvol_volsize_to_reservation(zpool_handle, volsize,
1254
real_props);
1255
1256
if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
1257
&strval) != 0) {
1258
if (nvlist_add_uint64(props,
1259
zfs_prop_to_name(resv_prop), volsize) != 0) {
1260
nvlist_free(props);
1261
nomem();
1262
}
1263
}
1264
}
1265
if (zpool_handle != NULL) {
1266
zpool_close(zpool_handle);
1267
nvlist_free(real_props);
1268
}
1269
1270
if (parents && zfs_name_valid(argv[0], type)) {
1271
/*
1272
* Now create the ancestors of target dataset. If the target
1273
* already exists and '-p' option was used we should not
1274
* complain.
1275
*/
1276
if (zfs_dataset_exists(g_zfs, argv[0], type)) {
1277
ret = 0;
1278
goto error;
1279
}
1280
if (verbose) {
1281
(void) printf(parseable ? "create_ancestors\t%s\n" :
1282
dryrun ? "would create ancestors of %s\n" :
1283
"create ancestors of %s\n", argv[0]);
1284
}
1285
if (!dryrun) {
1286
if (zfs_create_ancestors(g_zfs, argv[0]) != 0) {
1287
goto error;
1288
}
1289
}
1290
}
1291
1292
if (verbose) {
1293
nvpair_t *nvp = NULL;
1294
(void) printf(parseable ? "create\t%s\n" :
1295
dryrun ? "would create %s\n" : "create %s\n", argv[0]);
1296
while ((nvp = nvlist_next_nvpair(props, nvp)) != NULL) {
1297
uint64_t uval;
1298
const char *sval;
1299
1300
switch (nvpair_type(nvp)) {
1301
case DATA_TYPE_UINT64:
1302
VERIFY0(nvpair_value_uint64(nvp, &uval));
1303
(void) printf(parseable ?
1304
"property\t%s\t%llu\n" : "\t%s=%llu\n",
1305
nvpair_name(nvp), (u_longlong_t)uval);
1306
break;
1307
case DATA_TYPE_STRING:
1308
VERIFY0(nvpair_value_string(nvp, &sval));
1309
(void) printf(parseable ?
1310
"property\t%s\t%s\n" : "\t%s=%s\n",
1311
nvpair_name(nvp), sval);
1312
break;
1313
default:
1314
(void) fprintf(stderr, "property '%s' "
1315
"has illegal type %d\n",
1316
nvpair_name(nvp), nvpair_type(nvp));
1317
abort();
1318
}
1319
}
1320
}
1321
if (dryrun) {
1322
ret = 0;
1323
goto error;
1324
}
1325
1326
/* pass to libzfs */
1327
if (zfs_create(g_zfs, argv[0], type, props) != 0)
1328
goto error;
1329
1330
if (log_history) {
1331
(void) zpool_log_history(g_zfs, history_str);
1332
log_history = B_FALSE;
1333
}
1334
1335
if (nomount) {
1336
ret = 0;
1337
goto error;
1338
}
1339
1340
/* Dataset created successfully, mount/share failures are non-fatal */
1341
ret = 0;
1342
(void) zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET);
1343
error:
1344
nvlist_free(props);
1345
return (ret);
1346
badusage:
1347
nvlist_free(props);
1348
usage(B_FALSE);
1349
return (2);
1350
}
1351
1352
/*
1353
* zfs destroy [-rRf] <fs, vol>
1354
* zfs destroy [-rRd] <snap>
1355
*
1356
* -r Recursively destroy all children
1357
* -R Recursively destroy all dependents, including clones
1358
* -f Force unmounting of any dependents
1359
* -d If we can't destroy now, mark for deferred destruction
1360
*
1361
* Destroys the given dataset. By default, it will unmount any filesystems,
1362
* and refuse to destroy a dataset that has any dependents. A dependent can
1363
* either be a child, or a clone of a child.
1364
*/
1365
typedef struct destroy_cbdata {
1366
boolean_t cb_first;
1367
boolean_t cb_force;
1368
boolean_t cb_recurse;
1369
boolean_t cb_error;
1370
boolean_t cb_doclones;
1371
zfs_handle_t *cb_target;
1372
boolean_t cb_defer_destroy;
1373
boolean_t cb_verbose;
1374
boolean_t cb_parsable;
1375
boolean_t cb_dryrun;
1376
nvlist_t *cb_nvl;
1377
nvlist_t *cb_batchedsnaps;
1378
1379
/* first snap in contiguous run */
1380
char *cb_firstsnap;
1381
/* previous snap in contiguous run */
1382
char *cb_prevsnap;
1383
int64_t cb_snapused;
1384
char *cb_snapspec;
1385
char *cb_bookmark;
1386
uint64_t cb_snap_count;
1387
} destroy_cbdata_t;
1388
1389
/*
1390
* Check for any dependents based on the '-r' or '-R' flags.
1391
*/
1392
static int
1393
destroy_check_dependent(zfs_handle_t *zhp, void *data)
1394
{
1395
destroy_cbdata_t *cbp = data;
1396
const char *tname = zfs_get_name(cbp->cb_target);
1397
const char *name = zfs_get_name(zhp);
1398
1399
if (strncmp(tname, name, strlen(tname)) == 0 &&
1400
(name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
1401
/*
1402
* This is a direct descendant, not a clone somewhere else in
1403
* the hierarchy.
1404
*/
1405
if (cbp->cb_recurse)
1406
goto out;
1407
1408
if (cbp->cb_first) {
1409
(void) fprintf(stderr, gettext("cannot destroy '%s': "
1410
"%s has children\n"),
1411
zfs_get_name(cbp->cb_target),
1412
zfs_type_to_name(zfs_get_type(cbp->cb_target)));
1413
(void) fprintf(stderr, gettext("use '-r' to destroy "
1414
"the following datasets:\n"));
1415
cbp->cb_first = B_FALSE;
1416
cbp->cb_error = B_TRUE;
1417
}
1418
1419
(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
1420
} else {
1421
/*
1422
* This is a clone. We only want to report this if the '-r'
1423
* wasn't specified, or the target is a snapshot.
1424
*/
1425
if (!cbp->cb_recurse &&
1426
zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT)
1427
goto out;
1428
1429
if (cbp->cb_first) {
1430
(void) fprintf(stderr, gettext("cannot destroy '%s': "
1431
"%s has dependent clones\n"),
1432
zfs_get_name(cbp->cb_target),
1433
zfs_type_to_name(zfs_get_type(cbp->cb_target)));
1434
(void) fprintf(stderr, gettext("use '-R' to destroy "
1435
"the following datasets:\n"));
1436
cbp->cb_first = B_FALSE;
1437
cbp->cb_error = B_TRUE;
1438
cbp->cb_dryrun = B_TRUE;
1439
}
1440
1441
(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
1442
}
1443
1444
out:
1445
zfs_close(zhp);
1446
return (0);
1447
}
1448
1449
static int
1450
destroy_batched(destroy_cbdata_t *cb)
1451
{
1452
int error = zfs_destroy_snaps_nvl(g_zfs,
1453
cb->cb_batchedsnaps, B_FALSE);
1454
fnvlist_free(cb->cb_batchedsnaps);
1455
cb->cb_batchedsnaps = fnvlist_alloc();
1456
return (error);
1457
}
1458
1459
static int
1460
destroy_callback(zfs_handle_t *zhp, void *data)
1461
{
1462
destroy_cbdata_t *cb = data;
1463
const char *name = zfs_get_name(zhp);
1464
int error;
1465
1466
if (cb->cb_verbose) {
1467
if (cb->cb_parsable) {
1468
(void) printf("destroy\t%s\n", name);
1469
} else if (cb->cb_dryrun) {
1470
(void) printf(gettext("would destroy %s\n"),
1471
name);
1472
} else {
1473
(void) printf(gettext("will destroy %s\n"),
1474
name);
1475
}
1476
}
1477
1478
/*
1479
* Ignore pools (which we've already flagged as an error before getting
1480
* here).
1481
*/
1482
if (strchr(zfs_get_name(zhp), '/') == NULL &&
1483
zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
1484
zfs_close(zhp);
1485
return (0);
1486
}
1487
if (cb->cb_dryrun) {
1488
zfs_close(zhp);
1489
return (0);
1490
}
1491
1492
/*
1493
* We batch up all contiguous snapshots (even of different
1494
* filesystems) and destroy them with one ioctl. We can't
1495
* simply do all snap deletions and then all fs deletions,
1496
* because we must delete a clone before its origin.
1497
*/
1498
if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
1499
cb->cb_snap_count++;
1500
fnvlist_add_boolean(cb->cb_batchedsnaps, name);
1501
if (cb->cb_snap_count % 10 == 0 && cb->cb_defer_destroy) {
1502
error = destroy_batched(cb);
1503
if (error != 0) {
1504
zfs_close(zhp);
1505
return (-1);
1506
}
1507
}
1508
} else {
1509
error = destroy_batched(cb);
1510
if (error != 0 ||
1511
zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
1512
zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
1513
zfs_close(zhp);
1514
/*
1515
* When performing a recursive destroy we ignore errors
1516
* so that the recursive destroy could continue
1517
* destroying past problem datasets
1518
*/
1519
if (cb->cb_recurse) {
1520
cb->cb_error = B_TRUE;
1521
return (0);
1522
}
1523
return (-1);
1524
}
1525
}
1526
1527
zfs_close(zhp);
1528
return (0);
1529
}
1530
1531
static int
1532
destroy_print_cb(zfs_handle_t *zhp, void *arg)
1533
{
1534
destroy_cbdata_t *cb = arg;
1535
const char *name = zfs_get_name(zhp);
1536
int err = 0;
1537
1538
if (nvlist_exists(cb->cb_nvl, name)) {
1539
if (cb->cb_firstsnap == NULL)
1540
cb->cb_firstsnap = strdup(name);
1541
if (cb->cb_prevsnap != NULL)
1542
free(cb->cb_prevsnap);
1543
/* this snap continues the current range */
1544
cb->cb_prevsnap = strdup(name);
1545
if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
1546
nomem();
1547
if (cb->cb_verbose) {
1548
if (cb->cb_parsable) {
1549
(void) printf("destroy\t%s\n", name);
1550
} else if (cb->cb_dryrun) {
1551
(void) printf(gettext("would destroy %s\n"),
1552
name);
1553
} else {
1554
(void) printf(gettext("will destroy %s\n"),
1555
name);
1556
}
1557
}
1558
} else if (cb->cb_firstsnap != NULL) {
1559
/* end of this range */
1560
uint64_t used = 0;
1561
err = lzc_snaprange_space(cb->cb_firstsnap,
1562
cb->cb_prevsnap, &used);
1563
cb->cb_snapused += used;
1564
free(cb->cb_firstsnap);
1565
cb->cb_firstsnap = NULL;
1566
free(cb->cb_prevsnap);
1567
cb->cb_prevsnap = NULL;
1568
}
1569
zfs_close(zhp);
1570
return (err);
1571
}
1572
1573
static int
1574
destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
1575
{
1576
int err;
1577
assert(cb->cb_firstsnap == NULL);
1578
assert(cb->cb_prevsnap == NULL);
1579
err = zfs_iter_snapshots_sorted_v2(fs_zhp, 0, destroy_print_cb, cb, 0,
1580
0);
1581
if (cb->cb_firstsnap != NULL) {
1582
uint64_t used = 0;
1583
if (err == 0) {
1584
err = lzc_snaprange_space(cb->cb_firstsnap,
1585
cb->cb_prevsnap, &used);
1586
}
1587
cb->cb_snapused += used;
1588
free(cb->cb_firstsnap);
1589
cb->cb_firstsnap = NULL;
1590
free(cb->cb_prevsnap);
1591
cb->cb_prevsnap = NULL;
1592
}
1593
return (err);
1594
}
1595
1596
static int
1597
snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
1598
{
1599
destroy_cbdata_t *cb = arg;
1600
int err = 0;
1601
1602
/* Check for clones. */
1603
if (!cb->cb_doclones && !cb->cb_defer_destroy) {
1604
cb->cb_target = zhp;
1605
cb->cb_first = B_TRUE;
1606
err = zfs_iter_dependents_v2(zhp, 0, B_TRUE,
1607
destroy_check_dependent, cb);
1608
}
1609
1610
if (err == 0) {
1611
if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp)))
1612
nomem();
1613
}
1614
zfs_close(zhp);
1615
return (err);
1616
}
1617
1618
static int
1619
gather_snapshots(zfs_handle_t *zhp, void *arg)
1620
{
1621
destroy_cbdata_t *cb = arg;
1622
int err = 0;
1623
1624
err = zfs_iter_snapspec_v2(zhp, 0, cb->cb_snapspec,
1625
snapshot_to_nvl_cb, cb);
1626
if (err == ENOENT)
1627
err = 0;
1628
if (err != 0)
1629
goto out;
1630
1631
if (cb->cb_verbose) {
1632
err = destroy_print_snapshots(zhp, cb);
1633
if (err != 0)
1634
goto out;
1635
}
1636
1637
if (cb->cb_recurse)
1638
err = zfs_iter_filesystems_v2(zhp, 0, gather_snapshots, cb);
1639
1640
out:
1641
zfs_close(zhp);
1642
return (err);
1643
}
1644
1645
static int
1646
destroy_clones(destroy_cbdata_t *cb)
1647
{
1648
nvpair_t *pair;
1649
for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL);
1650
pair != NULL;
1651
pair = nvlist_next_nvpair(cb->cb_nvl, pair)) {
1652
zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair),
1653
ZFS_TYPE_SNAPSHOT);
1654
if (zhp != NULL) {
1655
boolean_t defer = cb->cb_defer_destroy;
1656
int err;
1657
1658
/*
1659
* We can't defer destroy non-snapshots, so set it to
1660
* false while destroying the clones.
1661
*/
1662
cb->cb_defer_destroy = B_FALSE;
1663
err = zfs_iter_dependents_v2(zhp, 0, B_FALSE,
1664
destroy_callback, cb);
1665
cb->cb_defer_destroy = defer;
1666
zfs_close(zhp);
1667
if (err != 0)
1668
return (err);
1669
}
1670
}
1671
return (0);
1672
}
1673
1674
static int
1675
zfs_do_destroy(int argc, char **argv)
1676
{
1677
destroy_cbdata_t cb = { 0 };
1678
int rv = 0;
1679
int err = 0;
1680
int c;
1681
zfs_handle_t *zhp = NULL;
1682
char *at, *pound;
1683
zfs_type_t type = ZFS_TYPE_DATASET;
1684
1685
/* check options */
1686
while ((c = getopt(argc, argv, "vpndfrR")) != -1) {
1687
switch (c) {
1688
case 'v':
1689
cb.cb_verbose = B_TRUE;
1690
break;
1691
case 'p':
1692
cb.cb_verbose = B_TRUE;
1693
cb.cb_parsable = B_TRUE;
1694
break;
1695
case 'n':
1696
cb.cb_dryrun = B_TRUE;
1697
break;
1698
case 'd':
1699
cb.cb_defer_destroy = B_TRUE;
1700
type = ZFS_TYPE_SNAPSHOT;
1701
break;
1702
case 'f':
1703
cb.cb_force = B_TRUE;
1704
break;
1705
case 'r':
1706
cb.cb_recurse = B_TRUE;
1707
break;
1708
case 'R':
1709
cb.cb_recurse = B_TRUE;
1710
cb.cb_doclones = B_TRUE;
1711
break;
1712
case '?':
1713
default:
1714
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1715
optopt);
1716
usage(B_FALSE);
1717
}
1718
}
1719
1720
argc -= optind;
1721
argv += optind;
1722
1723
/* check number of arguments */
1724
if (argc == 0) {
1725
(void) fprintf(stderr, gettext("missing dataset argument\n"));
1726
usage(B_FALSE);
1727
}
1728
if (argc > 1) {
1729
(void) fprintf(stderr, gettext("too many arguments\n"));
1730
usage(B_FALSE);
1731
}
1732
1733
at = strchr(argv[0], '@');
1734
pound = strchr(argv[0], '#');
1735
if (at != NULL) {
1736
1737
/* Build the list of snaps to destroy in cb_nvl. */
1738
cb.cb_nvl = fnvlist_alloc();
1739
1740
*at = '\0';
1741
zhp = zfs_open(g_zfs, argv[0],
1742
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
1743
if (zhp == NULL) {
1744
nvlist_free(cb.cb_nvl);
1745
return (1);
1746
}
1747
1748
cb.cb_snapspec = at + 1;
1749
if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
1750
cb.cb_error) {
1751
rv = 1;
1752
goto out;
1753
}
1754
1755
if (nvlist_empty(cb.cb_nvl)) {
1756
(void) fprintf(stderr, gettext("could not find any "
1757
"snapshots to destroy; check snapshot names.\n"));
1758
rv = 1;
1759
goto out;
1760
}
1761
1762
if (cb.cb_verbose) {
1763
char buf[16];
1764
zfs_nicebytes(cb.cb_snapused, buf, sizeof (buf));
1765
if (cb.cb_parsable) {
1766
(void) printf("reclaim\t%llu\n",
1767
(u_longlong_t)cb.cb_snapused);
1768
} else if (cb.cb_dryrun) {
1769
(void) printf(gettext("would reclaim %s\n"),
1770
buf);
1771
} else {
1772
(void) printf(gettext("will reclaim %s\n"),
1773
buf);
1774
}
1775
}
1776
1777
if (!cb.cb_dryrun) {
1778
if (cb.cb_doclones) {
1779
cb.cb_batchedsnaps = fnvlist_alloc();
1780
err = destroy_clones(&cb);
1781
if (err == 0) {
1782
err = zfs_destroy_snaps_nvl(g_zfs,
1783
cb.cb_batchedsnaps, B_FALSE);
1784
}
1785
if (err != 0) {
1786
rv = 1;
1787
goto out;
1788
}
1789
}
1790
if (err == 0) {
1791
err = zfs_destroy_snaps_nvl(g_zfs, cb.cb_nvl,
1792
cb.cb_defer_destroy);
1793
}
1794
}
1795
1796
if (err != 0)
1797
rv = 1;
1798
} else if (pound != NULL) {
1799
int err;
1800
nvlist_t *nvl;
1801
1802
if (cb.cb_dryrun) {
1803
(void) fprintf(stderr,
1804
"dryrun is not supported with bookmark\n");
1805
return (-1);
1806
}
1807
1808
if (cb.cb_defer_destroy) {
1809
(void) fprintf(stderr,
1810
"defer destroy is not supported with bookmark\n");
1811
return (-1);
1812
}
1813
1814
if (cb.cb_recurse) {
1815
(void) fprintf(stderr,
1816
"recursive is not supported with bookmark\n");
1817
return (-1);
1818
}
1819
1820
/*
1821
* Unfortunately, zfs_bookmark() doesn't honor the
1822
* casesensitivity setting. However, we can't simply
1823
* remove this check, because lzc_destroy_bookmarks()
1824
* ignores non-existent bookmarks, so this is necessary
1825
* to get a proper error message.
1826
*/
1827
if (!zfs_bookmark_exists(argv[0])) {
1828
(void) fprintf(stderr, gettext("bookmark '%s' "
1829
"does not exist.\n"), argv[0]);
1830
return (1);
1831
}
1832
1833
nvl = fnvlist_alloc();
1834
fnvlist_add_boolean(nvl, argv[0]);
1835
1836
err = lzc_destroy_bookmarks(nvl, NULL);
1837
if (err != 0) {
1838
(void) zfs_standard_error(g_zfs, err,
1839
"cannot destroy bookmark");
1840
}
1841
1842
nvlist_free(nvl);
1843
1844
return (err);
1845
} else {
1846
/* Open the given dataset */
1847
if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
1848
return (1);
1849
1850
cb.cb_target = zhp;
1851
1852
/*
1853
* Perform an explicit check for pools before going any further.
1854
*/
1855
if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
1856
zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
1857
(void) fprintf(stderr, gettext("cannot destroy '%s': "
1858
"operation does not apply to pools\n"),
1859
zfs_get_name(zhp));
1860
(void) fprintf(stderr, gettext("use 'zfs destroy -r "
1861
"%s' to destroy all datasets in the pool\n"),
1862
zfs_get_name(zhp));
1863
(void) fprintf(stderr, gettext("use 'zpool destroy %s' "
1864
"to destroy the pool itself\n"), zfs_get_name(zhp));
1865
rv = 1;
1866
goto out;
1867
}
1868
1869
/*
1870
* Check for any dependents and/or clones.
1871
*/
1872
cb.cb_first = B_TRUE;
1873
if (!cb.cb_doclones && zfs_iter_dependents_v2(zhp, 0, B_TRUE,
1874
destroy_check_dependent, &cb) != 0) {
1875
rv = 1;
1876
goto out;
1877
}
1878
1879
if (cb.cb_error) {
1880
rv = 1;
1881
goto out;
1882
}
1883
cb.cb_batchedsnaps = fnvlist_alloc();
1884
if (zfs_iter_dependents_v2(zhp, 0, B_FALSE, destroy_callback,
1885
&cb) != 0) {
1886
rv = 1;
1887
goto out;
1888
}
1889
1890
/*
1891
* Do the real thing. The callback will close the
1892
* handle regardless of whether it succeeds or not.
1893
*/
1894
err = destroy_callback(zhp, &cb);
1895
zhp = NULL;
1896
if (err == 0) {
1897
err = zfs_destroy_snaps_nvl(g_zfs,
1898
cb.cb_batchedsnaps, cb.cb_defer_destroy);
1899
}
1900
if (err != 0 || cb.cb_error == B_TRUE)
1901
rv = 1;
1902
}
1903
1904
out:
1905
fnvlist_free(cb.cb_batchedsnaps);
1906
fnvlist_free(cb.cb_nvl);
1907
if (zhp != NULL)
1908
zfs_close(zhp);
1909
return (rv);
1910
}
1911
1912
static boolean_t
1913
is_recvd_column(zprop_get_cbdata_t *cbp)
1914
{
1915
int i;
1916
zfs_get_column_t col;
1917
1918
for (i = 0; i < ZFS_GET_NCOLS &&
1919
(col = cbp->cb_columns[i]) != GET_COL_NONE; i++)
1920
if (col == GET_COL_RECVD)
1921
return (B_TRUE);
1922
return (B_FALSE);
1923
}
1924
1925
/*
1926
* Generates an nvlist with output version for every command based on params.
1927
* Purpose of this is to add a version of JSON output, considering the schema
1928
* format might be updated for each command in future.
1929
*
1930
* Schema:
1931
*
1932
* "output_version": {
1933
* "command": string,
1934
* "vers_major": integer,
1935
* "vers_minor": integer,
1936
* }
1937
*/
1938
static nvlist_t *
1939
zfs_json_schema(int maj_v, int min_v)
1940
{
1941
nvlist_t *sch = NULL;
1942
nvlist_t *ov = NULL;
1943
char cmd[MAX_CMD_LEN];
1944
snprintf(cmd, MAX_CMD_LEN, "zfs %s", current_command->name);
1945
1946
sch = fnvlist_alloc();
1947
ov = fnvlist_alloc();
1948
fnvlist_add_string(ov, "command", cmd);
1949
fnvlist_add_uint32(ov, "vers_major", maj_v);
1950
fnvlist_add_uint32(ov, "vers_minor", min_v);
1951
fnvlist_add_nvlist(sch, "output_version", ov);
1952
fnvlist_free(ov);
1953
return (sch);
1954
}
1955
1956
static void
1957
fill_dataset_info(nvlist_t *list, zfs_handle_t *zhp, boolean_t as_int)
1958
{
1959
char createtxg[ZFS_MAXPROPLEN];
1960
zfs_type_t type = zfs_get_type(zhp);
1961
nvlist_add_string(list, "name", zfs_get_name(zhp));
1962
1963
switch (type) {
1964
case ZFS_TYPE_FILESYSTEM:
1965
fnvlist_add_string(list, "type", "FILESYSTEM");
1966
break;
1967
case ZFS_TYPE_VOLUME:
1968
fnvlist_add_string(list, "type", "VOLUME");
1969
break;
1970
case ZFS_TYPE_SNAPSHOT:
1971
fnvlist_add_string(list, "type", "SNAPSHOT");
1972
break;
1973
case ZFS_TYPE_POOL:
1974
fnvlist_add_string(list, "type", "POOL");
1975
break;
1976
case ZFS_TYPE_BOOKMARK:
1977
fnvlist_add_string(list, "type", "BOOKMARK");
1978
break;
1979
default:
1980
fnvlist_add_string(list, "type", "UNKNOWN");
1981
break;
1982
}
1983
1984
if (type != ZFS_TYPE_POOL)
1985
fnvlist_add_string(list, "pool", zfs_get_pool_name(zhp));
1986
1987
if (as_int) {
1988
fnvlist_add_uint64(list, "createtxg", zfs_prop_get_int(zhp,
1989
ZFS_PROP_CREATETXG));
1990
} else {
1991
if (zfs_prop_get(zhp, ZFS_PROP_CREATETXG, createtxg,
1992
sizeof (createtxg), NULL, NULL, 0, B_TRUE) == 0)
1993
fnvlist_add_string(list, "createtxg", createtxg);
1994
}
1995
1996
if (type == ZFS_TYPE_SNAPSHOT) {
1997
char *snap = strdup(zfs_get_name(zhp));
1998
char *ds = strsep(&snap, "@");
1999
fnvlist_add_string(list, "dataset", ds);
2000
fnvlist_add_string(list, "snapshot_name", snap);
2001
free(ds);
2002
}
2003
}
2004
2005
/*
2006
* zfs get [-rHp] [-j [--json-int]] [-o all | field[,field]...]
2007
* [-s source[,source]...]
2008
* < all | property[,property]... > < fs | snap | vol > ...
2009
*
2010
* -r recurse over any child datasets
2011
* -H scripted mode. Headers are stripped, and fields are separated
2012
* by tabs instead of spaces.
2013
* -o Set of fields to display. One of "name,property,value,
2014
* received,source". Default is "name,property,value,source".
2015
* "all" is an alias for all five.
2016
* -s Set of sources to allow. One of
2017
* "local,default,inherited,received,temporary,none". Default is
2018
* all six.
2019
* -p Display values in parsable (literal) format.
2020
* -j Display output in JSON format.
2021
* --json-int Display numbers as integers instead of strings.
2022
*
2023
* Prints properties for the given datasets. The user can control which
2024
* columns to display as well as which property types to allow.
2025
*/
2026
2027
/*
2028
* Invoked to display the properties for a single dataset.
2029
*/
2030
static int
2031
get_callback(zfs_handle_t *zhp, void *data)
2032
{
2033
char buf[ZFS_MAXPROPLEN];
2034
char rbuf[ZFS_MAXPROPLEN];
2035
zprop_source_t sourcetype;
2036
char source[ZFS_MAX_DATASET_NAME_LEN];
2037
zprop_get_cbdata_t *cbp = data;
2038
nvlist_t *user_props = zfs_get_user_props(zhp);
2039
zprop_list_t *pl = cbp->cb_proplist;
2040
nvlist_t *propval;
2041
nvlist_t *item, *d = NULL, *props = NULL;
2042
const char *strval;
2043
const char *sourceval;
2044
boolean_t received = is_recvd_column(cbp);
2045
int err = 0;
2046
2047
if (cbp->cb_json) {
2048
d = fnvlist_lookup_nvlist(cbp->cb_jsobj, "datasets");
2049
if (d == NULL) {
2050
fprintf(stderr, "datasets obj not found.\n");
2051
exit(1);
2052
}
2053
props = fnvlist_alloc();
2054
}
2055
2056
for (; pl != NULL; pl = pl->pl_next) {
2057
char *recvdval = NULL;
2058
/*
2059
* Skip the special fake placeholder. This will also skip over
2060
* the name property when 'all' is specified.
2061
*/
2062
if (pl->pl_prop == ZFS_PROP_NAME &&
2063
pl == cbp->cb_proplist)
2064
continue;
2065
2066
if (pl->pl_prop != ZPROP_USERPROP) {
2067
if (zfs_prop_get(zhp, pl->pl_prop, buf,
2068
sizeof (buf), &sourcetype, source,
2069
sizeof (source),
2070
cbp->cb_literal) != 0) {
2071
if (pl->pl_all)
2072
continue;
2073
if (!zfs_prop_valid_for_type(pl->pl_prop,
2074
ZFS_TYPE_DATASET, B_FALSE)) {
2075
(void) fprintf(stderr,
2076
gettext("No such property '%s'\n"),
2077
zfs_prop_to_name(pl->pl_prop));
2078
continue;
2079
}
2080
sourcetype = ZPROP_SRC_NONE;
2081
(void) strlcpy(buf, "-", sizeof (buf));
2082
}
2083
2084
if (received && (zfs_prop_get_recvd(zhp,
2085
zfs_prop_to_name(pl->pl_prop), rbuf, sizeof (rbuf),
2086
cbp->cb_literal) == 0))
2087
recvdval = rbuf;
2088
2089
err = zprop_collect_property(zfs_get_name(zhp), cbp,
2090
zfs_prop_to_name(pl->pl_prop),
2091
buf, sourcetype, source, recvdval, props);
2092
} else if (zfs_prop_userquota(pl->pl_user_prop)) {
2093
sourcetype = ZPROP_SRC_LOCAL;
2094
2095
if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
2096
buf, sizeof (buf), cbp->cb_literal) != 0) {
2097
sourcetype = ZPROP_SRC_NONE;
2098
(void) strlcpy(buf, "-", sizeof (buf));
2099
}
2100
2101
err = zprop_collect_property(zfs_get_name(zhp), cbp,
2102
pl->pl_user_prop, buf, sourcetype, source, NULL,
2103
props);
2104
} else if (zfs_prop_written(pl->pl_user_prop)) {
2105
sourcetype = ZPROP_SRC_LOCAL;
2106
2107
if (zfs_prop_get_written(zhp, pl->pl_user_prop,
2108
buf, sizeof (buf), cbp->cb_literal) != 0) {
2109
sourcetype = ZPROP_SRC_NONE;
2110
(void) strlcpy(buf, "-", sizeof (buf));
2111
}
2112
2113
err = zprop_collect_property(zfs_get_name(zhp), cbp,
2114
pl->pl_user_prop, buf, sourcetype, source, NULL,
2115
props);
2116
} else {
2117
if (nvlist_lookup_nvlist(user_props,
2118
pl->pl_user_prop, &propval) != 0) {
2119
if (pl->pl_all)
2120
continue;
2121
sourcetype = ZPROP_SRC_NONE;
2122
strval = "-";
2123
} else {
2124
strval = fnvlist_lookup_string(propval,
2125
ZPROP_VALUE);
2126
sourceval = fnvlist_lookup_string(propval,
2127
ZPROP_SOURCE);
2128
2129
if (strcmp(sourceval,
2130
zfs_get_name(zhp)) == 0) {
2131
sourcetype = ZPROP_SRC_LOCAL;
2132
} else if (strcmp(sourceval,
2133
ZPROP_SOURCE_VAL_RECVD) == 0) {
2134
sourcetype = ZPROP_SRC_RECEIVED;
2135
} else {
2136
sourcetype = ZPROP_SRC_INHERITED;
2137
(void) strlcpy(source,
2138
sourceval, sizeof (source));
2139
}
2140
}
2141
2142
if (received && (zfs_prop_get_recvd(zhp,
2143
pl->pl_user_prop, rbuf, sizeof (rbuf),
2144
cbp->cb_literal) == 0))
2145
recvdval = rbuf;
2146
2147
err = zprop_collect_property(zfs_get_name(zhp), cbp,
2148
pl->pl_user_prop, strval, sourcetype,
2149
source, recvdval, props);
2150
}
2151
if (err != 0)
2152
return (err);
2153
}
2154
2155
if (cbp->cb_json) {
2156
if (!nvlist_empty(props)) {
2157
item = fnvlist_alloc();
2158
fill_dataset_info(item, zhp, cbp->cb_json_as_int);
2159
fnvlist_add_nvlist(item, "properties", props);
2160
fnvlist_add_nvlist(d, zfs_get_name(zhp), item);
2161
fnvlist_free(props);
2162
fnvlist_free(item);
2163
} else {
2164
fnvlist_free(props);
2165
}
2166
}
2167
2168
return (0);
2169
}
2170
2171
static int
2172
zfs_do_get(int argc, char **argv)
2173
{
2174
zprop_get_cbdata_t cb = { 0 };
2175
int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
2176
int types = ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK;
2177
char *fields;
2178
int ret = 0;
2179
int limit = 0;
2180
zprop_list_t fake_name = { 0 };
2181
nvlist_t *data;
2182
2183
/*
2184
* Set up default columns and sources.
2185
*/
2186
cb.cb_sources = ZPROP_SRC_ALL;
2187
cb.cb_columns[0] = GET_COL_NAME;
2188
cb.cb_columns[1] = GET_COL_PROPERTY;
2189
cb.cb_columns[2] = GET_COL_VALUE;
2190
cb.cb_columns[3] = GET_COL_SOURCE;
2191
cb.cb_type = ZFS_TYPE_DATASET;
2192
2193
struct option long_options[] = {
2194
{"json", no_argument, NULL, 'j'},
2195
{"json-int", no_argument, NULL, ZFS_OPTION_JSON_NUMS_AS_INT},
2196
{0, 0, 0, 0}
2197
};
2198
2199
/* check options */
2200
while ((c = getopt_long(argc, argv, ":d:o:s:jrt:Hp", long_options,
2201
NULL)) != -1) {
2202
switch (c) {
2203
case 'p':
2204
cb.cb_literal = B_TRUE;
2205
break;
2206
case 'd':
2207
limit = parse_depth(optarg, &flags);
2208
break;
2209
case 'r':
2210
flags |= ZFS_ITER_RECURSE;
2211
break;
2212
case 'H':
2213
cb.cb_scripted = B_TRUE;
2214
break;
2215
case 'j':
2216
cb.cb_json = B_TRUE;
2217
cb.cb_jsobj = zfs_json_schema(0, 1);
2218
data = fnvlist_alloc();
2219
fnvlist_add_nvlist(cb.cb_jsobj, "datasets", data);
2220
fnvlist_free(data);
2221
break;
2222
case ZFS_OPTION_JSON_NUMS_AS_INT:
2223
cb.cb_json_as_int = B_TRUE;
2224
cb.cb_literal = B_TRUE;
2225
break;
2226
case ':':
2227
(void) fprintf(stderr, gettext("missing argument for "
2228
"'%c' option\n"), optopt);
2229
usage(B_FALSE);
2230
break;
2231
case 'o':
2232
/*
2233
* Process the set of columns to display. We zero out
2234
* the structure to give us a blank slate.
2235
*/
2236
memset(&cb.cb_columns, 0, sizeof (cb.cb_columns));
2237
2238
i = 0;
2239
for (char *tok; (tok = strsep(&optarg, ",")); ) {
2240
static const char *const col_subopts[] =
2241
{ "name", "property", "value",
2242
"received", "source", "all" };
2243
static const zfs_get_column_t col_subopt_col[] =
2244
{ GET_COL_NAME, GET_COL_PROPERTY, GET_COL_VALUE,
2245
GET_COL_RECVD, GET_COL_SOURCE };
2246
static const int col_subopt_flags[] =
2247
{ 0, 0, 0, ZFS_ITER_RECVD_PROPS, 0 };
2248
2249
if (i == ZFS_GET_NCOLS) {
2250
(void) fprintf(stderr, gettext("too "
2251
"many fields given to -o "
2252
"option\n"));
2253
usage(B_FALSE);
2254
}
2255
2256
for (c = 0; c < ARRAY_SIZE(col_subopts); ++c)
2257
if (strcmp(tok, col_subopts[c]) == 0)
2258
goto found;
2259
2260
(void) fprintf(stderr,
2261
gettext("invalid column name '%s'\n"), tok);
2262
usage(B_FALSE);
2263
2264
found:
2265
if (c >= 5) {
2266
if (i > 0) {
2267
(void) fprintf(stderr,
2268
gettext("\"all\" conflicts "
2269
"with specific fields "
2270
"given to -o option\n"));
2271
usage(B_FALSE);
2272
}
2273
2274
memcpy(cb.cb_columns, col_subopt_col,
2275
sizeof (col_subopt_col));
2276
flags |= ZFS_ITER_RECVD_PROPS;
2277
i = ZFS_GET_NCOLS;
2278
} else {
2279
cb.cb_columns[i++] = col_subopt_col[c];
2280
flags |= col_subopt_flags[c];
2281
}
2282
}
2283
break;
2284
2285
case 's':
2286
cb.cb_sources = 0;
2287
2288
for (char *tok; (tok = strsep(&optarg, ",")); ) {
2289
static const char *const source_opt[] = {
2290
"local", "default",
2291
"inherited", "received",
2292
"temporary", "none" };
2293
static const int source_flg[] = {
2294
ZPROP_SRC_LOCAL, ZPROP_SRC_DEFAULT,
2295
ZPROP_SRC_INHERITED, ZPROP_SRC_RECEIVED,
2296
ZPROP_SRC_TEMPORARY, ZPROP_SRC_NONE };
2297
2298
for (i = 0; i < ARRAY_SIZE(source_opt); ++i)
2299
if (strcmp(tok, source_opt[i]) == 0) {
2300
cb.cb_sources |= source_flg[i];
2301
goto found2;
2302
}
2303
2304
(void) fprintf(stderr,
2305
gettext("invalid source '%s'\n"), tok);
2306
usage(B_FALSE);
2307
found2:;
2308
}
2309
break;
2310
2311
case 't':
2312
types = 0;
2313
flags &= ~ZFS_ITER_PROP_LISTSNAPS;
2314
2315
for (char *tok; (tok = strsep(&optarg, ",")); ) {
2316
static const char *const type_opts[] = {
2317
"filesystem",
2318
"fs",
2319
"volume",
2320
"vol",
2321
"snapshot",
2322
"snap",
2323
"bookmark",
2324
"all"
2325
};
2326
static const int type_types[] = {
2327
ZFS_TYPE_FILESYSTEM,
2328
ZFS_TYPE_FILESYSTEM,
2329
ZFS_TYPE_VOLUME,
2330
ZFS_TYPE_VOLUME,
2331
ZFS_TYPE_SNAPSHOT,
2332
ZFS_TYPE_SNAPSHOT,
2333
ZFS_TYPE_BOOKMARK,
2334
ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK
2335
};
2336
2337
for (i = 0; i < ARRAY_SIZE(type_opts); ++i)
2338
if (strcmp(tok, type_opts[i]) == 0) {
2339
types |= type_types[i];
2340
goto found3;
2341
}
2342
2343
(void) fprintf(stderr,
2344
gettext("invalid type '%s'\n"), tok);
2345
usage(B_FALSE);
2346
found3:;
2347
}
2348
break;
2349
case '?':
2350
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2351
optopt);
2352
usage(B_FALSE);
2353
}
2354
}
2355
2356
argc -= optind;
2357
argv += optind;
2358
2359
if (argc < 1) {
2360
(void) fprintf(stderr, gettext("missing property "
2361
"argument\n"));
2362
usage(B_FALSE);
2363
}
2364
2365
if (!cb.cb_json && cb.cb_json_as_int) {
2366
(void) fprintf(stderr, gettext("'--json-int' only works with"
2367
" '-j' option\n"));
2368
usage(B_FALSE);
2369
}
2370
2371
fields = argv[0];
2372
2373
/*
2374
* Handle users who want to get all snapshots or bookmarks
2375
* of a dataset (ex. 'zfs get -t snapshot refer <dataset>').
2376
*/
2377
if ((types == ZFS_TYPE_SNAPSHOT || types == ZFS_TYPE_BOOKMARK) &&
2378
argc > 1 && (flags & ZFS_ITER_RECURSE) == 0 && limit == 0) {
2379
flags |= (ZFS_ITER_DEPTH_LIMIT | ZFS_ITER_RECURSE);
2380
limit = 1;
2381
}
2382
2383
if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
2384
!= 0)
2385
usage(B_FALSE);
2386
2387
argc--;
2388
argv++;
2389
2390
/*
2391
* As part of zfs_expand_proplist(), we keep track of the maximum column
2392
* width for each property. For the 'NAME' (and 'SOURCE') columns, we
2393
* need to know the maximum name length. However, the user likely did
2394
* not specify 'name' as one of the properties to fetch, so we need to
2395
* make sure we always include at least this property for
2396
* print_get_headers() to work properly.
2397
*/
2398
if (cb.cb_proplist != NULL) {
2399
fake_name.pl_prop = ZFS_PROP_NAME;
2400
fake_name.pl_width = strlen(gettext("NAME"));
2401
fake_name.pl_next = cb.cb_proplist;
2402
cb.cb_proplist = &fake_name;
2403
}
2404
2405
cb.cb_first = B_TRUE;
2406
2407
/* run for each object */
2408
ret = zfs_for_each(argc, argv, flags, types, NULL,
2409
&cb.cb_proplist, limit, get_callback, &cb);
2410
2411
if (ret == 0 && cb.cb_json)
2412
zcmd_print_json(cb.cb_jsobj);
2413
else if (ret != 0 && cb.cb_json)
2414
nvlist_free(cb.cb_jsobj);
2415
2416
if (cb.cb_proplist == &fake_name)
2417
zprop_free_list(fake_name.pl_next);
2418
else
2419
zprop_free_list(cb.cb_proplist);
2420
2421
return (ret);
2422
}
2423
2424
/*
2425
* inherit [-rS] <property> <fs|vol> ...
2426
*
2427
* -r Recurse over all children
2428
* -S Revert to received value, if any
2429
*
2430
* For each dataset specified on the command line, inherit the given property
2431
* from its parent. Inheriting a property at the pool level will cause it to
2432
* use the default value. The '-r' flag will recurse over all children, and is
2433
* useful for setting a property on a hierarchy-wide basis, regardless of any
2434
* local modifications for each dataset.
2435
*/
2436
2437
typedef struct inherit_cbdata {
2438
const char *cb_propname;
2439
boolean_t cb_received;
2440
} inherit_cbdata_t;
2441
2442
static int
2443
inherit_recurse_cb(zfs_handle_t *zhp, void *data)
2444
{
2445
inherit_cbdata_t *cb = data;
2446
zfs_prop_t prop = zfs_name_to_prop(cb->cb_propname);
2447
2448
/*
2449
* If we're doing it recursively, then ignore properties that
2450
* are not valid for this type of dataset.
2451
*/
2452
if (prop != ZPROP_INVAL &&
2453
!zfs_prop_valid_for_type(prop, zfs_get_type(zhp), B_FALSE))
2454
return (0);
2455
2456
return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
2457
}
2458
2459
static int
2460
inherit_cb(zfs_handle_t *zhp, void *data)
2461
{
2462
inherit_cbdata_t *cb = data;
2463
2464
return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
2465
}
2466
2467
static int
2468
zfs_do_inherit(int argc, char **argv)
2469
{
2470
int c;
2471
zfs_prop_t prop;
2472
inherit_cbdata_t cb = { 0 };
2473
char *propname;
2474
int ret = 0;
2475
int flags = 0;
2476
boolean_t received = B_FALSE;
2477
2478
/* check options */
2479
while ((c = getopt(argc, argv, "rS")) != -1) {
2480
switch (c) {
2481
case 'r':
2482
flags |= ZFS_ITER_RECURSE;
2483
break;
2484
case 'S':
2485
received = B_TRUE;
2486
break;
2487
case '?':
2488
default:
2489
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2490
optopt);
2491
usage(B_FALSE);
2492
}
2493
}
2494
2495
argc -= optind;
2496
argv += optind;
2497
2498
/* check number of arguments */
2499
if (argc < 1) {
2500
(void) fprintf(stderr, gettext("missing property argument\n"));
2501
usage(B_FALSE);
2502
}
2503
if (argc < 2) {
2504
(void) fprintf(stderr, gettext("missing dataset argument\n"));
2505
usage(B_FALSE);
2506
}
2507
2508
propname = argv[0];
2509
argc--;
2510
argv++;
2511
2512
if ((prop = zfs_name_to_prop(propname)) != ZPROP_USERPROP) {
2513
if (zfs_prop_readonly(prop)) {
2514
(void) fprintf(stderr, gettext(
2515
"%s property is read-only\n"),
2516
propname);
2517
return (1);
2518
}
2519
if (!zfs_prop_inheritable(prop) && !received) {
2520
(void) fprintf(stderr, gettext("'%s' property cannot "
2521
"be inherited\n"), propname);
2522
if (prop == ZFS_PROP_QUOTA ||
2523
prop == ZFS_PROP_RESERVATION ||
2524
prop == ZFS_PROP_REFQUOTA ||
2525
prop == ZFS_PROP_REFRESERVATION) {
2526
(void) fprintf(stderr, gettext("use 'zfs set "
2527
"%s=none' to clear\n"), propname);
2528
(void) fprintf(stderr, gettext("use 'zfs "
2529
"inherit -S %s' to revert to received "
2530
"value\n"), propname);
2531
}
2532
return (1);
2533
}
2534
if (received && (prop == ZFS_PROP_VOLSIZE ||
2535
prop == ZFS_PROP_VERSION)) {
2536
(void) fprintf(stderr, gettext("'%s' property cannot "
2537
"be reverted to a received value\n"), propname);
2538
return (1);
2539
}
2540
} else if (!zfs_prop_user(propname)) {
2541
(void) fprintf(stderr, gettext("invalid property '%s'\n"),
2542
propname);
2543
usage(B_FALSE);
2544
}
2545
2546
cb.cb_propname = propname;
2547
cb.cb_received = received;
2548
2549
if (flags & ZFS_ITER_RECURSE) {
2550
ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
2551
NULL, NULL, 0, inherit_recurse_cb, &cb);
2552
} else {
2553
ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
2554
NULL, NULL, 0, inherit_cb, &cb);
2555
}
2556
2557
return (ret);
2558
}
2559
2560
typedef struct upgrade_cbdata {
2561
uint64_t cb_numupgraded;
2562
uint64_t cb_numsamegraded;
2563
uint64_t cb_numfailed;
2564
uint64_t cb_version;
2565
boolean_t cb_newer;
2566
boolean_t cb_foundone;
2567
char cb_lastfs[ZFS_MAX_DATASET_NAME_LEN];
2568
} upgrade_cbdata_t;
2569
2570
static int
2571
same_pool(zfs_handle_t *zhp, const char *name)
2572
{
2573
int len1 = strcspn(name, "/@");
2574
const char *zhname = zfs_get_name(zhp);
2575
int len2 = strcspn(zhname, "/@");
2576
2577
if (len1 != len2)
2578
return (B_FALSE);
2579
return (strncmp(name, zhname, len1) == 0);
2580
}
2581
2582
static int
2583
upgrade_list_callback(zfs_handle_t *zhp, void *data)
2584
{
2585
upgrade_cbdata_t *cb = data;
2586
int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
2587
2588
/* list if it's old/new */
2589
if ((!cb->cb_newer && version < ZPL_VERSION) ||
2590
(cb->cb_newer && version > ZPL_VERSION)) {
2591
char *str;
2592
if (cb->cb_newer) {
2593
str = gettext("The following filesystems are "
2594
"formatted using a newer software version and\n"
2595
"cannot be accessed on the current system.\n\n");
2596
} else {
2597
str = gettext("The following filesystems are "
2598
"out of date, and can be upgraded. After being\n"
2599
"upgraded, these filesystems (and any 'zfs send' "
2600
"streams generated from\n"
2601
"subsequent snapshots) will no longer be "
2602
"accessible by older software versions.\n\n");
2603
}
2604
2605
if (!cb->cb_foundone) {
2606
(void) puts(str);
2607
(void) printf(gettext("VER FILESYSTEM\n"));
2608
(void) printf(gettext("--- ------------\n"));
2609
cb->cb_foundone = B_TRUE;
2610
}
2611
2612
(void) printf("%2u %s\n", version, zfs_get_name(zhp));
2613
}
2614
2615
return (0);
2616
}
2617
2618
static int
2619
upgrade_set_callback(zfs_handle_t *zhp, void *data)
2620
{
2621
upgrade_cbdata_t *cb = data;
2622
int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
2623
int needed_spa_version;
2624
int spa_version;
2625
2626
if (zfs_spa_version(zhp, &spa_version) < 0)
2627
return (-1);
2628
2629
needed_spa_version = zfs_spa_version_map(cb->cb_version);
2630
2631
if (needed_spa_version < 0)
2632
return (-1);
2633
2634
if (spa_version < needed_spa_version) {
2635
/* can't upgrade */
2636
(void) printf(gettext("%s: can not be "
2637
"upgraded; the pool version needs to first "
2638
"be upgraded\nto version %d\n\n"),
2639
zfs_get_name(zhp), needed_spa_version);
2640
cb->cb_numfailed++;
2641
return (0);
2642
}
2643
2644
/* upgrade */
2645
if (version < cb->cb_version) {
2646
char verstr[24];
2647
(void) snprintf(verstr, sizeof (verstr),
2648
"%llu", (u_longlong_t)cb->cb_version);
2649
if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
2650
/*
2651
* If they did "zfs upgrade -a", then we could
2652
* be doing ioctls to different pools. We need
2653
* to log this history once to each pool, and bypass
2654
* the normal history logging that happens in main().
2655
*/
2656
(void) zpool_log_history(g_zfs, history_str);
2657
log_history = B_FALSE;
2658
}
2659
if (zfs_prop_set(zhp, "version", verstr) == 0)
2660
cb->cb_numupgraded++;
2661
else
2662
cb->cb_numfailed++;
2663
(void) strlcpy(cb->cb_lastfs, zfs_get_name(zhp),
2664
sizeof (cb->cb_lastfs));
2665
} else if (version > cb->cb_version) {
2666
/* can't downgrade */
2667
(void) printf(gettext("%s: can not be downgraded; "
2668
"it is already at version %u\n"),
2669
zfs_get_name(zhp), version);
2670
cb->cb_numfailed++;
2671
} else {
2672
cb->cb_numsamegraded++;
2673
}
2674
return (0);
2675
}
2676
2677
/*
2678
* zfs upgrade
2679
* zfs upgrade -v
2680
* zfs upgrade [-r] [-V <version>] <-a | filesystem>
2681
*/
2682
static int
2683
zfs_do_upgrade(int argc, char **argv)
2684
{
2685
boolean_t all = B_FALSE;
2686
boolean_t showversions = B_FALSE;
2687
int ret = 0;
2688
upgrade_cbdata_t cb = { 0 };
2689
int c;
2690
int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
2691
2692
/* check options */
2693
while ((c = getopt(argc, argv, "rvV:a")) != -1) {
2694
switch (c) {
2695
case 'r':
2696
flags |= ZFS_ITER_RECURSE;
2697
break;
2698
case 'v':
2699
showversions = B_TRUE;
2700
break;
2701
case 'V':
2702
if (zfs_prop_string_to_index(ZFS_PROP_VERSION,
2703
optarg, &cb.cb_version) != 0) {
2704
(void) fprintf(stderr,
2705
gettext("invalid version %s\n"), optarg);
2706
usage(B_FALSE);
2707
}
2708
break;
2709
case 'a':
2710
all = B_TRUE;
2711
break;
2712
case '?':
2713
default:
2714
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2715
optopt);
2716
usage(B_FALSE);
2717
}
2718
}
2719
2720
argc -= optind;
2721
argv += optind;
2722
2723
if ((!all && !argc) && ((flags & ZFS_ITER_RECURSE) | cb.cb_version))
2724
usage(B_FALSE);
2725
if (showversions && (flags & ZFS_ITER_RECURSE || all ||
2726
cb.cb_version || argc))
2727
usage(B_FALSE);
2728
if ((all || argc) && (showversions))
2729
usage(B_FALSE);
2730
if (all && argc)
2731
usage(B_FALSE);
2732
2733
if (showversions) {
2734
/* Show info on available versions. */
2735
(void) printf(gettext("The following filesystem versions are "
2736
"supported:\n\n"));
2737
(void) printf(gettext("VER DESCRIPTION\n"));
2738
(void) printf("--- -----------------------------------------"
2739
"---------------\n");
2740
(void) printf(gettext(" 1 Initial ZFS filesystem version\n"));
2741
(void) printf(gettext(" 2 Enhanced directory entries\n"));
2742
(void) printf(gettext(" 3 Case insensitive and filesystem "
2743
"user identifier (FUID)\n"));
2744
(void) printf(gettext(" 4 userquota, groupquota "
2745
"properties\n"));
2746
(void) printf(gettext(" 5 System attributes\n"));
2747
(void) printf(gettext("\nFor more information on a particular "
2748
"version, including supported releases,\n"));
2749
(void) printf("see the ZFS Administration Guide.\n\n");
2750
ret = 0;
2751
} else if (argc || all) {
2752
/* Upgrade filesystems */
2753
if (cb.cb_version == 0)
2754
cb.cb_version = ZPL_VERSION;
2755
ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM,
2756
NULL, NULL, 0, upgrade_set_callback, &cb);
2757
(void) printf(gettext("%llu filesystems upgraded\n"),
2758
(u_longlong_t)cb.cb_numupgraded);
2759
if (cb.cb_numsamegraded) {
2760
(void) printf(gettext("%llu filesystems already at "
2761
"this version\n"),
2762
(u_longlong_t)cb.cb_numsamegraded);
2763
}
2764
if (cb.cb_numfailed != 0)
2765
ret = 1;
2766
} else {
2767
/* List old-version filesystems */
2768
boolean_t found;
2769
(void) printf(gettext("This system is currently running "
2770
"ZFS filesystem version %llu.\n\n"), ZPL_VERSION);
2771
2772
flags |= ZFS_ITER_RECURSE;
2773
ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
2774
NULL, NULL, 0, upgrade_list_callback, &cb);
2775
2776
found = cb.cb_foundone;
2777
cb.cb_foundone = B_FALSE;
2778
cb.cb_newer = B_TRUE;
2779
2780
ret |= zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
2781
NULL, NULL, 0, upgrade_list_callback, &cb);
2782
2783
if (!cb.cb_foundone && !found) {
2784
(void) printf(gettext("All filesystems are "
2785
"formatted with the current version.\n"));
2786
}
2787
}
2788
2789
return (ret);
2790
}
2791
2792
/*
2793
* zfs userspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
2794
* [-S field [-S field]...] [-t type[,...]]
2795
* filesystem | snapshot | path
2796
* zfs groupspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
2797
* [-S field [-S field]...] [-t type[,...]]
2798
* filesystem | snapshot | path
2799
* zfs projectspace [-Hp] [-o field[,...]] [-s field [-s field]...]
2800
* [-S field [-S field]...] filesystem | snapshot | path
2801
*
2802
* -H Scripted mode; elide headers and separate columns by tabs.
2803
* -i Translate SID to POSIX ID.
2804
* -n Print numeric ID instead of user/group name.
2805
* -o Control which fields to display.
2806
* -p Use exact (parsable) numeric output.
2807
* -s Specify sort columns, descending order.
2808
* -S Specify sort columns, ascending order.
2809
* -t Control which object types to display.
2810
*
2811
* Displays space consumed by, and quotas on, each user in the specified
2812
* filesystem or snapshot.
2813
*/
2814
2815
/* us_field_types, us_field_hdr and us_field_names should be kept in sync */
2816
enum us_field_types {
2817
USFIELD_TYPE,
2818
USFIELD_NAME,
2819
USFIELD_USED,
2820
USFIELD_QUOTA,
2821
USFIELD_OBJUSED,
2822
USFIELD_OBJQUOTA
2823
};
2824
static const char *const us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA",
2825
"OBJUSED", "OBJQUOTA" };
2826
static const char *const us_field_names[] = { "type", "name", "used", "quota",
2827
"objused", "objquota" };
2828
#define USFIELD_LAST (sizeof (us_field_names) / sizeof (char *))
2829
2830
#define USTYPE_PSX_GRP (1 << 0)
2831
#define USTYPE_PSX_USR (1 << 1)
2832
#define USTYPE_SMB_GRP (1 << 2)
2833
#define USTYPE_SMB_USR (1 << 3)
2834
#define USTYPE_PROJ (1 << 4)
2835
#define USTYPE_ALL \
2836
(USTYPE_PSX_GRP | USTYPE_PSX_USR | USTYPE_SMB_GRP | USTYPE_SMB_USR | \
2837
USTYPE_PROJ)
2838
2839
static int us_type_bits[] = {
2840
USTYPE_PSX_GRP,
2841
USTYPE_PSX_USR,
2842
USTYPE_SMB_GRP,
2843
USTYPE_SMB_USR,
2844
USTYPE_ALL
2845
};
2846
static const char *const us_type_names[] = { "posixgroup", "posixuser",
2847
"smbgroup", "smbuser", "all" };
2848
2849
typedef struct us_node {
2850
nvlist_t *usn_nvl;
2851
uu_avl_node_t usn_avlnode;
2852
uu_list_node_t usn_listnode;
2853
} us_node_t;
2854
2855
typedef struct us_cbdata {
2856
nvlist_t **cb_nvlp;
2857
uu_avl_pool_t *cb_avl_pool;
2858
uu_avl_t *cb_avl;
2859
boolean_t cb_numname;
2860
boolean_t cb_nicenum;
2861
boolean_t cb_sid2posix;
2862
zfs_userquota_prop_t cb_prop;
2863
zfs_sort_column_t *cb_sortcol;
2864
size_t cb_width[USFIELD_LAST];
2865
} us_cbdata_t;
2866
2867
static boolean_t us_populated = B_FALSE;
2868
2869
typedef struct {
2870
zfs_sort_column_t *si_sortcol;
2871
boolean_t si_numname;
2872
} us_sort_info_t;
2873
2874
static int
2875
us_field_index(const char *field)
2876
{
2877
for (int i = 0; i < USFIELD_LAST; i++) {
2878
if (strcmp(field, us_field_names[i]) == 0)
2879
return (i);
2880
}
2881
2882
return (-1);
2883
}
2884
2885
static int
2886
us_compare(const void *larg, const void *rarg, void *unused)
2887
{
2888
const us_node_t *l = larg;
2889
const us_node_t *r = rarg;
2890
us_sort_info_t *si = (us_sort_info_t *)unused;
2891
zfs_sort_column_t *sortcol = si->si_sortcol;
2892
boolean_t numname = si->si_numname;
2893
nvlist_t *lnvl = l->usn_nvl;
2894
nvlist_t *rnvl = r->usn_nvl;
2895
int rc = 0;
2896
boolean_t lvb, rvb;
2897
2898
for (; sortcol != NULL; sortcol = sortcol->sc_next) {
2899
const char *lvstr = "";
2900
const char *rvstr = "";
2901
uint32_t lv32 = 0;
2902
uint32_t rv32 = 0;
2903
uint64_t lv64 = 0;
2904
uint64_t rv64 = 0;
2905
zfs_prop_t prop = sortcol->sc_prop;
2906
const char *propname = NULL;
2907
boolean_t reverse = sortcol->sc_reverse;
2908
2909
switch (prop) {
2910
case ZFS_PROP_TYPE:
2911
propname = "type";
2912
(void) nvlist_lookup_uint32(lnvl, propname, &lv32);
2913
(void) nvlist_lookup_uint32(rnvl, propname, &rv32);
2914
if (rv32 != lv32)
2915
rc = (rv32 < lv32) ? 1 : -1;
2916
break;
2917
case ZFS_PROP_NAME:
2918
propname = "name";
2919
if (numname) {
2920
compare_nums:
2921
(void) nvlist_lookup_uint64(lnvl, propname,
2922
&lv64);
2923
(void) nvlist_lookup_uint64(rnvl, propname,
2924
&rv64);
2925
if (rv64 != lv64)
2926
rc = (rv64 < lv64) ? 1 : -1;
2927
} else {
2928
if ((nvlist_lookup_string(lnvl, propname,
2929
&lvstr) == ENOENT) ||
2930
(nvlist_lookup_string(rnvl, propname,
2931
&rvstr) == ENOENT)) {
2932
goto compare_nums;
2933
}
2934
rc = strcmp(lvstr, rvstr);
2935
}
2936
break;
2937
case ZFS_PROP_USED:
2938
case ZFS_PROP_QUOTA:
2939
if (!us_populated)
2940
break;
2941
if (prop == ZFS_PROP_USED)
2942
propname = "used";
2943
else
2944
propname = "quota";
2945
(void) nvlist_lookup_uint64(lnvl, propname, &lv64);
2946
(void) nvlist_lookup_uint64(rnvl, propname, &rv64);
2947
if (rv64 != lv64)
2948
rc = (rv64 < lv64) ? 1 : -1;
2949
break;
2950
2951
default:
2952
break;
2953
}
2954
2955
if (rc != 0) {
2956
if (rc < 0)
2957
return (reverse ? 1 : -1);
2958
else
2959
return (reverse ? -1 : 1);
2960
}
2961
}
2962
2963
/*
2964
* If entries still seem to be the same, check if they are of the same
2965
* type (smbentity is added only if we are doing SID to POSIX ID
2966
* translation where we can have duplicate type/name combinations).
2967
*/
2968
if (nvlist_lookup_boolean_value(lnvl, "smbentity", &lvb) == 0 &&
2969
nvlist_lookup_boolean_value(rnvl, "smbentity", &rvb) == 0 &&
2970
lvb != rvb)
2971
return (lvb < rvb ? -1 : 1);
2972
2973
return (0);
2974
}
2975
2976
static boolean_t
2977
zfs_prop_is_user(unsigned p)
2978
{
2979
return (p == ZFS_PROP_USERUSED || p == ZFS_PROP_USERQUOTA ||
2980
p == ZFS_PROP_USEROBJUSED || p == ZFS_PROP_USEROBJQUOTA);
2981
}
2982
2983
static boolean_t
2984
zfs_prop_is_group(unsigned p)
2985
{
2986
return (p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA ||
2987
p == ZFS_PROP_GROUPOBJUSED || p == ZFS_PROP_GROUPOBJQUOTA);
2988
}
2989
2990
static boolean_t
2991
zfs_prop_is_project(unsigned p)
2992
{
2993
return (p == ZFS_PROP_PROJECTUSED || p == ZFS_PROP_PROJECTQUOTA ||
2994
p == ZFS_PROP_PROJECTOBJUSED || p == ZFS_PROP_PROJECTOBJQUOTA);
2995
}
2996
2997
static inline const char *
2998
us_type2str(unsigned field_type)
2999
{
3000
switch (field_type) {
3001
case USTYPE_PSX_USR:
3002
return ("POSIX User");
3003
case USTYPE_PSX_GRP:
3004
return ("POSIX Group");
3005
case USTYPE_SMB_USR:
3006
return ("SMB User");
3007
case USTYPE_SMB_GRP:
3008
return ("SMB Group");
3009
case USTYPE_PROJ:
3010
return ("Project");
3011
default:
3012
return ("Undefined");
3013
}
3014
}
3015
3016
static int
3017
userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space,
3018
uint64_t default_quota)
3019
{
3020
us_cbdata_t *cb = (us_cbdata_t *)arg;
3021
zfs_userquota_prop_t prop = cb->cb_prop;
3022
char *name = NULL;
3023
const char *propname;
3024
char sizebuf[32];
3025
us_node_t *node;
3026
uu_avl_pool_t *avl_pool = cb->cb_avl_pool;
3027
uu_avl_t *avl = cb->cb_avl;
3028
uu_avl_index_t idx;
3029
nvlist_t *props;
3030
us_node_t *n;
3031
zfs_sort_column_t *sortcol = cb->cb_sortcol;
3032
unsigned type = 0;
3033
const char *typestr;
3034
size_t namelen;
3035
size_t typelen;
3036
size_t sizelen;
3037
int typeidx, nameidx, sizeidx;
3038
us_sort_info_t sortinfo = { sortcol, cb->cb_numname };
3039
boolean_t smbentity = B_FALSE;
3040
3041
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
3042
nomem();
3043
node = safe_malloc(sizeof (us_node_t));
3044
uu_avl_node_init(node, &node->usn_avlnode, avl_pool);
3045
node->usn_nvl = props;
3046
3047
if (domain != NULL && domain[0] != '\0') {
3048
#ifdef HAVE_IDMAP
3049
/* SMB */
3050
char sid[MAXNAMELEN + 32];
3051
uid_t id;
3052
uint64_t classes;
3053
int err;
3054
directory_error_t e;
3055
3056
smbentity = B_TRUE;
3057
3058
(void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid);
3059
3060
if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
3061
type = USTYPE_SMB_GRP;
3062
err = sid_to_id(sid, B_FALSE, &id);
3063
} else {
3064
type = USTYPE_SMB_USR;
3065
err = sid_to_id(sid, B_TRUE, &id);
3066
}
3067
3068
if (err == 0) {
3069
rid = id;
3070
if (!cb->cb_sid2posix) {
3071
e = directory_name_from_sid(NULL, sid, &name,
3072
&classes);
3073
if (e != NULL)
3074
directory_error_free(e);
3075
if (name == NULL)
3076
name = sid;
3077
}
3078
}
3079
#else
3080
nvlist_free(props);
3081
free(node);
3082
3083
return (-1);
3084
#endif /* HAVE_IDMAP */
3085
}
3086
3087
if (cb->cb_sid2posix || domain == NULL || domain[0] == '\0') {
3088
/* POSIX or -i */
3089
if (zfs_prop_is_group(prop)) {
3090
type = USTYPE_PSX_GRP;
3091
if (!cb->cb_numname) {
3092
struct group *g;
3093
3094
if ((g = getgrgid(rid)) != NULL)
3095
name = g->gr_name;
3096
}
3097
} else if (zfs_prop_is_user(prop)) {
3098
type = USTYPE_PSX_USR;
3099
if (!cb->cb_numname) {
3100
struct passwd *p;
3101
3102
if ((p = getpwuid(rid)) != NULL)
3103
name = p->pw_name;
3104
}
3105
} else {
3106
type = USTYPE_PROJ;
3107
}
3108
}
3109
3110
/*
3111
* Make sure that the type/name combination is unique when doing
3112
* SID to POSIX ID translation (hence changing the type from SMB to
3113
* POSIX).
3114
*/
3115
if (cb->cb_sid2posix &&
3116
nvlist_add_boolean_value(props, "smbentity", smbentity) != 0)
3117
nomem();
3118
3119
/* Calculate/update width of TYPE field */
3120
typestr = us_type2str(type);
3121
typelen = strlen(gettext(typestr));
3122
typeidx = us_field_index("type");
3123
if (typelen > cb->cb_width[typeidx])
3124
cb->cb_width[typeidx] = typelen;
3125
if (nvlist_add_uint32(props, "type", type) != 0)
3126
nomem();
3127
3128
/* Calculate/update width of NAME field */
3129
if ((cb->cb_numname && cb->cb_sid2posix) || name == NULL) {
3130
if (nvlist_add_uint64(props, "name", rid) != 0)
3131
nomem();
3132
namelen = snprintf(NULL, 0, "%u", rid);
3133
} else {
3134
if (nvlist_add_string(props, "name", name) != 0)
3135
nomem();
3136
namelen = strlen(name);
3137
}
3138
nameidx = us_field_index("name");
3139
if (nameidx >= 0 && namelen > cb->cb_width[nameidx])
3140
cb->cb_width[nameidx] = namelen;
3141
3142
/*
3143
* Check if this type/name combination is in the list and update it;
3144
* otherwise add new node to the list.
3145
*/
3146
if ((n = uu_avl_find(avl, node, &sortinfo, &idx)) == NULL) {
3147
uu_avl_insert(avl, node, idx);
3148
} else {
3149
nvlist_free(props);
3150
free(node);
3151
node = n;
3152
props = node->usn_nvl;
3153
}
3154
3155
/* Calculate/update width of USED/QUOTA fields */
3156
if (cb->cb_nicenum) {
3157
if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED ||
3158
prop == ZFS_PROP_USERQUOTA || prop == ZFS_PROP_GROUPQUOTA ||
3159
prop == ZFS_PROP_PROJECTUSED ||
3160
prop == ZFS_PROP_PROJECTQUOTA) {
3161
zfs_nicebytes(space, sizebuf, sizeof (sizebuf));
3162
} else {
3163
zfs_nicenum(space, sizebuf, sizeof (sizebuf));
3164
}
3165
} else {
3166
(void) snprintf(sizebuf, sizeof (sizebuf), "%llu",
3167
(u_longlong_t)space);
3168
}
3169
sizelen = strlen(sizebuf);
3170
if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED ||
3171
prop == ZFS_PROP_PROJECTUSED) {
3172
propname = "used";
3173
if (!nvlist_exists(props, "quota"))
3174
(void) nvlist_add_uint64(props, "quota", default_quota);
3175
} else if (prop == ZFS_PROP_USERQUOTA || prop == ZFS_PROP_GROUPQUOTA ||
3176
prop == ZFS_PROP_PROJECTQUOTA) {
3177
propname = "quota";
3178
if (!nvlist_exists(props, "used"))
3179
(void) nvlist_add_uint64(props, "used", 0);
3180
} else if (prop == ZFS_PROP_USEROBJUSED ||
3181
prop == ZFS_PROP_GROUPOBJUSED || prop == ZFS_PROP_PROJECTOBJUSED) {
3182
propname = "objused";
3183
if (!nvlist_exists(props, "objquota")) {
3184
(void) nvlist_add_uint64(props, "objquota",
3185
default_quota);
3186
}
3187
} else if (prop == ZFS_PROP_USEROBJQUOTA ||
3188
prop == ZFS_PROP_GROUPOBJQUOTA ||
3189
prop == ZFS_PROP_PROJECTOBJQUOTA) {
3190
propname = "objquota";
3191
if (!nvlist_exists(props, "objused"))
3192
(void) nvlist_add_uint64(props, "objused", 0);
3193
} else {
3194
return (-1);
3195
}
3196
sizeidx = us_field_index(propname);
3197
if (sizeidx >= 0 && sizelen > cb->cb_width[sizeidx])
3198
cb->cb_width[sizeidx] = sizelen;
3199
3200
if (nvlist_add_uint64(props, propname, space) != 0)
3201
nomem();
3202
3203
return (0);
3204
}
3205
3206
static void
3207
print_us_node(boolean_t scripted, boolean_t parsable, int *fields, int types,
3208
size_t *width, us_node_t *node)
3209
{
3210
nvlist_t *nvl = node->usn_nvl;
3211
char valstr[MAXNAMELEN];
3212
boolean_t first = B_TRUE;
3213
int cfield = 0;
3214
int field;
3215
uint32_t ustype;
3216
3217
/* Check type */
3218
(void) nvlist_lookup_uint32(nvl, "type", &ustype);
3219
if (!(ustype & types))
3220
return;
3221
3222
while ((field = fields[cfield]) != USFIELD_LAST) {
3223
nvpair_t *nvp = NULL;
3224
data_type_t type;
3225
uint32_t val32 = -1;
3226
uint64_t val64 = -1;
3227
const char *strval = "-";
3228
3229
while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL)
3230
if (strcmp(nvpair_name(nvp),
3231
us_field_names[field]) == 0)
3232
break;
3233
3234
type = nvp == NULL ? DATA_TYPE_UNKNOWN : nvpair_type(nvp);
3235
switch (type) {
3236
case DATA_TYPE_UINT32:
3237
val32 = fnvpair_value_uint32(nvp);
3238
break;
3239
case DATA_TYPE_UINT64:
3240
val64 = fnvpair_value_uint64(nvp);
3241
break;
3242
case DATA_TYPE_STRING:
3243
strval = fnvpair_value_string(nvp);
3244
break;
3245
case DATA_TYPE_UNKNOWN:
3246
break;
3247
default:
3248
(void) fprintf(stderr, "invalid data type\n");
3249
}
3250
3251
switch (field) {
3252
case USFIELD_TYPE:
3253
if (type == DATA_TYPE_UINT32)
3254
strval = us_type2str(val32);
3255
break;
3256
case USFIELD_NAME:
3257
if (type == DATA_TYPE_UINT64) {
3258
(void) sprintf(valstr, "%llu",
3259
(u_longlong_t)val64);
3260
strval = valstr;
3261
}
3262
break;
3263
case USFIELD_USED:
3264
case USFIELD_QUOTA:
3265
if (type == DATA_TYPE_UINT64) {
3266
if (parsable) {
3267
(void) sprintf(valstr, "%llu",
3268
(u_longlong_t)val64);
3269
strval = valstr;
3270
} else if (field == USFIELD_QUOTA &&
3271
val64 == 0) {
3272
strval = "none";
3273
} else {
3274
zfs_nicebytes(val64, valstr,
3275
sizeof (valstr));
3276
strval = valstr;
3277
}
3278
}
3279
break;
3280
case USFIELD_OBJUSED:
3281
case USFIELD_OBJQUOTA:
3282
if (type == DATA_TYPE_UINT64) {
3283
if (parsable) {
3284
(void) sprintf(valstr, "%llu",
3285
(u_longlong_t)val64);
3286
strval = valstr;
3287
} else if (field == USFIELD_OBJQUOTA &&
3288
val64 == 0) {
3289
strval = "none";
3290
} else {
3291
zfs_nicenum(val64, valstr,
3292
sizeof (valstr));
3293
strval = valstr;
3294
}
3295
}
3296
break;
3297
}
3298
3299
if (!first) {
3300
if (scripted)
3301
(void) putchar('\t');
3302
else
3303
(void) fputs(" ", stdout);
3304
}
3305
if (scripted)
3306
(void) fputs(strval, stdout);
3307
else if (field == USFIELD_TYPE || field == USFIELD_NAME)
3308
(void) printf("%-*s", (int)width[field], strval);
3309
else
3310
(void) printf("%*s", (int)width[field], strval);
3311
3312
first = B_FALSE;
3313
cfield++;
3314
}
3315
3316
(void) putchar('\n');
3317
}
3318
3319
static void
3320
print_us(boolean_t scripted, boolean_t parsable, int *fields, int types,
3321
size_t *width, boolean_t rmnode, uu_avl_t *avl)
3322
{
3323
us_node_t *node;
3324
const char *col;
3325
int cfield = 0;
3326
int field;
3327
3328
if (!scripted) {
3329
boolean_t first = B_TRUE;
3330
3331
while ((field = fields[cfield]) != USFIELD_LAST) {
3332
col = gettext(us_field_hdr[field]);
3333
if (field == USFIELD_TYPE || field == USFIELD_NAME) {
3334
(void) printf(first ? "%-*s" : " %-*s",
3335
(int)width[field], col);
3336
} else {
3337
(void) printf(first ? "%*s" : " %*s",
3338
(int)width[field], col);
3339
}
3340
first = B_FALSE;
3341
cfield++;
3342
}
3343
(void) printf("\n");
3344
}
3345
3346
for (node = uu_avl_first(avl); node; node = uu_avl_next(avl, node)) {
3347
print_us_node(scripted, parsable, fields, types, width, node);
3348
if (rmnode)
3349
nvlist_free(node->usn_nvl);
3350
}
3351
}
3352
3353
static int
3354
zfs_do_userspace(int argc, char **argv)
3355
{
3356
zfs_handle_t *zhp;
3357
zfs_userquota_prop_t p;
3358
uu_avl_pool_t *avl_pool;
3359
uu_avl_t *avl_tree;
3360
uu_avl_walk_t *walk;
3361
char *delim;
3362
char deffields[] = "type,name,used,quota,objused,objquota";
3363
char *ofield = NULL;
3364
char *tfield = NULL;
3365
int cfield = 0;
3366
int fields[256];
3367
int i;
3368
boolean_t scripted = B_FALSE;
3369
boolean_t prtnum = B_FALSE;
3370
boolean_t parsable = B_FALSE;
3371
boolean_t sid2posix = B_FALSE;
3372
int ret = 0;
3373
int c;
3374
zfs_sort_column_t *sortcol = NULL;
3375
int types = USTYPE_PSX_USR | USTYPE_SMB_USR;
3376
us_cbdata_t cb;
3377
us_node_t *node;
3378
us_node_t *rmnode;
3379
uu_list_pool_t *listpool;
3380
uu_list_t *list;
3381
uu_avl_index_t idx = 0;
3382
uu_list_index_t idx2 = 0;
3383
3384
if (argc < 2)
3385
usage(B_FALSE);
3386
3387
if (strcmp(argv[0], "groupspace") == 0) {
3388
/* Toggle default group types */
3389
types = USTYPE_PSX_GRP | USTYPE_SMB_GRP;
3390
} else if (strcmp(argv[0], "projectspace") == 0) {
3391
types = USTYPE_PROJ;
3392
prtnum = B_TRUE;
3393
}
3394
3395
while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) {
3396
switch (c) {
3397
case 'n':
3398
if (types == USTYPE_PROJ) {
3399
(void) fprintf(stderr,
3400
gettext("invalid option 'n'\n"));
3401
usage(B_FALSE);
3402
}
3403
prtnum = B_TRUE;
3404
break;
3405
case 'H':
3406
scripted = B_TRUE;
3407
break;
3408
case 'p':
3409
parsable = B_TRUE;
3410
break;
3411
case 'o':
3412
ofield = optarg;
3413
break;
3414
case 's':
3415
case 'S':
3416
if (zfs_add_sort_column(&sortcol, optarg,
3417
c == 's' ? B_FALSE : B_TRUE) != 0) {
3418
(void) fprintf(stderr,
3419
gettext("invalid field '%s'\n"), optarg);
3420
usage(B_FALSE);
3421
}
3422
break;
3423
case 't':
3424
if (types == USTYPE_PROJ) {
3425
(void) fprintf(stderr,
3426
gettext("invalid option 't'\n"));
3427
usage(B_FALSE);
3428
}
3429
tfield = optarg;
3430
break;
3431
case 'i':
3432
if (types == USTYPE_PROJ) {
3433
(void) fprintf(stderr,
3434
gettext("invalid option 'i'\n"));
3435
usage(B_FALSE);
3436
}
3437
sid2posix = B_TRUE;
3438
break;
3439
case ':':
3440
(void) fprintf(stderr, gettext("missing argument for "
3441
"'%c' option\n"), optopt);
3442
usage(B_FALSE);
3443
break;
3444
case '?':
3445
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3446
optopt);
3447
usage(B_FALSE);
3448
}
3449
}
3450
3451
argc -= optind;
3452
argv += optind;
3453
3454
if (argc < 1) {
3455
(void) fprintf(stderr, gettext("missing dataset name\n"));
3456
usage(B_FALSE);
3457
}
3458
if (argc > 1) {
3459
(void) fprintf(stderr, gettext("too many arguments\n"));
3460
usage(B_FALSE);
3461
}
3462
3463
/* Use default output fields if not specified using -o */
3464
if (ofield == NULL)
3465
ofield = deffields;
3466
do {
3467
if ((delim = strchr(ofield, ',')) != NULL)
3468
*delim = '\0';
3469
if ((fields[cfield++] = us_field_index(ofield)) == -1) {
3470
(void) fprintf(stderr, gettext("invalid type '%s' "
3471
"for -o option\n"), ofield);
3472
return (-1);
3473
}
3474
if (delim != NULL)
3475
ofield = delim + 1;
3476
} while (delim != NULL);
3477
fields[cfield] = USFIELD_LAST;
3478
3479
/* Override output types (-t option) */
3480
if (tfield != NULL) {
3481
types = 0;
3482
3483
do {
3484
boolean_t found = B_FALSE;
3485
3486
if ((delim = strchr(tfield, ',')) != NULL)
3487
*delim = '\0';
3488
for (i = 0; i < sizeof (us_type_bits) / sizeof (int);
3489
i++) {
3490
if (strcmp(tfield, us_type_names[i]) == 0) {
3491
found = B_TRUE;
3492
types |= us_type_bits[i];
3493
break;
3494
}
3495
}
3496
if (!found) {
3497
(void) fprintf(stderr, gettext("invalid type "
3498
"'%s' for -t option\n"), tfield);
3499
return (-1);
3500
}
3501
if (delim != NULL)
3502
tfield = delim + 1;
3503
} while (delim != NULL);
3504
}
3505
3506
if ((zhp = zfs_path_to_zhandle(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM |
3507
ZFS_TYPE_SNAPSHOT)) == NULL)
3508
return (1);
3509
if (zfs_get_underlying_type(zhp) != ZFS_TYPE_FILESYSTEM) {
3510
(void) fprintf(stderr, gettext("operation is only applicable "
3511
"to filesystems and their snapshots\n"));
3512
zfs_close(zhp);
3513
return (1);
3514
}
3515
3516
if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t),
3517
offsetof(us_node_t, usn_avlnode), us_compare, UU_DEFAULT)) == NULL)
3518
nomem();
3519
if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
3520
nomem();
3521
3522
/* Always add default sorting columns */
3523
(void) zfs_add_sort_column(&sortcol, "type", B_FALSE);
3524
(void) zfs_add_sort_column(&sortcol, "name", B_FALSE);
3525
3526
cb.cb_sortcol = sortcol;
3527
cb.cb_numname = prtnum;
3528
cb.cb_nicenum = !parsable;
3529
cb.cb_avl_pool = avl_pool;
3530
cb.cb_avl = avl_tree;
3531
cb.cb_sid2posix = sid2posix;
3532
3533
for (i = 0; i < USFIELD_LAST; i++)
3534
cb.cb_width[i] = strlen(gettext(us_field_hdr[i]));
3535
3536
for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
3537
if ((zfs_prop_is_user(p) &&
3538
!(types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
3539
(zfs_prop_is_group(p) &&
3540
!(types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))) ||
3541
(zfs_prop_is_project(p) && types != USTYPE_PROJ))
3542
continue;
3543
3544
cb.cb_prop = p;
3545
if ((ret = zfs_userspace(zhp, p, userspace_cb, &cb)) != 0) {
3546
zfs_close(zhp);
3547
return (ret);
3548
}
3549
}
3550
zfs_close(zhp);
3551
3552
/* Sort the list */
3553
if ((node = uu_avl_first(avl_tree)) == NULL)
3554
return (0);
3555
3556
us_populated = B_TRUE;
3557
3558
listpool = uu_list_pool_create("tmplist", sizeof (us_node_t),
3559
offsetof(us_node_t, usn_listnode), NULL, UU_DEFAULT);
3560
list = uu_list_create(listpool, NULL, UU_DEFAULT);
3561
uu_list_node_init(node, &node->usn_listnode, listpool);
3562
3563
while (node != NULL) {
3564
rmnode = node;
3565
node = uu_avl_next(avl_tree, node);
3566
uu_avl_remove(avl_tree, rmnode);
3567
if (uu_list_find(list, rmnode, NULL, &idx2) == NULL)
3568
uu_list_insert(list, rmnode, idx2);
3569
}
3570
3571
for (node = uu_list_first(list); node != NULL;
3572
node = uu_list_next(list, node)) {
3573
us_sort_info_t sortinfo = { sortcol, cb.cb_numname };
3574
3575
if (uu_avl_find(avl_tree, node, &sortinfo, &idx) == NULL)
3576
uu_avl_insert(avl_tree, node, idx);
3577
}
3578
3579
uu_list_destroy(list);
3580
uu_list_pool_destroy(listpool);
3581
3582
/* Print and free node nvlist memory */
3583
print_us(scripted, parsable, fields, types, cb.cb_width, B_TRUE,
3584
cb.cb_avl);
3585
3586
zfs_free_sort_columns(sortcol);
3587
3588
/* Clean up the AVL tree */
3589
if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
3590
nomem();
3591
3592
while ((node = uu_avl_walk_next(walk)) != NULL) {
3593
uu_avl_remove(cb.cb_avl, node);
3594
free(node);
3595
}
3596
3597
uu_avl_walk_end(walk);
3598
uu_avl_destroy(avl_tree);
3599
uu_avl_pool_destroy(avl_pool);
3600
3601
return (ret);
3602
}
3603
3604
/*
3605
* list [-Hp][-r|-d max] [-o property[,...]] [-s property] ... [-S property]
3606
* [-t type[,...]] [filesystem|volume|snapshot] ...
3607
*
3608
* -H Scripted mode; elide headers and separate columns by tabs
3609
* -p Display values in parsable (literal) format.
3610
* -r Recurse over all children
3611
* -d Limit recursion by depth.
3612
* -o Control which fields to display.
3613
* -s Specify sort columns, descending order.
3614
* -S Specify sort columns, ascending order.
3615
* -t Control which object types to display.
3616
*
3617
* When given no arguments, list all filesystems in the system.
3618
* Otherwise, list the specified datasets, optionally recursing down them if
3619
* '-r' is specified.
3620
*/
3621
typedef struct list_cbdata {
3622
boolean_t cb_first;
3623
boolean_t cb_literal;
3624
boolean_t cb_scripted;
3625
zprop_list_t *cb_proplist;
3626
boolean_t cb_json;
3627
nvlist_t *cb_jsobj;
3628
boolean_t cb_json_as_int;
3629
} list_cbdata_t;
3630
3631
/*
3632
* Given a list of columns to display, output appropriate headers for each one.
3633
*/
3634
static void
3635
print_header(list_cbdata_t *cb)
3636
{
3637
zprop_list_t *pl = cb->cb_proplist;
3638
char headerbuf[ZFS_MAXPROPLEN];
3639
const char *header;
3640
int i;
3641
boolean_t first = B_TRUE;
3642
boolean_t right_justify;
3643
3644
color_start(ANSI_BOLD);
3645
3646
for (; pl != NULL; pl = pl->pl_next) {
3647
if (!first) {
3648
(void) printf(" ");
3649
} else {
3650
first = B_FALSE;
3651
}
3652
3653
right_justify = B_FALSE;
3654
if (pl->pl_prop != ZPROP_USERPROP) {
3655
header = zfs_prop_column_name(pl->pl_prop);
3656
right_justify = zfs_prop_align_right(pl->pl_prop);
3657
} else {
3658
for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
3659
headerbuf[i] = toupper(pl->pl_user_prop[i]);
3660
headerbuf[i] = '\0';
3661
header = headerbuf;
3662
}
3663
3664
if (pl->pl_next == NULL && !right_justify)
3665
(void) printf("%s", header);
3666
else if (right_justify)
3667
(void) printf("%*s", (int)pl->pl_width, header);
3668
else
3669
(void) printf("%-*s", (int)pl->pl_width, header);
3670
}
3671
3672
color_end();
3673
3674
(void) printf("\n");
3675
}
3676
3677
/*
3678
* Decides on the color that the avail value should be printed in.
3679
* > 80% used = yellow
3680
* > 90% used = red
3681
*/
3682
static const char *
3683
zfs_list_avail_color(zfs_handle_t *zhp)
3684
{
3685
uint64_t used = zfs_prop_get_int(zhp, ZFS_PROP_USED);
3686
uint64_t avail = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE);
3687
int percentage = (int)((double)avail / MAX(avail + used, 1) * 100);
3688
3689
if (percentage > 20)
3690
return (NULL);
3691
else if (percentage > 10)
3692
return (ANSI_YELLOW);
3693
else
3694
return (ANSI_RED);
3695
}
3696
3697
/*
3698
* Given a dataset and a list of fields, print out all the properties according
3699
* to the described layout, or return an nvlist containing all the fields, later
3700
* to be printed out as JSON object.
3701
*/
3702
static void
3703
collect_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
3704
{
3705
zprop_list_t *pl = cb->cb_proplist;
3706
boolean_t first = B_TRUE;
3707
char property[ZFS_MAXPROPLEN];
3708
nvlist_t *userprops = zfs_get_user_props(zhp);
3709
nvlist_t *propval;
3710
const char *propstr;
3711
boolean_t right_justify;
3712
nvlist_t *item, *d, *props;
3713
item = d = props = NULL;
3714
zprop_source_t sourcetype = ZPROP_SRC_NONE;
3715
char source[ZFS_MAX_DATASET_NAME_LEN];
3716
if (cb->cb_json) {
3717
d = fnvlist_lookup_nvlist(cb->cb_jsobj, "datasets");
3718
if (d == NULL) {
3719
fprintf(stderr, "datasets obj not found.\n");
3720
exit(1);
3721
}
3722
item = fnvlist_alloc();
3723
props = fnvlist_alloc();
3724
fill_dataset_info(item, zhp, cb->cb_json_as_int);
3725
}
3726
3727
for (; pl != NULL; pl = pl->pl_next) {
3728
if (!cb->cb_json && !first) {
3729
if (cb->cb_scripted)
3730
(void) putchar('\t');
3731
else
3732
(void) fputs(" ", stdout);
3733
} else {
3734
first = B_FALSE;
3735
}
3736
3737
if (pl->pl_prop == ZFS_PROP_NAME) {
3738
(void) strlcpy(property, zfs_get_name(zhp),
3739
sizeof (property));
3740
propstr = property;
3741
right_justify = zfs_prop_align_right(pl->pl_prop);
3742
} else if (pl->pl_prop != ZPROP_USERPROP) {
3743
if (zfs_prop_get(zhp, pl->pl_prop, property,
3744
sizeof (property), &sourcetype, source,
3745
sizeof (source), cb->cb_literal) != 0)
3746
propstr = "-";
3747
else
3748
propstr = property;
3749
right_justify = zfs_prop_align_right(pl->pl_prop);
3750
} else if (zfs_prop_userquota(pl->pl_user_prop)) {
3751
sourcetype = ZPROP_SRC_LOCAL;
3752
if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
3753
property, sizeof (property), cb->cb_literal) != 0) {
3754
sourcetype = ZPROP_SRC_NONE;
3755
propstr = "-";
3756
} else {
3757
propstr = property;
3758
}
3759
right_justify = B_TRUE;
3760
} else if (zfs_prop_written(pl->pl_user_prop)) {
3761
sourcetype = ZPROP_SRC_LOCAL;
3762
if (zfs_prop_get_written(zhp, pl->pl_user_prop,
3763
property, sizeof (property), cb->cb_literal) != 0) {
3764
sourcetype = ZPROP_SRC_NONE;
3765
propstr = "-";
3766
} else {
3767
propstr = property;
3768
}
3769
right_justify = B_TRUE;
3770
} else {
3771
if (nvlist_lookup_nvlist(userprops,
3772
pl->pl_user_prop, &propval) != 0) {
3773
propstr = "-";
3774
} else {
3775
propstr = fnvlist_lookup_string(propval,
3776
ZPROP_VALUE);
3777
strlcpy(source,
3778
fnvlist_lookup_string(propval,
3779
ZPROP_SOURCE), ZFS_MAX_DATASET_NAME_LEN);
3780
if (strcmp(source,
3781
zfs_get_name(zhp)) == 0) {
3782
sourcetype = ZPROP_SRC_LOCAL;
3783
} else if (strcmp(source,
3784
ZPROP_SOURCE_VAL_RECVD) == 0) {
3785
sourcetype = ZPROP_SRC_RECEIVED;
3786
} else {
3787
sourcetype = ZPROP_SRC_INHERITED;
3788
}
3789
}
3790
right_justify = B_FALSE;
3791
}
3792
3793
if (cb->cb_json) {
3794
if (pl->pl_prop == ZFS_PROP_NAME)
3795
continue;
3796
const char *prop_name;
3797
if (pl->pl_prop != ZPROP_USERPROP)
3798
prop_name = zfs_prop_to_name(pl->pl_prop);
3799
else
3800
prop_name = pl->pl_user_prop;
3801
if (zprop_nvlist_one_property(
3802
prop_name, propstr,
3803
sourcetype, source, NULL, props,
3804
cb->cb_json_as_int) != 0)
3805
nomem();
3806
} else {
3807
/*
3808
* zfs_list_avail_color() needs
3809
* ZFS_PROP_AVAILABLE + USED, so we need another
3810
* for() search for the USED part when no colors
3811
* wanted, we can skip the whole thing
3812
*/
3813
if (use_color() && pl->pl_prop == ZFS_PROP_AVAILABLE) {
3814
zprop_list_t *pl2 = cb->cb_proplist;
3815
for (; pl2 != NULL; pl2 = pl2->pl_next) {
3816
if (pl2->pl_prop == ZFS_PROP_USED) {
3817
color_start(
3818
zfs_list_avail_color(zhp));
3819
/*
3820
* found it, no need for more
3821
* loops
3822
*/
3823
break;
3824
}
3825
}
3826
}
3827
3828
/*
3829
* If this is being called in scripted mode, or if
3830
* this is the last column and it is left-justified,
3831
* don't include a width format specifier.
3832
*/
3833
if (cb->cb_scripted || (pl->pl_next == NULL &&
3834
!right_justify))
3835
(void) fputs(propstr, stdout);
3836
else if (right_justify) {
3837
(void) printf("%*s", (int)pl->pl_width,
3838
propstr);
3839
} else {
3840
(void) printf("%-*s", (int)pl->pl_width,
3841
propstr);
3842
}
3843
3844
if (pl->pl_prop == ZFS_PROP_AVAILABLE)
3845
color_end();
3846
}
3847
}
3848
if (cb->cb_json) {
3849
fnvlist_add_nvlist(item, "properties", props);
3850
fnvlist_add_nvlist(d, zfs_get_name(zhp), item);
3851
fnvlist_free(props);
3852
fnvlist_free(item);
3853
} else
3854
(void) putchar('\n');
3855
}
3856
3857
/*
3858
* Generic callback function to list a dataset or snapshot.
3859
*/
3860
static int
3861
list_callback(zfs_handle_t *zhp, void *data)
3862
{
3863
list_cbdata_t *cbp = data;
3864
3865
if (cbp->cb_first) {
3866
if (!cbp->cb_scripted && !cbp->cb_json)
3867
print_header(cbp);
3868
cbp->cb_first = B_FALSE;
3869
}
3870
3871
collect_dataset(zhp, cbp);
3872
3873
return (0);
3874
}
3875
3876
static int
3877
zfs_do_list(int argc, char **argv)
3878
{
3879
int c;
3880
char default_fields[] =
3881
"name,used,available,referenced,mountpoint";
3882
int types = ZFS_TYPE_DATASET;
3883
boolean_t types_specified = B_FALSE;
3884
char *fields = default_fields;
3885
list_cbdata_t cb = { 0 };
3886
int limit = 0;
3887
int ret = 0;
3888
zfs_sort_column_t *sortcol = NULL;
3889
int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
3890
nvlist_t *data = NULL;
3891
3892
struct option long_options[] = {
3893
{"json", no_argument, NULL, 'j'},
3894
{"json-int", no_argument, NULL, ZFS_OPTION_JSON_NUMS_AS_INT},
3895
{0, 0, 0, 0}
3896
};
3897
3898
/* check options */
3899
while ((c = getopt_long(argc, argv, "jHS:d:o:prs:t:", long_options,
3900
NULL)) != -1) {
3901
switch (c) {
3902
case 'o':
3903
fields = optarg;
3904
break;
3905
case 'p':
3906
cb.cb_literal = B_TRUE;
3907
flags |= ZFS_ITER_LITERAL_PROPS;
3908
break;
3909
case 'd':
3910
limit = parse_depth(optarg, &flags);
3911
break;
3912
case 'r':
3913
flags |= ZFS_ITER_RECURSE;
3914
break;
3915
case 'j':
3916
cb.cb_json = B_TRUE;
3917
cb.cb_jsobj = zfs_json_schema(0, 1);
3918
data = fnvlist_alloc();
3919
fnvlist_add_nvlist(cb.cb_jsobj, "datasets", data);
3920
fnvlist_free(data);
3921
break;
3922
case ZFS_OPTION_JSON_NUMS_AS_INT:
3923
cb.cb_json_as_int = B_TRUE;
3924
cb.cb_literal = B_TRUE;
3925
break;
3926
case 'H':
3927
cb.cb_scripted = B_TRUE;
3928
break;
3929
case 's':
3930
if (zfs_add_sort_column(&sortcol, optarg,
3931
B_FALSE) != 0) {
3932
(void) fprintf(stderr,
3933
gettext("invalid property '%s'\n"), optarg);
3934
usage(B_FALSE);
3935
}
3936
break;
3937
case 'S':
3938
if (zfs_add_sort_column(&sortcol, optarg,
3939
B_TRUE) != 0) {
3940
(void) fprintf(stderr,
3941
gettext("invalid property '%s'\n"), optarg);
3942
usage(B_FALSE);
3943
}
3944
break;
3945
case 't':
3946
types = 0;
3947
types_specified = B_TRUE;
3948
flags &= ~ZFS_ITER_PROP_LISTSNAPS;
3949
3950
for (char *tok; (tok = strsep(&optarg, ",")); ) {
3951
static const char *const type_subopts[] = {
3952
"filesystem",
3953
"fs",
3954
"volume",
3955
"vol",
3956
"snapshot",
3957
"snap",
3958
"bookmark",
3959
"all"
3960
};
3961
static const int type_types[] = {
3962
ZFS_TYPE_FILESYSTEM,
3963
ZFS_TYPE_FILESYSTEM,
3964
ZFS_TYPE_VOLUME,
3965
ZFS_TYPE_VOLUME,
3966
ZFS_TYPE_SNAPSHOT,
3967
ZFS_TYPE_SNAPSHOT,
3968
ZFS_TYPE_BOOKMARK,
3969
ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK
3970
};
3971
3972
for (c = 0; c < ARRAY_SIZE(type_subopts); ++c)
3973
if (strcmp(tok, type_subopts[c]) == 0) {
3974
types |= type_types[c];
3975
goto found3;
3976
}
3977
3978
(void) fprintf(stderr,
3979
gettext("invalid type '%s'\n"), tok);
3980
usage(B_FALSE);
3981
found3:;
3982
}
3983
break;
3984
case ':':
3985
(void) fprintf(stderr, gettext("missing argument for "
3986
"'%c' option\n"), optopt);
3987
usage(B_FALSE);
3988
break;
3989
case '?':
3990
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3991
optopt);
3992
usage(B_FALSE);
3993
}
3994
}
3995
3996
argc -= optind;
3997
argv += optind;
3998
3999
if (!cb.cb_json && cb.cb_json_as_int) {
4000
(void) fprintf(stderr, gettext("'--json-int' only works with"
4001
" '-j' option\n"));
4002
usage(B_FALSE);
4003
}
4004
4005
/*
4006
* If "-o space" and no types were specified, don't display snapshots.
4007
*/
4008
if (strcmp(fields, "space") == 0 && types_specified == B_FALSE)
4009
types &= ~ZFS_TYPE_SNAPSHOT;
4010
4011
/*
4012
* Handle users who want to list all snapshots or bookmarks
4013
* of the current dataset (ex. 'zfs list -t snapshot <dataset>').
4014
*/
4015
if ((types == ZFS_TYPE_SNAPSHOT || types == ZFS_TYPE_BOOKMARK) &&
4016
argc > 0 && (flags & ZFS_ITER_RECURSE) == 0 && limit == 0) {
4017
flags |= (ZFS_ITER_DEPTH_LIMIT | ZFS_ITER_RECURSE);
4018
limit = 1;
4019
}
4020
4021
/*
4022
* If the user specifies '-o all', the zprop_get_list() doesn't
4023
* normally include the name of the dataset. For 'zfs list', we always
4024
* want this property to be first.
4025
*/
4026
if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
4027
!= 0)
4028
usage(B_FALSE);
4029
4030
cb.cb_first = B_TRUE;
4031
4032
/*
4033
* If we are only going to list and sort by properties that are "fast"
4034
* then we can use "simple" mode and avoid populating the properties
4035
* nvlist.
4036
*/
4037
if (zfs_list_only_by_fast(cb.cb_proplist) &&
4038
zfs_sort_only_by_fast(sortcol))
4039
flags |= ZFS_ITER_SIMPLE;
4040
4041
ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
4042
limit, list_callback, &cb);
4043
4044
if (ret == 0 && cb.cb_json)
4045
zcmd_print_json(cb.cb_jsobj);
4046
else if (ret != 0 && cb.cb_json)
4047
nvlist_free(cb.cb_jsobj);
4048
4049
zprop_free_list(cb.cb_proplist);
4050
zfs_free_sort_columns(sortcol);
4051
4052
if (ret == 0 && cb.cb_first && !cb.cb_scripted)
4053
(void) fprintf(stderr, gettext("no datasets available\n"));
4054
4055
return (ret);
4056
}
4057
4058
/*
4059
* zfs rename [-fu] <fs | snap | vol> <fs | snap | vol>
4060
* zfs rename [-f] -p <fs | vol> <fs | vol>
4061
* zfs rename [-u] -r <snap> <snap>
4062
*
4063
* Renames the given dataset to another of the same type.
4064
*
4065
* The '-p' flag creates all the non-existing ancestors of the target first.
4066
* The '-u' flag prevents file systems from being remounted during rename.
4067
*/
4068
static int
4069
zfs_do_rename(int argc, char **argv)
4070
{
4071
zfs_handle_t *zhp;
4072
renameflags_t flags = { 0 };
4073
int c;
4074
int ret = 0;
4075
int types;
4076
boolean_t parents = B_FALSE;
4077
4078
/* check options */
4079
while ((c = getopt(argc, argv, "pruf")) != -1) {
4080
switch (c) {
4081
case 'p':
4082
parents = B_TRUE;
4083
break;
4084
case 'r':
4085
flags.recursive = B_TRUE;
4086
break;
4087
case 'u':
4088
flags.nounmount = B_TRUE;
4089
break;
4090
case 'f':
4091
flags.forceunmount = B_TRUE;
4092
break;
4093
case '?':
4094
default:
4095
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4096
optopt);
4097
usage(B_FALSE);
4098
}
4099
}
4100
4101
argc -= optind;
4102
argv += optind;
4103
4104
/* check number of arguments */
4105
if (argc < 1) {
4106
(void) fprintf(stderr, gettext("missing source dataset "
4107
"argument\n"));
4108
usage(B_FALSE);
4109
}
4110
if (argc < 2) {
4111
(void) fprintf(stderr, gettext("missing target dataset "
4112
"argument\n"));
4113
usage(B_FALSE);
4114
}
4115
if (argc > 2) {
4116
(void) fprintf(stderr, gettext("too many arguments\n"));
4117
usage(B_FALSE);
4118
}
4119
4120
if (flags.recursive && parents) {
4121
(void) fprintf(stderr, gettext("-p and -r options are mutually "
4122
"exclusive\n"));
4123
usage(B_FALSE);
4124
}
4125
4126
if (flags.nounmount && parents) {
4127
(void) fprintf(stderr, gettext("-u and -p options are mutually "
4128
"exclusive\n"));
4129
usage(B_FALSE);
4130
}
4131
4132
if (flags.recursive && strchr(argv[0], '@') == 0) {
4133
(void) fprintf(stderr, gettext("source dataset for recursive "
4134
"rename must be a snapshot\n"));
4135
usage(B_FALSE);
4136
}
4137
4138
if (flags.nounmount)
4139
types = ZFS_TYPE_FILESYSTEM;
4140
else if (parents)
4141
types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
4142
else
4143
types = ZFS_TYPE_DATASET;
4144
4145
if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL)
4146
return (1);
4147
4148
/* If we were asked and the name looks good, try to create ancestors. */
4149
if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp)) &&
4150
zfs_create_ancestors(g_zfs, argv[1]) != 0) {
4151
zfs_close(zhp);
4152
return (1);
4153
}
4154
4155
ret = (zfs_rename(zhp, argv[1], flags) != 0);
4156
4157
zfs_close(zhp);
4158
return (ret);
4159
}
4160
4161
/*
4162
* zfs promote <fs>
4163
*
4164
* Promotes the given clone fs to be the parent
4165
*/
4166
static int
4167
zfs_do_promote(int argc, char **argv)
4168
{
4169
zfs_handle_t *zhp;
4170
int ret = 0;
4171
4172
/* check options */
4173
if (argc > 1 && argv[1][0] == '-') {
4174
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4175
argv[1][1]);
4176
usage(B_FALSE);
4177
}
4178
4179
/* check number of arguments */
4180
if (argc < 2) {
4181
(void) fprintf(stderr, gettext("missing clone filesystem"
4182
" argument\n"));
4183
usage(B_FALSE);
4184
}
4185
if (argc > 2) {
4186
(void) fprintf(stderr, gettext("too many arguments\n"));
4187
usage(B_FALSE);
4188
}
4189
4190
zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
4191
if (zhp == NULL)
4192
return (1);
4193
4194
ret = (zfs_promote(zhp) != 0);
4195
4196
4197
zfs_close(zhp);
4198
return (ret);
4199
}
4200
4201
static int
4202
zfs_do_redact(int argc, char **argv)
4203
{
4204
char *snap = NULL;
4205
char *bookname = NULL;
4206
char **rsnaps = NULL;
4207
int numrsnaps = 0;
4208
argv++;
4209
argc--;
4210
if (argc < 3) {
4211
(void) fprintf(stderr, gettext("too few arguments\n"));
4212
usage(B_FALSE);
4213
}
4214
4215
snap = argv[0];
4216
bookname = argv[1];
4217
rsnaps = argv + 2;
4218
numrsnaps = argc - 2;
4219
4220
nvlist_t *rsnapnv = fnvlist_alloc();
4221
4222
for (int i = 0; i < numrsnaps; i++) {
4223
fnvlist_add_boolean(rsnapnv, rsnaps[i]);
4224
}
4225
4226
int err = lzc_redact(snap, bookname, rsnapnv);
4227
fnvlist_free(rsnapnv);
4228
4229
switch (err) {
4230
case 0:
4231
break;
4232
case ENOENT: {
4233
zfs_handle_t *zhp = zfs_open(g_zfs, snap, ZFS_TYPE_SNAPSHOT);
4234
if (zhp == NULL) {
4235
(void) fprintf(stderr, gettext("provided snapshot %s "
4236
"does not exist\n"), snap);
4237
} else {
4238
zfs_close(zhp);
4239
}
4240
for (int i = 0; i < numrsnaps; i++) {
4241
zhp = zfs_open(g_zfs, rsnaps[i], ZFS_TYPE_SNAPSHOT);
4242
if (zhp == NULL) {
4243
(void) fprintf(stderr, gettext("provided "
4244
"snapshot %s does not exist\n"), rsnaps[i]);
4245
} else {
4246
zfs_close(zhp);
4247
}
4248
}
4249
break;
4250
}
4251
case EEXIST:
4252
(void) fprintf(stderr, gettext("specified redaction bookmark "
4253
"(%s) provided already exists\n"), bookname);
4254
break;
4255
case ENAMETOOLONG:
4256
(void) fprintf(stderr, gettext("provided bookmark name cannot "
4257
"be used, final name would be too long\n"));
4258
break;
4259
case E2BIG:
4260
(void) fprintf(stderr, gettext("too many redaction snapshots "
4261
"specified\n"));
4262
break;
4263
case EINVAL:
4264
if (strchr(bookname, '#') != NULL)
4265
(void) fprintf(stderr, gettext(
4266
"redaction bookmark name must not contain '#'\n"));
4267
else
4268
(void) fprintf(stderr, gettext(
4269
"redaction snapshot must be descendent of "
4270
"snapshot being redacted\n"));
4271
break;
4272
case EALREADY:
4273
(void) fprintf(stderr, gettext("attempted to redact redacted "
4274
"dataset or with respect to redacted dataset\n"));
4275
break;
4276
case ENOTSUP:
4277
(void) fprintf(stderr, gettext("redaction bookmarks feature "
4278
"not enabled\n"));
4279
break;
4280
case EXDEV:
4281
(void) fprintf(stderr, gettext("potentially invalid redaction "
4282
"snapshot; full dataset names required\n"));
4283
break;
4284
case ESRCH:
4285
(void) fprintf(stderr, gettext("attempted to resume redaction "
4286
" with a mismatched redaction list\n"));
4287
break;
4288
default:
4289
(void) fprintf(stderr, gettext("internal error: %s\n"),
4290
strerror(errno));
4291
}
4292
4293
return (err);
4294
}
4295
4296
/*
4297
* zfs rollback [-rRf] <snapshot>
4298
*
4299
* -r Delete any intervening snapshots before doing rollback
4300
* -R Delete any snapshots and their clones
4301
* -f ignored for backwards compatibility
4302
*
4303
* Given a filesystem, rollback to a specific snapshot, discarding any changes
4304
* since then and making it the active dataset. If more recent snapshots exist,
4305
* the command will complain unless the '-r' flag is given.
4306
*/
4307
typedef struct rollback_cbdata {
4308
uint64_t cb_create;
4309
uint8_t cb_younger_ds_printed;
4310
boolean_t cb_first;
4311
int cb_doclones;
4312
char *cb_target;
4313
int cb_error;
4314
boolean_t cb_recurse;
4315
} rollback_cbdata_t;
4316
4317
static int
4318
rollback_check_dependent(zfs_handle_t *zhp, void *data)
4319
{
4320
rollback_cbdata_t *cbp = data;
4321
4322
if (cbp->cb_first && cbp->cb_recurse) {
4323
(void) fprintf(stderr, gettext("cannot rollback to "
4324
"'%s': clones of previous snapshots exist\n"),
4325
cbp->cb_target);
4326
(void) fprintf(stderr, gettext("use '-R' to "
4327
"force deletion of the following clones and "
4328
"dependents:\n"));
4329
cbp->cb_first = 0;
4330
cbp->cb_error = 1;
4331
}
4332
4333
(void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
4334
4335
zfs_close(zhp);
4336
return (0);
4337
}
4338
4339
4340
/*
4341
* Report some snapshots/bookmarks more recent than the one specified.
4342
* Used when '-r' is not specified. We reuse this same callback for the
4343
* snapshot dependents - if 'cb_dependent' is set, then this is a
4344
* dependent and we should report it without checking the transaction group.
4345
*/
4346
static int
4347
rollback_check(zfs_handle_t *zhp, void *data)
4348
{
4349
rollback_cbdata_t *cbp = data;
4350
/*
4351
* Max number of younger snapshots and/or bookmarks to display before
4352
* we stop the iteration.
4353
*/
4354
const uint8_t max_younger = 32;
4355
4356
if (cbp->cb_doclones) {
4357
zfs_close(zhp);
4358
return (0);
4359
}
4360
4361
if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
4362
if (cbp->cb_first && !cbp->cb_recurse) {
4363
(void) fprintf(stderr, gettext("cannot "
4364
"rollback to '%s': more recent snapshots "
4365
"or bookmarks exist\n"),
4366
cbp->cb_target);
4367
(void) fprintf(stderr, gettext("use '-r' to "
4368
"force deletion of the following "
4369
"snapshots and bookmarks:\n"));
4370
cbp->cb_first = 0;
4371
cbp->cb_error = 1;
4372
}
4373
4374
if (cbp->cb_recurse) {
4375
if (zfs_iter_dependents_v2(zhp, 0, B_TRUE,
4376
rollback_check_dependent, cbp) != 0) {
4377
zfs_close(zhp);
4378
return (-1);
4379
}
4380
} else {
4381
(void) fprintf(stderr, "%s\n",
4382
zfs_get_name(zhp));
4383
cbp->cb_younger_ds_printed++;
4384
}
4385
}
4386
zfs_close(zhp);
4387
4388
if (cbp->cb_younger_ds_printed == max_younger) {
4389
/*
4390
* This non-recursive rollback is going to fail due to the
4391
* presence of snapshots and/or bookmarks that are younger than
4392
* the rollback target.
4393
* We printed some of the offending objects, now we stop
4394
* zfs_iter_snapshot/bookmark iteration so we can fail fast and
4395
* avoid iterating over the rest of the younger objects
4396
*/
4397
(void) fprintf(stderr, gettext("Output limited to %d "
4398
"snapshots/bookmarks\n"), max_younger);
4399
return (-1);
4400
}
4401
return (0);
4402
}
4403
4404
static int
4405
zfs_do_rollback(int argc, char **argv)
4406
{
4407
int ret = 0;
4408
int c;
4409
boolean_t force = B_FALSE;
4410
rollback_cbdata_t cb = { 0 };
4411
zfs_handle_t *zhp, *snap;
4412
char parentname[ZFS_MAX_DATASET_NAME_LEN];
4413
char *delim;
4414
uint64_t min_txg = 0;
4415
4416
/* check options */
4417
while ((c = getopt(argc, argv, "rRf")) != -1) {
4418
switch (c) {
4419
case 'r':
4420
cb.cb_recurse = 1;
4421
break;
4422
case 'R':
4423
cb.cb_recurse = 1;
4424
cb.cb_doclones = 1;
4425
break;
4426
case 'f':
4427
force = B_TRUE;
4428
break;
4429
case '?':
4430
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4431
optopt);
4432
usage(B_FALSE);
4433
}
4434
}
4435
4436
argc -= optind;
4437
argv += optind;
4438
4439
/* check number of arguments */
4440
if (argc < 1) {
4441
(void) fprintf(stderr, gettext("missing dataset argument\n"));
4442
usage(B_FALSE);
4443
}
4444
if (argc > 1) {
4445
(void) fprintf(stderr, gettext("too many arguments\n"));
4446
usage(B_FALSE);
4447
}
4448
4449
/* open the snapshot */
4450
if ((snap = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
4451
return (1);
4452
4453
/* open the parent dataset */
4454
(void) strlcpy(parentname, argv[0], sizeof (parentname));
4455
verify((delim = strrchr(parentname, '@')) != NULL);
4456
*delim = '\0';
4457
if ((zhp = zfs_open(g_zfs, parentname, ZFS_TYPE_DATASET)) == NULL) {
4458
zfs_close(snap);
4459
return (1);
4460
}
4461
4462
/*
4463
* Check for more recent snapshots and/or clones based on the presence
4464
* of '-r' and '-R'.
4465
*/
4466
cb.cb_target = argv[0];
4467
cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
4468
cb.cb_first = B_TRUE;
4469
cb.cb_error = 0;
4470
4471
if (cb.cb_create > 0)
4472
min_txg = cb.cb_create;
4473
4474
if ((ret = zfs_iter_snapshots_sorted_v2(zhp, 0, rollback_check, &cb,
4475
min_txg, 0)) != 0)
4476
goto out;
4477
if ((ret = zfs_iter_bookmarks_v2(zhp, 0, rollback_check, &cb)) != 0)
4478
goto out;
4479
4480
if ((ret = cb.cb_error) != 0)
4481
goto out;
4482
4483
/*
4484
* Rollback parent to the given snapshot.
4485
*/
4486
ret = zfs_rollback(zhp, snap, force);
4487
4488
out:
4489
zfs_close(snap);
4490
zfs_close(zhp);
4491
4492
if (ret == 0)
4493
return (0);
4494
else
4495
return (1);
4496
}
4497
4498
/*
4499
* zfs set property=value ... { fs | snap | vol } ...
4500
*
4501
* Sets the given properties for all datasets specified on the command line.
4502
*/
4503
4504
static int
4505
set_callback(zfs_handle_t *zhp, void *data)
4506
{
4507
zprop_set_cbdata_t *cb = data;
4508
int ret = zfs_prop_set_list_flags(zhp, cb->cb_proplist, cb->cb_flags);
4509
4510
if (ret != 0 || libzfs_errno(g_zfs) != EZFS_SUCCESS) {
4511
switch (libzfs_errno(g_zfs)) {
4512
case EZFS_MOUNTFAILED:
4513
(void) fprintf(stderr, gettext("property may be set "
4514
"but unable to remount filesystem\n"));
4515
break;
4516
case EZFS_SHARENFSFAILED:
4517
(void) fprintf(stderr, gettext("property may be set "
4518
"but unable to reshare filesystem\n"));
4519
break;
4520
}
4521
}
4522
return (ret);
4523
}
4524
4525
static int
4526
zfs_do_set(int argc, char **argv)
4527
{
4528
zprop_set_cbdata_t cb = { 0 };
4529
int ds_start = -1; /* argv idx of first dataset arg */
4530
int ret = 0;
4531
int i, c;
4532
4533
/* check options */
4534
while ((c = getopt(argc, argv, "u")) != -1) {
4535
switch (c) {
4536
case 'u':
4537
cb.cb_flags |= ZFS_SET_NOMOUNT;
4538
break;
4539
case '?':
4540
default:
4541
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4542
optopt);
4543
usage(B_FALSE);
4544
}
4545
}
4546
4547
argc -= optind;
4548
argv += optind;
4549
4550
/* check number of arguments */
4551
if (argc < 1) {
4552
(void) fprintf(stderr, gettext("missing arguments\n"));
4553
usage(B_FALSE);
4554
}
4555
if (argc < 2) {
4556
if (strchr(argv[0], '=') == NULL) {
4557
(void) fprintf(stderr, gettext("missing property=value "
4558
"argument(s)\n"));
4559
} else {
4560
(void) fprintf(stderr, gettext("missing dataset "
4561
"name(s)\n"));
4562
}
4563
usage(B_FALSE);
4564
}
4565
4566
/* validate argument order: prop=val args followed by dataset args */
4567
for (i = 0; i < argc; i++) {
4568
if (strchr(argv[i], '=') != NULL) {
4569
if (ds_start > 0) {
4570
/* out-of-order prop=val argument */
4571
(void) fprintf(stderr, gettext("invalid "
4572
"argument order\n"));
4573
usage(B_FALSE);
4574
}
4575
} else if (ds_start < 0) {
4576
ds_start = i;
4577
}
4578
}
4579
if (ds_start < 0) {
4580
(void) fprintf(stderr, gettext("missing dataset name(s)\n"));
4581
usage(B_FALSE);
4582
}
4583
4584
/* Populate a list of property settings */
4585
if (nvlist_alloc(&cb.cb_proplist, NV_UNIQUE_NAME, 0) != 0)
4586
nomem();
4587
for (i = 0; i < ds_start; i++) {
4588
if (!parseprop(cb.cb_proplist, argv[i])) {
4589
ret = -1;
4590
goto error;
4591
}
4592
}
4593
4594
ret = zfs_for_each(argc - ds_start, argv + ds_start, 0,
4595
ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, &cb);
4596
4597
error:
4598
nvlist_free(cb.cb_proplist);
4599
return (ret);
4600
}
4601
4602
typedef struct snap_cbdata {
4603
nvlist_t *sd_nvl;
4604
boolean_t sd_recursive;
4605
const char *sd_snapname;
4606
} snap_cbdata_t;
4607
4608
static int
4609
zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
4610
{
4611
snap_cbdata_t *sd = arg;
4612
char *name;
4613
int rv = 0;
4614
int error;
4615
4616
if (sd->sd_recursive &&
4617
zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) != 0) {
4618
zfs_close(zhp);
4619
return (0);
4620
}
4621
4622
error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
4623
if (error == -1)
4624
nomem();
4625
fnvlist_add_boolean(sd->sd_nvl, name);
4626
free(name);
4627
4628
if (sd->sd_recursive)
4629
rv = zfs_iter_filesystems_v2(zhp, 0, zfs_snapshot_cb, sd);
4630
zfs_close(zhp);
4631
return (rv);
4632
}
4633
4634
/*
4635
* zfs snapshot [-r] [-o prop=value] ... <fs@snap>
4636
*
4637
* Creates a snapshot with the given name. While functionally equivalent to
4638
* 'zfs create', it is a separate command to differentiate intent.
4639
*/
4640
static int
4641
zfs_do_snapshot(int argc, char **argv)
4642
{
4643
int ret = 0;
4644
int c;
4645
nvlist_t *props;
4646
snap_cbdata_t sd = { 0 };
4647
boolean_t multiple_snaps = B_FALSE;
4648
4649
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
4650
nomem();
4651
if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
4652
nomem();
4653
4654
/* check options */
4655
while ((c = getopt(argc, argv, "ro:")) != -1) {
4656
switch (c) {
4657
case 'o':
4658
if (!parseprop(props, optarg)) {
4659
nvlist_free(sd.sd_nvl);
4660
nvlist_free(props);
4661
return (1);
4662
}
4663
break;
4664
case 'r':
4665
sd.sd_recursive = B_TRUE;
4666
multiple_snaps = B_TRUE;
4667
break;
4668
case '?':
4669
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4670
optopt);
4671
goto usage;
4672
}
4673
}
4674
4675
argc -= optind;
4676
argv += optind;
4677
4678
/* check number of arguments */
4679
if (argc < 1) {
4680
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
4681
goto usage;
4682
}
4683
4684
if (argc > 1)
4685
multiple_snaps = B_TRUE;
4686
for (; argc > 0; argc--, argv++) {
4687
char *atp;
4688
zfs_handle_t *zhp;
4689
4690
atp = strchr(argv[0], '@');
4691
if (atp == NULL)
4692
goto usage;
4693
*atp = '\0';
4694
sd.sd_snapname = atp + 1;
4695
zhp = zfs_open(g_zfs, argv[0],
4696
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
4697
if (zhp == NULL)
4698
goto usage;
4699
if (zfs_snapshot_cb(zhp, &sd) != 0)
4700
goto usage;
4701
}
4702
4703
ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
4704
nvlist_free(sd.sd_nvl);
4705
nvlist_free(props);
4706
if (ret != 0 && multiple_snaps)
4707
(void) fprintf(stderr, gettext("no snapshots were created\n"));
4708
return (ret != 0);
4709
4710
usage:
4711
nvlist_free(sd.sd_nvl);
4712
nvlist_free(props);
4713
usage(B_FALSE);
4714
return (-1);
4715
}
4716
4717
/*
4718
* Array of prefixes to exclude –
4719
* a linear search, even if executed for each dataset,
4720
* is plenty good enough.
4721
*/
4722
typedef struct zfs_send_exclude_arg {
4723
size_t count;
4724
const char **list;
4725
} zfs_send_exclude_arg_t;
4726
4727
static boolean_t
4728
zfs_do_send_exclude(zfs_handle_t *zhp, void *context)
4729
{
4730
zfs_send_exclude_arg_t *excludes = context;
4731
const char *name = zfs_get_name(zhp);
4732
4733
for (size_t i = 0; i < excludes->count; ++i) {
4734
size_t len = strlen(excludes->list[i]);
4735
if (strncmp(name, excludes->list[i], len) == 0 &&
4736
memchr("/@", name[len], sizeof ("/@")))
4737
return (B_FALSE);
4738
}
4739
4740
return (B_TRUE);
4741
}
4742
4743
/*
4744
* Send a backup stream to stdout.
4745
*/
4746
static int
4747
zfs_do_send(int argc, char **argv)
4748
{
4749
char *fromname = NULL;
4750
char *toname = NULL;
4751
char *resume_token = NULL;
4752
char *cp;
4753
zfs_handle_t *zhp;
4754
sendflags_t flags = { 0 };
4755
int c, err;
4756
nvlist_t *dbgnv = NULL;
4757
char *redactbook = NULL;
4758
zfs_send_exclude_arg_t excludes = { 0 };
4759
4760
struct option long_options[] = {
4761
{"replicate", no_argument, NULL, 'R'},
4762
{"skip-missing", no_argument, NULL, 's'},
4763
{"redact", required_argument, NULL, 'd'},
4764
{"props", no_argument, NULL, 'p'},
4765
{"parsable", no_argument, NULL, 'P'},
4766
{"dedup", no_argument, NULL, 'D'},
4767
{"proctitle", no_argument, NULL, 'V'},
4768
{"verbose", no_argument, NULL, 'v'},
4769
{"dryrun", no_argument, NULL, 'n'},
4770
{"large-block", no_argument, NULL, 'L'},
4771
{"embed", no_argument, NULL, 'e'},
4772
{"resume", required_argument, NULL, 't'},
4773
{"compressed", no_argument, NULL, 'c'},
4774
{"raw", no_argument, NULL, 'w'},
4775
{"backup", no_argument, NULL, 'b'},
4776
{"holds", no_argument, NULL, 'h'},
4777
{"saved", no_argument, NULL, 'S'},
4778
{"exclude", required_argument, NULL, 'X'},
4779
{0, 0, 0, 0}
4780
};
4781
4782
/* check options */
4783
while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:SX:",
4784
long_options, NULL)) != -1) {
4785
switch (c) {
4786
case 'X':
4787
for (char *ds; (ds = strsep(&optarg, ",")) != NULL; ) {
4788
if (!zfs_name_valid(ds, ZFS_TYPE_DATASET) ||
4789
strchr(ds, '/') == NULL) {
4790
(void) fprintf(stderr, gettext("-X %s: "
4791
"not a valid non-root dataset name"
4792
".\n"), ds);
4793
usage(B_FALSE);
4794
}
4795
excludes.list = safe_realloc(excludes.list,
4796
sizeof (char *) * (excludes.count + 1));
4797
excludes.list[excludes.count++] = ds;
4798
}
4799
break;
4800
case 'i':
4801
if (fromname)
4802
usage(B_FALSE);
4803
fromname = optarg;
4804
break;
4805
case 'I':
4806
if (fromname)
4807
usage(B_FALSE);
4808
fromname = optarg;
4809
flags.doall = B_TRUE;
4810
break;
4811
case 'R':
4812
flags.replicate = B_TRUE;
4813
break;
4814
case 's':
4815
flags.skipmissing = B_TRUE;
4816
break;
4817
case 'd':
4818
redactbook = optarg;
4819
break;
4820
case 'p':
4821
flags.props = B_TRUE;
4822
break;
4823
case 'b':
4824
flags.backup = B_TRUE;
4825
break;
4826
case 'h':
4827
flags.holds = B_TRUE;
4828
break;
4829
case 'P':
4830
flags.parsable = B_TRUE;
4831
break;
4832
case 'V':
4833
flags.progressastitle = B_TRUE;
4834
break;
4835
case 'v':
4836
flags.verbosity++;
4837
flags.progress = B_TRUE;
4838
break;
4839
case 'D':
4840
(void) fprintf(stderr,
4841
gettext("WARNING: deduplicated send is no "
4842
"longer supported. A regular,\n"
4843
"non-deduplicated stream will be generated.\n\n"));
4844
break;
4845
case 'n':
4846
flags.dryrun = B_TRUE;
4847
break;
4848
case 'L':
4849
flags.largeblock = B_TRUE;
4850
break;
4851
case 'e':
4852
flags.embed_data = B_TRUE;
4853
break;
4854
case 't':
4855
resume_token = optarg;
4856
break;
4857
case 'c':
4858
flags.compress = B_TRUE;
4859
break;
4860
case 'w':
4861
flags.raw = B_TRUE;
4862
flags.compress = B_TRUE;
4863
flags.embed_data = B_TRUE;
4864
flags.largeblock = B_TRUE;
4865
break;
4866
case 'S':
4867
flags.saved = B_TRUE;
4868
break;
4869
case ':':
4870
/*
4871
* If a parameter was not passed, optopt contains the
4872
* value that would normally lead us into the
4873
* appropriate case statement. If it's > 256, then this
4874
* must be a longopt and we should look at argv to get
4875
* the string. Otherwise it's just the character, so we
4876
* should use it directly.
4877
*/
4878
if (optopt <= UINT8_MAX) {
4879
(void) fprintf(stderr,
4880
gettext("missing argument for '%c' "
4881
"option\n"), optopt);
4882
} else {
4883
(void) fprintf(stderr,
4884
gettext("missing argument for '%s' "
4885
"option\n"), argv[optind - 1]);
4886
}
4887
free(excludes.list);
4888
usage(B_FALSE);
4889
break;
4890
case '?':
4891
default:
4892
/*
4893
* If an invalid flag was passed, optopt contains the
4894
* character if it was a short flag, or 0 if it was a
4895
* longopt.
4896
*/
4897
if (optopt != 0) {
4898
(void) fprintf(stderr,
4899
gettext("invalid option '%c'\n"), optopt);
4900
} else {
4901
(void) fprintf(stderr,
4902
gettext("invalid option '%s'\n"),
4903
argv[optind - 1]);
4904
4905
}
4906
free(excludes.list);
4907
usage(B_FALSE);
4908
}
4909
}
4910
4911
if ((flags.parsable || flags.progressastitle) && flags.verbosity == 0)
4912
flags.verbosity = 1;
4913
4914
if (excludes.count > 0 && !flags.replicate) {
4915
free(excludes.list);
4916
(void) fprintf(stderr, gettext("Cannot specify "
4917
"dataset exclusion (-X) on a non-recursive "
4918
"send.\n"));
4919
return (1);
4920
}
4921
4922
argc -= optind;
4923
argv += optind;
4924
4925
if (resume_token != NULL) {
4926
if (fromname != NULL || flags.replicate || flags.props ||
4927
flags.backup || flags.holds ||
4928
flags.saved || redactbook != NULL) {
4929
free(excludes.list);
4930
(void) fprintf(stderr,
4931
gettext("invalid flags combined with -t\n"));
4932
usage(B_FALSE);
4933
}
4934
if (argc > 0) {
4935
free(excludes.list);
4936
(void) fprintf(stderr, gettext("too many arguments\n"));
4937
usage(B_FALSE);
4938
}
4939
} else {
4940
if (argc < 1) {
4941
free(excludes.list);
4942
(void) fprintf(stderr,
4943
gettext("missing snapshot argument\n"));
4944
usage(B_FALSE);
4945
}
4946
if (argc > 1) {
4947
free(excludes.list);
4948
(void) fprintf(stderr, gettext("too many arguments\n"));
4949
usage(B_FALSE);
4950
}
4951
}
4952
4953
if (flags.saved) {
4954
if (fromname != NULL || flags.replicate || flags.props ||
4955
flags.doall || flags.backup ||
4956
flags.holds || flags.largeblock || flags.embed_data ||
4957
flags.compress || flags.raw || redactbook != NULL) {
4958
free(excludes.list);
4959
4960
(void) fprintf(stderr, gettext("incompatible flags "
4961
"combined with saved send flag\n"));
4962
usage(B_FALSE);
4963
}
4964
if (strchr(argv[0], '@') != NULL) {
4965
free(excludes.list);
4966
4967
(void) fprintf(stderr, gettext("saved send must "
4968
"specify the dataset with partially-received "
4969
"state\n"));
4970
usage(B_FALSE);
4971
}
4972
}
4973
4974
if (flags.raw && redactbook != NULL) {
4975
free(excludes.list);
4976
(void) fprintf(stderr,
4977
gettext("Error: raw sends may not be redacted.\n"));
4978
return (1);
4979
}
4980
4981
if (!flags.dryrun && isatty(STDOUT_FILENO)) {
4982
free(excludes.list);
4983
(void) fprintf(stderr,
4984
gettext("Error: Stream can not be written to a terminal.\n"
4985
"You must redirect standard output.\n"));
4986
return (1);
4987
}
4988
4989
if (flags.saved) {
4990
zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET);
4991
if (zhp == NULL) {
4992
free(excludes.list);
4993
return (1);
4994
}
4995
4996
err = zfs_send_saved(zhp, &flags, STDOUT_FILENO,
4997
resume_token);
4998
free(excludes.list);
4999
zfs_close(zhp);
5000
return (err != 0);
5001
} else if (resume_token != NULL) {
5002
free(excludes.list);
5003
return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
5004
resume_token));
5005
}
5006
5007
if (flags.skipmissing && !flags.replicate) {
5008
free(excludes.list);
5009
(void) fprintf(stderr,
5010
gettext("skip-missing flag can only be used in "
5011
"conjunction with replicate\n"));
5012
usage(B_FALSE);
5013
}
5014
5015
/*
5016
* For everything except -R and -I, use the new, cleaner code path.
5017
*/
5018
if (!(flags.replicate || flags.doall)) {
5019
char frombuf[ZFS_MAX_DATASET_NAME_LEN];
5020
5021
if (fromname != NULL && (strchr(fromname, '#') == NULL &&
5022
strchr(fromname, '@') == NULL)) {
5023
/*
5024
* Neither bookmark or snapshot was specified. Print a
5025
* warning, and assume snapshot.
5026
*/
5027
(void) fprintf(stderr, "Warning: incremental source "
5028
"didn't specify type, assuming snapshot. Use '@' "
5029
"or '#' prefix to avoid ambiguity.\n");
5030
(void) snprintf(frombuf, sizeof (frombuf), "@%s",
5031
fromname);
5032
fromname = frombuf;
5033
}
5034
if (fromname != NULL &&
5035
(fromname[0] == '#' || fromname[0] == '@')) {
5036
/*
5037
* Incremental source name begins with # or @.
5038
* Default to same fs as target.
5039
*/
5040
char tmpbuf[ZFS_MAX_DATASET_NAME_LEN];
5041
(void) strlcpy(tmpbuf, fromname, sizeof (tmpbuf));
5042
(void) strlcpy(frombuf, argv[0], sizeof (frombuf));
5043
cp = strchr(frombuf, '@');
5044
if (cp != NULL)
5045
*cp = '\0';
5046
(void) strlcat(frombuf, tmpbuf, sizeof (frombuf));
5047
fromname = frombuf;
5048
}
5049
5050
zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET);
5051
if (zhp == NULL) {
5052
free(excludes.list);
5053
return (1);
5054
}
5055
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags,
5056
redactbook);
5057
5058
free(excludes.list);
5059
zfs_close(zhp);
5060
return (err != 0);
5061
}
5062
5063
if (fromname != NULL && strchr(fromname, '#')) {
5064
(void) fprintf(stderr,
5065
gettext("Error: multiple snapshots cannot be "
5066
"sent from a bookmark.\n"));
5067
free(excludes.list);
5068
return (1);
5069
}
5070
5071
if (redactbook != NULL) {
5072
(void) fprintf(stderr, gettext("Error: multiple snapshots "
5073
"cannot be sent redacted.\n"));
5074
free(excludes.list);
5075
return (1);
5076
}
5077
5078
if ((cp = strchr(argv[0], '@')) == NULL) {
5079
(void) fprintf(stderr, gettext("Error: "
5080
"Unsupported flag with filesystem or bookmark.\n"));
5081
free(excludes.list);
5082
return (1);
5083
}
5084
*cp = '\0';
5085
toname = cp + 1;
5086
zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
5087
if (zhp == NULL) {
5088
free(excludes.list);
5089
return (1);
5090
}
5091
5092
/*
5093
* If they specified the full path to the snapshot, chop off
5094
* everything except the short name of the snapshot, but special
5095
* case if they specify the origin.
5096
*/
5097
if (fromname && (cp = strchr(fromname, '@')) != NULL) {
5098
char origin[ZFS_MAX_DATASET_NAME_LEN];
5099
zprop_source_t src;
5100
5101
(void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
5102
origin, sizeof (origin), &src, NULL, 0, B_FALSE);
5103
5104
if (strcmp(origin, fromname) == 0) {
5105
fromname = NULL;
5106
flags.fromorigin = B_TRUE;
5107
} else {
5108
*cp = '\0';
5109
if (cp != fromname && strcmp(argv[0], fromname)) {
5110
zfs_close(zhp);
5111
free(excludes.list);
5112
(void) fprintf(stderr,
5113
gettext("incremental source must be "
5114
"in same filesystem\n"));
5115
usage(B_FALSE);
5116
}
5117
fromname = cp + 1;
5118
if (strchr(fromname, '@') || strchr(fromname, '/')) {
5119
zfs_close(zhp);
5120
free(excludes.list);
5121
(void) fprintf(stderr,
5122
gettext("invalid incremental source\n"));
5123
usage(B_FALSE);
5124
}
5125
}
5126
}
5127
5128
if (flags.replicate && fromname == NULL)
5129
flags.doall = B_TRUE;
5130
5131
err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO,
5132
excludes.count > 0 ? zfs_do_send_exclude : NULL,
5133
&excludes, flags.verbosity >= 3 ? &dbgnv : NULL);
5134
5135
if (flags.verbosity >= 3 && dbgnv != NULL) {
5136
/*
5137
* dump_nvlist prints to stdout, but that's been
5138
* redirected to a file. Make it print to stderr
5139
* instead.
5140
*/
5141
(void) dup2(STDERR_FILENO, STDOUT_FILENO);
5142
dump_nvlist(dbgnv, 0);
5143
nvlist_free(dbgnv);
5144
}
5145
5146
zfs_close(zhp);
5147
free(excludes.list);
5148
return (err != 0);
5149
}
5150
5151
/*
5152
* Restore a backup stream from stdin.
5153
*/
5154
static int
5155
zfs_do_receive(int argc, char **argv)
5156
{
5157
int c, err = 0;
5158
recvflags_t flags = { 0 };
5159
boolean_t abort_resumable = B_FALSE;
5160
nvlist_t *props;
5161
5162
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
5163
nomem();
5164
5165
/* check options */
5166
while ((c = getopt(argc, argv, ":o:x:dehMnuvFsAc")) != -1) {
5167
switch (c) {
5168
case 'o':
5169
if (!parseprop(props, optarg)) {
5170
nvlist_free(props);
5171
usage(B_FALSE);
5172
}
5173
break;
5174
case 'x':
5175
if (!parsepropname(props, optarg)) {
5176
nvlist_free(props);
5177
usage(B_FALSE);
5178
}
5179
break;
5180
case 'd':
5181
if (flags.istail) {
5182
(void) fprintf(stderr, gettext("invalid option "
5183
"combination: -d and -e are mutually "
5184
"exclusive\n"));
5185
usage(B_FALSE);
5186
}
5187
flags.isprefix = B_TRUE;
5188
break;
5189
case 'e':
5190
if (flags.isprefix) {
5191
(void) fprintf(stderr, gettext("invalid option "
5192
"combination: -d and -e are mutually "
5193
"exclusive\n"));
5194
usage(B_FALSE);
5195
}
5196
flags.istail = B_TRUE;
5197
break;
5198
case 'h':
5199
flags.skipholds = B_TRUE;
5200
break;
5201
case 'M':
5202
flags.forceunmount = B_TRUE;
5203
break;
5204
case 'n':
5205
flags.dryrun = B_TRUE;
5206
break;
5207
case 'u':
5208
flags.nomount = B_TRUE;
5209
break;
5210
case 'v':
5211
flags.verbose = B_TRUE;
5212
break;
5213
case 's':
5214
flags.resumable = B_TRUE;
5215
break;
5216
case 'F':
5217
flags.force = B_TRUE;
5218
break;
5219
case 'A':
5220
abort_resumable = B_TRUE;
5221
break;
5222
case 'c':
5223
flags.heal = B_TRUE;
5224
break;
5225
case ':':
5226
(void) fprintf(stderr, gettext("missing argument for "
5227
"'%c' option\n"), optopt);
5228
usage(B_FALSE);
5229
break;
5230
case '?':
5231
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5232
optopt);
5233
usage(B_FALSE);
5234
}
5235
}
5236
5237
argc -= optind;
5238
argv += optind;
5239
5240
/* zfs recv -e (use "tail" name) implies -d (remove dataset "head") */
5241
if (flags.istail)
5242
flags.isprefix = B_TRUE;
5243
5244
/* check number of arguments */
5245
if (argc < 1) {
5246
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
5247
usage(B_FALSE);
5248
}
5249
if (argc > 1) {
5250
(void) fprintf(stderr, gettext("too many arguments\n"));
5251
usage(B_FALSE);
5252
}
5253
5254
if (abort_resumable) {
5255
if (flags.isprefix || flags.istail || flags.dryrun ||
5256
flags.resumable || flags.nomount) {
5257
(void) fprintf(stderr, gettext("invalid option\n"));
5258
usage(B_FALSE);
5259
}
5260
5261
char namebuf[ZFS_MAX_DATASET_NAME_LEN];
5262
(void) snprintf(namebuf, sizeof (namebuf),
5263
"%s/%%recv", argv[0]);
5264
5265
if (zfs_dataset_exists(g_zfs, namebuf,
5266
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) {
5267
zfs_handle_t *zhp = zfs_open(g_zfs,
5268
namebuf, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
5269
if (zhp == NULL) {
5270
nvlist_free(props);
5271
return (1);
5272
}
5273
err = zfs_destroy(zhp, B_FALSE);
5274
zfs_close(zhp);
5275
} else {
5276
zfs_handle_t *zhp = zfs_open(g_zfs,
5277
argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
5278
if (zhp == NULL)
5279
usage(B_FALSE);
5280
if (!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) ||
5281
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
5282
NULL, 0, NULL, NULL, 0, B_TRUE) == -1) {
5283
(void) fprintf(stderr,
5284
gettext("'%s' does not have any "
5285
"resumable receive state to abort\n"),
5286
argv[0]);
5287
nvlist_free(props);
5288
zfs_close(zhp);
5289
return (1);
5290
}
5291
err = zfs_destroy(zhp, B_FALSE);
5292
zfs_close(zhp);
5293
}
5294
nvlist_free(props);
5295
return (err != 0);
5296
}
5297
5298
if (isatty(STDIN_FILENO)) {
5299
(void) fprintf(stderr,
5300
gettext("Error: Backup stream can not be read "
5301
"from a terminal.\n"
5302
"You must redirect standard input.\n"));
5303
nvlist_free(props);
5304
return (1);
5305
}
5306
err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);
5307
nvlist_free(props);
5308
5309
return (err != 0);
5310
}
5311
5312
/*
5313
* allow/unallow stuff
5314
*/
5315
/* copied from zfs/sys/dsl_deleg.h */
5316
#define ZFS_DELEG_PERM_CREATE "create"
5317
#define ZFS_DELEG_PERM_DESTROY "destroy"
5318
#define ZFS_DELEG_PERM_SNAPSHOT "snapshot"
5319
#define ZFS_DELEG_PERM_ROLLBACK "rollback"
5320
#define ZFS_DELEG_PERM_CLONE "clone"
5321
#define ZFS_DELEG_PERM_PROMOTE "promote"
5322
#define ZFS_DELEG_PERM_RENAME "rename"
5323
#define ZFS_DELEG_PERM_MOUNT "mount"
5324
#define ZFS_DELEG_PERM_SHARE "share"
5325
#define ZFS_DELEG_PERM_SEND "send"
5326
#define ZFS_DELEG_PERM_SEND_RAW "send:raw"
5327
#define ZFS_DELEG_PERM_RECEIVE "receive"
5328
#define ZFS_DELEG_PERM_RECEIVE_APPEND "receive:append"
5329
#define ZFS_DELEG_PERM_ALLOW "allow"
5330
#define ZFS_DELEG_PERM_USERPROP "userprop"
5331
#define ZFS_DELEG_PERM_VSCAN "vscan" /* ??? */
5332
#define ZFS_DELEG_PERM_USERQUOTA "userquota"
5333
#define ZFS_DELEG_PERM_GROUPQUOTA "groupquota"
5334
#define ZFS_DELEG_PERM_USERUSED "userused"
5335
#define ZFS_DELEG_PERM_GROUPUSED "groupused"
5336
#define ZFS_DELEG_PERM_USEROBJQUOTA "userobjquota"
5337
#define ZFS_DELEG_PERM_GROUPOBJQUOTA "groupobjquota"
5338
#define ZFS_DELEG_PERM_USEROBJUSED "userobjused"
5339
#define ZFS_DELEG_PERM_GROUPOBJUSED "groupobjused"
5340
5341
#define ZFS_DELEG_PERM_HOLD "hold"
5342
#define ZFS_DELEG_PERM_RELEASE "release"
5343
#define ZFS_DELEG_PERM_DIFF "diff"
5344
#define ZFS_DELEG_PERM_BOOKMARK "bookmark"
5345
#define ZFS_DELEG_PERM_LOAD_KEY "load-key"
5346
#define ZFS_DELEG_PERM_CHANGE_KEY "change-key"
5347
5348
#define ZFS_DELEG_PERM_PROJECTUSED "projectused"
5349
#define ZFS_DELEG_PERM_PROJECTQUOTA "projectquota"
5350
#define ZFS_DELEG_PERM_PROJECTOBJUSED "projectobjused"
5351
#define ZFS_DELEG_PERM_PROJECTOBJQUOTA "projectobjquota"
5352
5353
#define ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE
5354
5355
static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = {
5356
{ ZFS_DELEG_PERM_ALLOW, ZFS_DELEG_NOTE_ALLOW },
5357
{ ZFS_DELEG_PERM_CLONE, ZFS_DELEG_NOTE_CLONE },
5358
{ ZFS_DELEG_PERM_CREATE, ZFS_DELEG_NOTE_CREATE },
5359
{ ZFS_DELEG_PERM_DESTROY, ZFS_DELEG_NOTE_DESTROY },
5360
{ ZFS_DELEG_PERM_DIFF, ZFS_DELEG_NOTE_DIFF},
5361
{ ZFS_DELEG_PERM_HOLD, ZFS_DELEG_NOTE_HOLD },
5362
{ ZFS_DELEG_PERM_MOUNT, ZFS_DELEG_NOTE_MOUNT },
5363
{ ZFS_DELEG_PERM_PROMOTE, ZFS_DELEG_NOTE_PROMOTE },
5364
{ ZFS_DELEG_PERM_RECEIVE, ZFS_DELEG_NOTE_RECEIVE },
5365
{ ZFS_DELEG_PERM_RELEASE, ZFS_DELEG_NOTE_RELEASE },
5366
{ ZFS_DELEG_PERM_RENAME, ZFS_DELEG_NOTE_RENAME },
5367
{ ZFS_DELEG_PERM_ROLLBACK, ZFS_DELEG_NOTE_ROLLBACK },
5368
{ ZFS_DELEG_PERM_SEND, ZFS_DELEG_NOTE_SEND },
5369
{ ZFS_DELEG_PERM_SEND_RAW, ZFS_DELEG_NOTE_SEND_RAW },
5370
{ ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
5371
{ ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
5372
{ ZFS_DELEG_PERM_BOOKMARK, ZFS_DELEG_NOTE_BOOKMARK },
5373
{ ZFS_DELEG_PERM_LOAD_KEY, ZFS_DELEG_NOTE_LOAD_KEY },
5374
{ ZFS_DELEG_PERM_CHANGE_KEY, ZFS_DELEG_NOTE_CHANGE_KEY },
5375
5376
{ ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA },
5377
{ ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED },
5378
{ ZFS_DELEG_PERM_USERPROP, ZFS_DELEG_NOTE_USERPROP },
5379
{ ZFS_DELEG_PERM_USERQUOTA, ZFS_DELEG_NOTE_USERQUOTA },
5380
{ ZFS_DELEG_PERM_USERUSED, ZFS_DELEG_NOTE_USERUSED },
5381
{ ZFS_DELEG_PERM_USEROBJQUOTA, ZFS_DELEG_NOTE_USEROBJQUOTA },
5382
{ ZFS_DELEG_PERM_USEROBJUSED, ZFS_DELEG_NOTE_USEROBJUSED },
5383
{ ZFS_DELEG_PERM_GROUPOBJQUOTA, ZFS_DELEG_NOTE_GROUPOBJQUOTA },
5384
{ ZFS_DELEG_PERM_GROUPOBJUSED, ZFS_DELEG_NOTE_GROUPOBJUSED },
5385
{ ZFS_DELEG_PERM_PROJECTUSED, ZFS_DELEG_NOTE_PROJECTUSED },
5386
{ ZFS_DELEG_PERM_PROJECTQUOTA, ZFS_DELEG_NOTE_PROJECTQUOTA },
5387
{ ZFS_DELEG_PERM_PROJECTOBJUSED, ZFS_DELEG_NOTE_PROJECTOBJUSED },
5388
{ ZFS_DELEG_PERM_PROJECTOBJQUOTA, ZFS_DELEG_NOTE_PROJECTOBJQUOTA },
5389
{ NULL, ZFS_DELEG_NOTE_NONE }
5390
};
5391
5392
/* permission structure */
5393
typedef struct deleg_perm {
5394
zfs_deleg_who_type_t dp_who_type;
5395
const char *dp_name;
5396
boolean_t dp_local;
5397
boolean_t dp_descend;
5398
} deleg_perm_t;
5399
5400
/* */
5401
typedef struct deleg_perm_node {
5402
deleg_perm_t dpn_perm;
5403
5404
uu_avl_node_t dpn_avl_node;
5405
} deleg_perm_node_t;
5406
5407
typedef struct fs_perm fs_perm_t;
5408
5409
/* permissions set */
5410
typedef struct who_perm {
5411
zfs_deleg_who_type_t who_type;
5412
const char *who_name; /* id */
5413
char who_ug_name[256]; /* user/group name */
5414
fs_perm_t *who_fsperm; /* uplink */
5415
5416
uu_avl_t *who_deleg_perm_avl; /* permissions */
5417
} who_perm_t;
5418
5419
/* */
5420
typedef struct who_perm_node {
5421
who_perm_t who_perm;
5422
uu_avl_node_t who_avl_node;
5423
} who_perm_node_t;
5424
5425
typedef struct fs_perm_set fs_perm_set_t;
5426
/* fs permissions */
5427
struct fs_perm {
5428
const char *fsp_name;
5429
5430
uu_avl_t *fsp_sc_avl; /* sets,create */
5431
uu_avl_t *fsp_uge_avl; /* user,group,everyone */
5432
5433
fs_perm_set_t *fsp_set; /* uplink */
5434
};
5435
5436
/* */
5437
typedef struct fs_perm_node {
5438
fs_perm_t fspn_fsperm;
5439
uu_avl_t *fspn_avl;
5440
5441
uu_list_node_t fspn_list_node;
5442
} fs_perm_node_t;
5443
5444
/* top level structure */
5445
struct fs_perm_set {
5446
uu_list_pool_t *fsps_list_pool;
5447
uu_list_t *fsps_list; /* list of fs_perms */
5448
5449
uu_avl_pool_t *fsps_named_set_avl_pool;
5450
uu_avl_pool_t *fsps_who_perm_avl_pool;
5451
uu_avl_pool_t *fsps_deleg_perm_avl_pool;
5452
};
5453
5454
static inline const char *
5455
deleg_perm_type(zfs_deleg_note_t note)
5456
{
5457
/* subcommands */
5458
switch (note) {
5459
/* SUBCOMMANDS */
5460
/* OTHER */
5461
case ZFS_DELEG_NOTE_GROUPQUOTA:
5462
case ZFS_DELEG_NOTE_GROUPUSED:
5463
case ZFS_DELEG_NOTE_USERPROP:
5464
case ZFS_DELEG_NOTE_USERQUOTA:
5465
case ZFS_DELEG_NOTE_USERUSED:
5466
case ZFS_DELEG_NOTE_USEROBJQUOTA:
5467
case ZFS_DELEG_NOTE_USEROBJUSED:
5468
case ZFS_DELEG_NOTE_GROUPOBJQUOTA:
5469
case ZFS_DELEG_NOTE_GROUPOBJUSED:
5470
case ZFS_DELEG_NOTE_PROJECTUSED:
5471
case ZFS_DELEG_NOTE_PROJECTQUOTA:
5472
case ZFS_DELEG_NOTE_PROJECTOBJUSED:
5473
case ZFS_DELEG_NOTE_PROJECTOBJQUOTA:
5474
/* other */
5475
return (gettext("other"));
5476
default:
5477
return (gettext("subcommand"));
5478
}
5479
}
5480
5481
static int
5482
who_type2weight(zfs_deleg_who_type_t who_type)
5483
{
5484
int res;
5485
switch (who_type) {
5486
case ZFS_DELEG_NAMED_SET_SETS:
5487
case ZFS_DELEG_NAMED_SET:
5488
res = 0;
5489
break;
5490
case ZFS_DELEG_CREATE_SETS:
5491
case ZFS_DELEG_CREATE:
5492
res = 1;
5493
break;
5494
case ZFS_DELEG_USER_SETS:
5495
case ZFS_DELEG_USER:
5496
res = 2;
5497
break;
5498
case ZFS_DELEG_GROUP_SETS:
5499
case ZFS_DELEG_GROUP:
5500
res = 3;
5501
break;
5502
case ZFS_DELEG_EVERYONE_SETS:
5503
case ZFS_DELEG_EVERYONE:
5504
res = 4;
5505
break;
5506
default:
5507
res = -1;
5508
}
5509
5510
return (res);
5511
}
5512
5513
static int
5514
who_perm_compare(const void *larg, const void *rarg, void *unused)
5515
{
5516
(void) unused;
5517
const who_perm_node_t *l = larg;
5518
const who_perm_node_t *r = rarg;
5519
zfs_deleg_who_type_t ltype = l->who_perm.who_type;
5520
zfs_deleg_who_type_t rtype = r->who_perm.who_type;
5521
int lweight = who_type2weight(ltype);
5522
int rweight = who_type2weight(rtype);
5523
int res = lweight - rweight;
5524
if (res == 0)
5525
res = strncmp(l->who_perm.who_name, r->who_perm.who_name,
5526
ZFS_MAX_DELEG_NAME-1);
5527
5528
if (res == 0)
5529
return (0);
5530
if (res > 0)
5531
return (1);
5532
else
5533
return (-1);
5534
}
5535
5536
static int
5537
deleg_perm_compare(const void *larg, const void *rarg, void *unused)
5538
{
5539
(void) unused;
5540
const deleg_perm_node_t *l = larg;
5541
const deleg_perm_node_t *r = rarg;
5542
int res = strncmp(l->dpn_perm.dp_name, r->dpn_perm.dp_name,
5543
ZFS_MAX_DELEG_NAME-1);
5544
5545
if (res == 0)
5546
return (0);
5547
5548
if (res > 0)
5549
return (1);
5550
else
5551
return (-1);
5552
}
5553
5554
static inline void
5555
fs_perm_set_init(fs_perm_set_t *fspset)
5556
{
5557
memset(fspset, 0, sizeof (fs_perm_set_t));
5558
5559
if ((fspset->fsps_list_pool = uu_list_pool_create("fsps_list_pool",
5560
sizeof (fs_perm_node_t), offsetof(fs_perm_node_t, fspn_list_node),
5561
NULL, UU_DEFAULT)) == NULL)
5562
nomem();
5563
if ((fspset->fsps_list = uu_list_create(fspset->fsps_list_pool, NULL,
5564
UU_DEFAULT)) == NULL)
5565
nomem();
5566
5567
if ((fspset->fsps_named_set_avl_pool = uu_avl_pool_create(
5568
"named_set_avl_pool", sizeof (who_perm_node_t), offsetof(
5569
who_perm_node_t, who_avl_node), who_perm_compare,
5570
UU_DEFAULT)) == NULL)
5571
nomem();
5572
5573
if ((fspset->fsps_who_perm_avl_pool = uu_avl_pool_create(
5574
"who_perm_avl_pool", sizeof (who_perm_node_t), offsetof(
5575
who_perm_node_t, who_avl_node), who_perm_compare,
5576
UU_DEFAULT)) == NULL)
5577
nomem();
5578
5579
if ((fspset->fsps_deleg_perm_avl_pool = uu_avl_pool_create(
5580
"deleg_perm_avl_pool", sizeof (deleg_perm_node_t), offsetof(
5581
deleg_perm_node_t, dpn_avl_node), deleg_perm_compare, UU_DEFAULT))
5582
== NULL)
5583
nomem();
5584
}
5585
5586
static inline void fs_perm_fini(fs_perm_t *);
5587
static inline void who_perm_fini(who_perm_t *);
5588
5589
static inline void
5590
fs_perm_set_fini(fs_perm_set_t *fspset)
5591
{
5592
fs_perm_node_t *node = uu_list_first(fspset->fsps_list);
5593
5594
while (node != NULL) {
5595
fs_perm_node_t *next_node =
5596
uu_list_next(fspset->fsps_list, node);
5597
fs_perm_t *fsperm = &node->fspn_fsperm;
5598
fs_perm_fini(fsperm);
5599
uu_list_remove(fspset->fsps_list, node);
5600
free(node);
5601
node = next_node;
5602
}
5603
5604
uu_avl_pool_destroy(fspset->fsps_named_set_avl_pool);
5605
uu_avl_pool_destroy(fspset->fsps_who_perm_avl_pool);
5606
uu_avl_pool_destroy(fspset->fsps_deleg_perm_avl_pool);
5607
}
5608
5609
static inline void
5610
deleg_perm_init(deleg_perm_t *deleg_perm, zfs_deleg_who_type_t type,
5611
const char *name)
5612
{
5613
deleg_perm->dp_who_type = type;
5614
deleg_perm->dp_name = name;
5615
}
5616
5617
static inline void
5618
who_perm_init(who_perm_t *who_perm, fs_perm_t *fsperm,
5619
zfs_deleg_who_type_t type, const char *name)
5620
{
5621
uu_avl_pool_t *pool;
5622
pool = fsperm->fsp_set->fsps_deleg_perm_avl_pool;
5623
5624
memset(who_perm, 0, sizeof (who_perm_t));
5625
5626
if ((who_perm->who_deleg_perm_avl = uu_avl_create(pool, NULL,
5627
UU_DEFAULT)) == NULL)
5628
nomem();
5629
5630
who_perm->who_type = type;
5631
who_perm->who_name = name;
5632
who_perm->who_fsperm = fsperm;
5633
}
5634
5635
static inline void
5636
who_perm_fini(who_perm_t *who_perm)
5637
{
5638
deleg_perm_node_t *node = uu_avl_first(who_perm->who_deleg_perm_avl);
5639
5640
while (node != NULL) {
5641
deleg_perm_node_t *next_node =
5642
uu_avl_next(who_perm->who_deleg_perm_avl, node);
5643
5644
uu_avl_remove(who_perm->who_deleg_perm_avl, node);
5645
free(node);
5646
node = next_node;
5647
}
5648
5649
uu_avl_destroy(who_perm->who_deleg_perm_avl);
5650
}
5651
5652
static inline void
5653
fs_perm_init(fs_perm_t *fsperm, fs_perm_set_t *fspset, const char *fsname)
5654
{
5655
uu_avl_pool_t *nset_pool = fspset->fsps_named_set_avl_pool;
5656
uu_avl_pool_t *who_pool = fspset->fsps_who_perm_avl_pool;
5657
5658
memset(fsperm, 0, sizeof (fs_perm_t));
5659
5660
if ((fsperm->fsp_sc_avl = uu_avl_create(nset_pool, NULL, UU_DEFAULT))
5661
== NULL)
5662
nomem();
5663
5664
if ((fsperm->fsp_uge_avl = uu_avl_create(who_pool, NULL, UU_DEFAULT))
5665
== NULL)
5666
nomem();
5667
5668
fsperm->fsp_set = fspset;
5669
fsperm->fsp_name = fsname;
5670
}
5671
5672
static inline void
5673
fs_perm_fini(fs_perm_t *fsperm)
5674
{
5675
who_perm_node_t *node = uu_avl_first(fsperm->fsp_sc_avl);
5676
while (node != NULL) {
5677
who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_sc_avl,
5678
node);
5679
who_perm_t *who_perm = &node->who_perm;
5680
who_perm_fini(who_perm);
5681
uu_avl_remove(fsperm->fsp_sc_avl, node);
5682
free(node);
5683
node = next_node;
5684
}
5685
5686
node = uu_avl_first(fsperm->fsp_uge_avl);
5687
while (node != NULL) {
5688
who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_uge_avl,
5689
node);
5690
who_perm_t *who_perm = &node->who_perm;
5691
who_perm_fini(who_perm);
5692
uu_avl_remove(fsperm->fsp_uge_avl, node);
5693
free(node);
5694
node = next_node;
5695
}
5696
5697
uu_avl_destroy(fsperm->fsp_sc_avl);
5698
uu_avl_destroy(fsperm->fsp_uge_avl);
5699
}
5700
5701
static void
5702
set_deleg_perm_node(uu_avl_t *avl, deleg_perm_node_t *node,
5703
zfs_deleg_who_type_t who_type, const char *name, char locality)
5704
{
5705
uu_avl_index_t idx = 0;
5706
5707
deleg_perm_node_t *found_node = NULL;
5708
deleg_perm_t *deleg_perm = &node->dpn_perm;
5709
5710
deleg_perm_init(deleg_perm, who_type, name);
5711
5712
if ((found_node = uu_avl_find(avl, node, NULL, &idx))
5713
== NULL)
5714
uu_avl_insert(avl, node, idx);
5715
else {
5716
node = found_node;
5717
deleg_perm = &node->dpn_perm;
5718
}
5719
5720
5721
switch (locality) {
5722
case ZFS_DELEG_LOCAL:
5723
deleg_perm->dp_local = B_TRUE;
5724
break;
5725
case ZFS_DELEG_DESCENDENT:
5726
deleg_perm->dp_descend = B_TRUE;
5727
break;
5728
case ZFS_DELEG_NA:
5729
break;
5730
default:
5731
assert(B_FALSE); /* invalid locality */
5732
}
5733
}
5734
5735
static inline int
5736
parse_who_perm(who_perm_t *who_perm, nvlist_t *nvl, char locality)
5737
{
5738
nvpair_t *nvp = NULL;
5739
fs_perm_set_t *fspset = who_perm->who_fsperm->fsp_set;
5740
uu_avl_t *avl = who_perm->who_deleg_perm_avl;
5741
zfs_deleg_who_type_t who_type = who_perm->who_type;
5742
5743
while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
5744
const char *name = nvpair_name(nvp);
5745
data_type_t type = nvpair_type(nvp);
5746
uu_avl_pool_t *avl_pool = fspset->fsps_deleg_perm_avl_pool;
5747
deleg_perm_node_t *node =
5748
safe_malloc(sizeof (deleg_perm_node_t));
5749
5750
VERIFY(type == DATA_TYPE_BOOLEAN);
5751
5752
uu_avl_node_init(node, &node->dpn_avl_node, avl_pool);
5753
set_deleg_perm_node(avl, node, who_type, name, locality);
5754
}
5755
5756
return (0);
5757
}
5758
5759
static inline int
5760
parse_fs_perm(fs_perm_t *fsperm, nvlist_t *nvl)
5761
{
5762
nvpair_t *nvp = NULL;
5763
fs_perm_set_t *fspset = fsperm->fsp_set;
5764
5765
while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
5766
nvlist_t *nvl2 = NULL;
5767
const char *name = nvpair_name(nvp);
5768
uu_avl_t *avl = NULL;
5769
uu_avl_pool_t *avl_pool = NULL;
5770
zfs_deleg_who_type_t perm_type = name[0];
5771
char perm_locality = name[1];
5772
const char *perm_name = name + 3;
5773
who_perm_t *who_perm = NULL;
5774
5775
assert('$' == name[2]);
5776
5777
if (nvpair_value_nvlist(nvp, &nvl2) != 0)
5778
return (-1);
5779
5780
switch (perm_type) {
5781
case ZFS_DELEG_CREATE:
5782
case ZFS_DELEG_CREATE_SETS:
5783
case ZFS_DELEG_NAMED_SET:
5784
case ZFS_DELEG_NAMED_SET_SETS:
5785
avl_pool = fspset->fsps_named_set_avl_pool;
5786
avl = fsperm->fsp_sc_avl;
5787
break;
5788
case ZFS_DELEG_USER:
5789
case ZFS_DELEG_USER_SETS:
5790
case ZFS_DELEG_GROUP:
5791
case ZFS_DELEG_GROUP_SETS:
5792
case ZFS_DELEG_EVERYONE:
5793
case ZFS_DELEG_EVERYONE_SETS:
5794
avl_pool = fspset->fsps_who_perm_avl_pool;
5795
avl = fsperm->fsp_uge_avl;
5796
break;
5797
5798
default:
5799
assert(!"unhandled zfs_deleg_who_type_t");
5800
}
5801
5802
who_perm_node_t *found_node = NULL;
5803
who_perm_node_t *node = safe_malloc(
5804
sizeof (who_perm_node_t));
5805
who_perm = &node->who_perm;
5806
uu_avl_index_t idx = 0;
5807
5808
uu_avl_node_init(node, &node->who_avl_node, avl_pool);
5809
who_perm_init(who_perm, fsperm, perm_type, perm_name);
5810
5811
if ((found_node = uu_avl_find(avl, node, NULL, &idx))
5812
== NULL) {
5813
if (avl == fsperm->fsp_uge_avl) {
5814
uid_t rid = 0;
5815
struct passwd *p = NULL;
5816
struct group *g = NULL;
5817
const char *nice_name = NULL;
5818
5819
switch (perm_type) {
5820
case ZFS_DELEG_USER_SETS:
5821
case ZFS_DELEG_USER:
5822
rid = atoi(perm_name);
5823
p = getpwuid(rid);
5824
if (p)
5825
nice_name = p->pw_name;
5826
break;
5827
case ZFS_DELEG_GROUP_SETS:
5828
case ZFS_DELEG_GROUP:
5829
rid = atoi(perm_name);
5830
g = getgrgid(rid);
5831
if (g)
5832
nice_name = g->gr_name;
5833
break;
5834
5835
default:
5836
break;
5837
}
5838
5839
if (nice_name != NULL) {
5840
(void) strlcpy(
5841
node->who_perm.who_ug_name,
5842
nice_name, 256);
5843
} else {
5844
/* User or group unknown */
5845
(void) snprintf(
5846
node->who_perm.who_ug_name,
5847
sizeof (node->who_perm.who_ug_name),
5848
"(unknown: %d)", rid);
5849
}
5850
}
5851
5852
uu_avl_insert(avl, node, idx);
5853
} else {
5854
node = found_node;
5855
who_perm = &node->who_perm;
5856
}
5857
5858
assert(who_perm != NULL);
5859
(void) parse_who_perm(who_perm, nvl2, perm_locality);
5860
}
5861
5862
return (0);
5863
}
5864
5865
static inline int
5866
parse_fs_perm_set(fs_perm_set_t *fspset, nvlist_t *nvl)
5867
{
5868
nvpair_t *nvp = NULL;
5869
uu_avl_index_t idx = 0;
5870
5871
while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
5872
nvlist_t *nvl2 = NULL;
5873
const char *fsname = nvpair_name(nvp);
5874
data_type_t type = nvpair_type(nvp);
5875
fs_perm_t *fsperm = NULL;
5876
fs_perm_node_t *node = safe_malloc(sizeof (fs_perm_node_t));
5877
5878
fsperm = &node->fspn_fsperm;
5879
5880
VERIFY(DATA_TYPE_NVLIST == type);
5881
5882
uu_list_node_init(node, &node->fspn_list_node,
5883
fspset->fsps_list_pool);
5884
5885
idx = uu_list_numnodes(fspset->fsps_list);
5886
fs_perm_init(fsperm, fspset, fsname);
5887
5888
if (nvpair_value_nvlist(nvp, &nvl2) != 0)
5889
return (-1);
5890
5891
(void) parse_fs_perm(fsperm, nvl2);
5892
5893
uu_list_insert(fspset->fsps_list, node, idx);
5894
}
5895
5896
return (0);
5897
}
5898
5899
static inline const char *
5900
deleg_perm_comment(zfs_deleg_note_t note)
5901
{
5902
const char *str;
5903
5904
/* subcommands */
5905
switch (note) {
5906
/* SUBCOMMANDS */
5907
case ZFS_DELEG_NOTE_ALLOW:
5908
str = gettext("Must also have the permission that is being"
5909
"\n\t\t\t\tallowed");
5910
break;
5911
case ZFS_DELEG_NOTE_CLONE:
5912
str = gettext("Must also have the 'create' ability and 'mount'"
5913
"\n\t\t\t\tability in the origin file system");
5914
break;
5915
case ZFS_DELEG_NOTE_CREATE:
5916
str = gettext("Must also have the 'mount' ability");
5917
break;
5918
case ZFS_DELEG_NOTE_DESTROY:
5919
str = gettext("Must also have the 'mount' ability");
5920
break;
5921
case ZFS_DELEG_NOTE_DIFF:
5922
str = gettext("Allows lookup of paths within a dataset;"
5923
"\n\t\t\t\tgiven an object number. Ordinary users need this"
5924
"\n\t\t\t\tin order to use zfs diff");
5925
break;
5926
case ZFS_DELEG_NOTE_HOLD:
5927
str = gettext("Allows adding a user hold to a snapshot");
5928
break;
5929
case ZFS_DELEG_NOTE_MOUNT:
5930
str = gettext("Allows mount/umount of ZFS datasets");
5931
break;
5932
case ZFS_DELEG_NOTE_PROMOTE:
5933
str = gettext("Must also have the 'mount'\n\t\t\t\tand"
5934
" 'promote' ability in the origin file system");
5935
break;
5936
case ZFS_DELEG_NOTE_RECEIVE:
5937
str = gettext("Must also have the 'mount' and 'create'"
5938
" ability");
5939
break;
5940
case ZFS_DELEG_NOTE_RELEASE:
5941
str = gettext("Allows releasing a user hold which\n\t\t\t\t"
5942
"might destroy the snapshot");
5943
break;
5944
case ZFS_DELEG_NOTE_RENAME:
5945
str = gettext("Must also have the 'mount' and 'create'"
5946
"\n\t\t\t\tability in the new parent");
5947
break;
5948
case ZFS_DELEG_NOTE_ROLLBACK:
5949
str = gettext("");
5950
break;
5951
case ZFS_DELEG_NOTE_SEND:
5952
str = gettext("");
5953
break;
5954
case ZFS_DELEG_NOTE_SEND_RAW:
5955
str = gettext("Allow sending ONLY encrypted (raw) replication"
5956
"\n\t\t\t\tstreams");
5957
break;
5958
case ZFS_DELEG_NOTE_SHARE:
5959
str = gettext("Allows sharing file systems over NFS or SMB"
5960
"\n\t\t\t\tprotocols");
5961
break;
5962
case ZFS_DELEG_NOTE_SNAPSHOT:
5963
str = gettext("");
5964
break;
5965
case ZFS_DELEG_NOTE_LOAD_KEY:
5966
str = gettext("Allows loading or unloading an encryption key");
5967
break;
5968
case ZFS_DELEG_NOTE_CHANGE_KEY:
5969
str = gettext("Allows changing or adding an encryption key");
5970
break;
5971
/*
5972
* case ZFS_DELEG_NOTE_VSCAN:
5973
* str = gettext("");
5974
* break;
5975
*/
5976
/* OTHER */
5977
case ZFS_DELEG_NOTE_GROUPQUOTA:
5978
str = gettext("Allows accessing any groupquota@... property");
5979
break;
5980
case ZFS_DELEG_NOTE_GROUPUSED:
5981
str = gettext("Allows reading any groupused@... property");
5982
break;
5983
case ZFS_DELEG_NOTE_USERPROP:
5984
str = gettext("Allows changing any user property");
5985
break;
5986
case ZFS_DELEG_NOTE_USERQUOTA:
5987
str = gettext("Allows accessing any userquota@... property");
5988
break;
5989
case ZFS_DELEG_NOTE_USERUSED:
5990
str = gettext("Allows reading any userused@... property");
5991
break;
5992
case ZFS_DELEG_NOTE_USEROBJQUOTA:
5993
str = gettext("Allows accessing any userobjquota@... property");
5994
break;
5995
case ZFS_DELEG_NOTE_GROUPOBJQUOTA:
5996
str = gettext("Allows accessing any \n\t\t\t\t"
5997
"groupobjquota@... property");
5998
break;
5999
case ZFS_DELEG_NOTE_GROUPOBJUSED:
6000
str = gettext("Allows reading any groupobjused@... property");
6001
break;
6002
case ZFS_DELEG_NOTE_USEROBJUSED:
6003
str = gettext("Allows reading any userobjused@... property");
6004
break;
6005
case ZFS_DELEG_NOTE_PROJECTQUOTA:
6006
str = gettext("Allows accessing any projectquota@... property");
6007
break;
6008
case ZFS_DELEG_NOTE_PROJECTOBJQUOTA:
6009
str = gettext("Allows accessing any \n\t\t\t\t"
6010
"projectobjquota@... property");
6011
break;
6012
case ZFS_DELEG_NOTE_PROJECTUSED:
6013
str = gettext("Allows reading any projectused@... property");
6014
break;
6015
case ZFS_DELEG_NOTE_PROJECTOBJUSED:
6016
str = gettext("Allows accessing any \n\t\t\t\t"
6017
"projectobjused@... property");
6018
break;
6019
/* other */
6020
default:
6021
str = "";
6022
}
6023
6024
return (str);
6025
}
6026
6027
struct allow_opts {
6028
boolean_t local;
6029
boolean_t descend;
6030
boolean_t user;
6031
boolean_t group;
6032
boolean_t everyone;
6033
boolean_t create;
6034
boolean_t set;
6035
boolean_t recursive; /* unallow only */
6036
boolean_t prt_usage;
6037
6038
boolean_t prt_perms;
6039
char *who;
6040
char *perms;
6041
const char *dataset;
6042
};
6043
6044
static inline int
6045
prop_cmp(const void *a, const void *b)
6046
{
6047
const char *str1 = *(const char **)a;
6048
const char *str2 = *(const char **)b;
6049
return (strcmp(str1, str2));
6050
}
6051
6052
static void
6053
allow_usage(boolean_t un, boolean_t requested, const char *msg)
6054
{
6055
const char *opt_desc[] = {
6056
"-h", gettext("show this help message and exit"),
6057
"-l", gettext("set permission locally"),
6058
"-d", gettext("set permission for descents"),
6059
"-u", gettext("set permission for user"),
6060
"-g", gettext("set permission for group"),
6061
"-e", gettext("set permission for everyone"),
6062
"-c", gettext("set create time permission"),
6063
"-s", gettext("define permission set"),
6064
/* unallow only */
6065
"-r", gettext("remove permissions recursively"),
6066
};
6067
size_t unallow_size = sizeof (opt_desc) / sizeof (char *);
6068
size_t allow_size = unallow_size - 2;
6069
const char *props[ZFS_NUM_PROPS];
6070
int i;
6071
size_t count = 0;
6072
FILE *fp = requested ? stdout : stderr;
6073
zprop_desc_t *pdtbl = zfs_prop_get_table();
6074
const char *fmt = gettext("%-16s %-14s\t%s\n");
6075
6076
(void) fprintf(fp, gettext("Usage: %s\n"), get_usage(un ? HELP_UNALLOW :
6077
HELP_ALLOW));
6078
(void) fprintf(fp, gettext("Options:\n"));
6079
for (i = 0; i < (un ? unallow_size : allow_size); i += 2) {
6080
const char *opt = opt_desc[i];
6081
const char *optdsc = opt_desc[i + 1];
6082
(void) fprintf(fp, gettext(" %-10s %s\n"), opt, optdsc);
6083
}
6084
6085
(void) fprintf(fp, gettext("\nThe following permissions are "
6086
"supported:\n\n"));
6087
(void) fprintf(fp, fmt, gettext("NAME"), gettext("TYPE"),
6088
gettext("NOTES"));
6089
for (i = 0; i < ZFS_NUM_DELEG_NOTES; i++) {
6090
const char *perm_name = zfs_deleg_perm_tbl[i].z_perm;
6091
zfs_deleg_note_t perm_note = zfs_deleg_perm_tbl[i].z_note;
6092
const char *perm_type = deleg_perm_type(perm_note);
6093
const char *perm_comment = deleg_perm_comment(perm_note);
6094
(void) fprintf(fp, fmt, perm_name, perm_type, perm_comment);
6095
}
6096
6097
for (i = 0; i < ZFS_NUM_PROPS; i++) {
6098
zprop_desc_t *pd = &pdtbl[i];
6099
if (pd->pd_visible != B_TRUE)
6100
continue;
6101
6102
if (pd->pd_attr == PROP_READONLY)
6103
continue;
6104
6105
props[count++] = pd->pd_name;
6106
}
6107
props[count] = NULL;
6108
6109
qsort(props, count, sizeof (char *), prop_cmp);
6110
6111
for (i = 0; i < count; i++)
6112
(void) fprintf(fp, fmt, props[i], gettext("property"), "");
6113
6114
if (msg != NULL)
6115
(void) fprintf(fp, gettext("\nzfs: error: %s"), msg);
6116
6117
exit(requested ? 0 : 2);
6118
}
6119
6120
static inline const char *
6121
munge_args(int argc, char **argv, boolean_t un, size_t expected_argc,
6122
char **permsp)
6123
{
6124
if (un && argc == expected_argc - 1)
6125
*permsp = NULL;
6126
else if (argc == expected_argc)
6127
*permsp = argv[argc - 2];
6128
else
6129
allow_usage(un, B_FALSE,
6130
gettext("wrong number of parameters\n"));
6131
6132
return (argv[argc - 1]);
6133
}
6134
6135
static void
6136
parse_allow_args(int argc, char **argv, boolean_t un, struct allow_opts *opts)
6137
{
6138
int uge_sum = opts->user + opts->group + opts->everyone;
6139
int csuge_sum = opts->create + opts->set + uge_sum;
6140
int ldcsuge_sum = csuge_sum + opts->local + opts->descend;
6141
int all_sum = un ? ldcsuge_sum + opts->recursive : ldcsuge_sum;
6142
6143
if (uge_sum > 1)
6144
allow_usage(un, B_FALSE,
6145
gettext("-u, -g, and -e are mutually exclusive\n"));
6146
6147
if (opts->prt_usage) {
6148
if (argc == 0 && all_sum == 0)
6149
allow_usage(un, B_TRUE, NULL);
6150
else
6151
usage(B_FALSE);
6152
}
6153
6154
if (opts->set) {
6155
if (csuge_sum > 1)
6156
allow_usage(un, B_FALSE,
6157
gettext("invalid options combined with -s\n"));
6158
6159
opts->dataset = munge_args(argc, argv, un, 3, &opts->perms);
6160
if (argv[0][0] != '@')
6161
allow_usage(un, B_FALSE,
6162
gettext("invalid set name: missing '@' prefix\n"));
6163
opts->who = argv[0];
6164
} else if (opts->create) {
6165
if (ldcsuge_sum > 1)
6166
allow_usage(un, B_FALSE,
6167
gettext("invalid options combined with -c\n"));
6168
opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
6169
} else if (opts->everyone) {
6170
if (csuge_sum > 1)
6171
allow_usage(un, B_FALSE,
6172
gettext("invalid options combined with -e\n"));
6173
opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
6174
} else if (uge_sum == 0 && argc > 0 && strcmp(argv[0], "everyone")
6175
== 0) {
6176
opts->everyone = B_TRUE;
6177
argc--;
6178
argv++;
6179
opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
6180
} else if (argc == 1 && !un) {
6181
opts->prt_perms = B_TRUE;
6182
opts->dataset = argv[argc-1];
6183
} else {
6184
opts->dataset = munge_args(argc, argv, un, 3, &opts->perms);
6185
opts->who = argv[0];
6186
}
6187
6188
if (!opts->local && !opts->descend) {
6189
opts->local = B_TRUE;
6190
opts->descend = B_TRUE;
6191
}
6192
}
6193
6194
static void
6195
store_allow_perm(zfs_deleg_who_type_t type, boolean_t local, boolean_t descend,
6196
const char *who, char *perms, nvlist_t *top_nvl)
6197
{
6198
int i;
6199
char ld[2] = { '\0', '\0' };
6200
char who_buf[MAXNAMELEN + 32];
6201
char base_type = '\0';
6202
char set_type = '\0';
6203
nvlist_t *base_nvl = NULL;
6204
nvlist_t *set_nvl = NULL;
6205
nvlist_t *nvl;
6206
6207
if (nvlist_alloc(&base_nvl, NV_UNIQUE_NAME, 0) != 0)
6208
nomem();
6209
if (nvlist_alloc(&set_nvl, NV_UNIQUE_NAME, 0) != 0)
6210
nomem();
6211
6212
switch (type) {
6213
case ZFS_DELEG_NAMED_SET_SETS:
6214
case ZFS_DELEG_NAMED_SET:
6215
set_type = ZFS_DELEG_NAMED_SET_SETS;
6216
base_type = ZFS_DELEG_NAMED_SET;
6217
ld[0] = ZFS_DELEG_NA;
6218
break;
6219
case ZFS_DELEG_CREATE_SETS:
6220
case ZFS_DELEG_CREATE:
6221
set_type = ZFS_DELEG_CREATE_SETS;
6222
base_type = ZFS_DELEG_CREATE;
6223
ld[0] = ZFS_DELEG_NA;
6224
break;
6225
case ZFS_DELEG_USER_SETS:
6226
case ZFS_DELEG_USER:
6227
set_type = ZFS_DELEG_USER_SETS;
6228
base_type = ZFS_DELEG_USER;
6229
if (local)
6230
ld[0] = ZFS_DELEG_LOCAL;
6231
if (descend)
6232
ld[1] = ZFS_DELEG_DESCENDENT;
6233
break;
6234
case ZFS_DELEG_GROUP_SETS:
6235
case ZFS_DELEG_GROUP:
6236
set_type = ZFS_DELEG_GROUP_SETS;
6237
base_type = ZFS_DELEG_GROUP;
6238
if (local)
6239
ld[0] = ZFS_DELEG_LOCAL;
6240
if (descend)
6241
ld[1] = ZFS_DELEG_DESCENDENT;
6242
break;
6243
case ZFS_DELEG_EVERYONE_SETS:
6244
case ZFS_DELEG_EVERYONE:
6245
set_type = ZFS_DELEG_EVERYONE_SETS;
6246
base_type = ZFS_DELEG_EVERYONE;
6247
if (local)
6248
ld[0] = ZFS_DELEG_LOCAL;
6249
if (descend)
6250
ld[1] = ZFS_DELEG_DESCENDENT;
6251
break;
6252
6253
default:
6254
assert(set_type != '\0' && base_type != '\0');
6255
}
6256
6257
if (perms != NULL) {
6258
char *curr = perms;
6259
char *end = curr + strlen(perms);
6260
6261
while (curr < end) {
6262
char *delim = strchr(curr, ',');
6263
if (delim == NULL)
6264
delim = end;
6265
else
6266
*delim = '\0';
6267
6268
if (curr[0] == '@')
6269
nvl = set_nvl;
6270
else
6271
nvl = base_nvl;
6272
6273
(void) nvlist_add_boolean(nvl, curr);
6274
if (delim != end)
6275
*delim = ',';
6276
curr = delim + 1;
6277
}
6278
6279
for (i = 0; i < 2; i++) {
6280
char locality = ld[i];
6281
if (locality == 0)
6282
continue;
6283
6284
if (!nvlist_empty(base_nvl)) {
6285
if (who != NULL)
6286
(void) snprintf(who_buf,
6287
sizeof (who_buf), "%c%c$%s",
6288
base_type, locality, who);
6289
else
6290
(void) snprintf(who_buf,
6291
sizeof (who_buf), "%c%c$",
6292
base_type, locality);
6293
6294
(void) nvlist_add_nvlist(top_nvl, who_buf,
6295
base_nvl);
6296
}
6297
6298
6299
if (!nvlist_empty(set_nvl)) {
6300
if (who != NULL)
6301
(void) snprintf(who_buf,
6302
sizeof (who_buf), "%c%c$%s",
6303
set_type, locality, who);
6304
else
6305
(void) snprintf(who_buf,
6306
sizeof (who_buf), "%c%c$",
6307
set_type, locality);
6308
6309
(void) nvlist_add_nvlist(top_nvl, who_buf,
6310
set_nvl);
6311
}
6312
}
6313
} else {
6314
for (i = 0; i < 2; i++) {
6315
char locality = ld[i];
6316
if (locality == 0)
6317
continue;
6318
6319
if (who != NULL)
6320
(void) snprintf(who_buf, sizeof (who_buf),
6321
"%c%c$%s", base_type, locality, who);
6322
else
6323
(void) snprintf(who_buf, sizeof (who_buf),
6324
"%c%c$", base_type, locality);
6325
(void) nvlist_add_boolean(top_nvl, who_buf);
6326
6327
if (who != NULL)
6328
(void) snprintf(who_buf, sizeof (who_buf),
6329
"%c%c$%s", set_type, locality, who);
6330
else
6331
(void) snprintf(who_buf, sizeof (who_buf),
6332
"%c%c$", set_type, locality);
6333
(void) nvlist_add_boolean(top_nvl, who_buf);
6334
}
6335
}
6336
}
6337
6338
static int
6339
construct_fsacl_list(boolean_t un, struct allow_opts *opts, nvlist_t **nvlp)
6340
{
6341
if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0)
6342
nomem();
6343
6344
if (opts->set) {
6345
store_allow_perm(ZFS_DELEG_NAMED_SET, opts->local,
6346
opts->descend, opts->who, opts->perms, *nvlp);
6347
} else if (opts->create) {
6348
store_allow_perm(ZFS_DELEG_CREATE, opts->local,
6349
opts->descend, NULL, opts->perms, *nvlp);
6350
} else if (opts->everyone) {
6351
store_allow_perm(ZFS_DELEG_EVERYONE, opts->local,
6352
opts->descend, NULL, opts->perms, *nvlp);
6353
} else {
6354
char *curr = opts->who;
6355
char *end = curr + strlen(curr);
6356
6357
while (curr < end) {
6358
const char *who;
6359
zfs_deleg_who_type_t who_type = ZFS_DELEG_WHO_UNKNOWN;
6360
char *endch;
6361
char *delim = strchr(curr, ',');
6362
char errbuf[256];
6363
char id[64];
6364
struct passwd *p = NULL;
6365
struct group *g = NULL;
6366
6367
uid_t rid;
6368
if (delim == NULL)
6369
delim = end;
6370
else
6371
*delim = '\0';
6372
6373
rid = (uid_t)strtol(curr, &endch, 0);
6374
if (opts->user) {
6375
who_type = ZFS_DELEG_USER;
6376
if (*endch != '\0')
6377
p = getpwnam(curr);
6378
else
6379
p = getpwuid(rid);
6380
6381
if (p != NULL)
6382
rid = p->pw_uid;
6383
else if (*endch != '\0') {
6384
(void) snprintf(errbuf, sizeof (errbuf),
6385
gettext("invalid user %s\n"), curr);
6386
allow_usage(un, B_TRUE, errbuf);
6387
}
6388
} else if (opts->group) {
6389
who_type = ZFS_DELEG_GROUP;
6390
if (*endch != '\0')
6391
g = getgrnam(curr);
6392
else
6393
g = getgrgid(rid);
6394
6395
if (g != NULL)
6396
rid = g->gr_gid;
6397
else if (*endch != '\0') {
6398
(void) snprintf(errbuf, sizeof (errbuf),
6399
gettext("invalid group %s\n"),
6400
curr);
6401
allow_usage(un, B_TRUE, errbuf);
6402
}
6403
} else {
6404
if (*endch != '\0') {
6405
p = getpwnam(curr);
6406
} else {
6407
p = getpwuid(rid);
6408
}
6409
6410
if (p == NULL) {
6411
if (*endch != '\0') {
6412
g = getgrnam(curr);
6413
} else {
6414
g = getgrgid(rid);
6415
}
6416
}
6417
6418
if (p != NULL) {
6419
who_type = ZFS_DELEG_USER;
6420
rid = p->pw_uid;
6421
} else if (g != NULL) {
6422
who_type = ZFS_DELEG_GROUP;
6423
rid = g->gr_gid;
6424
} else {
6425
(void) snprintf(errbuf, sizeof (errbuf),
6426
gettext("invalid user/group %s\n"),
6427
curr);
6428
allow_usage(un, B_TRUE, errbuf);
6429
}
6430
}
6431
6432
(void) sprintf(id, "%u", rid);
6433
who = id;
6434
6435
store_allow_perm(who_type, opts->local,
6436
opts->descend, who, opts->perms, *nvlp);
6437
curr = delim + 1;
6438
}
6439
}
6440
6441
return (0);
6442
}
6443
6444
static void
6445
print_set_creat_perms(uu_avl_t *who_avl)
6446
{
6447
const char *sc_title[] = {
6448
gettext("Permission sets:\n"),
6449
gettext("Create time permissions:\n"),
6450
NULL
6451
};
6452
who_perm_node_t *who_node = NULL;
6453
int prev_weight = -1;
6454
6455
for (who_node = uu_avl_first(who_avl); who_node != NULL;
6456
who_node = uu_avl_next(who_avl, who_node)) {
6457
uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl;
6458
zfs_deleg_who_type_t who_type = who_node->who_perm.who_type;
6459
const char *who_name = who_node->who_perm.who_name;
6460
int weight = who_type2weight(who_type);
6461
boolean_t first = B_TRUE;
6462
deleg_perm_node_t *deleg_node;
6463
6464
if (prev_weight != weight) {
6465
(void) printf("%s", sc_title[weight]);
6466
prev_weight = weight;
6467
}
6468
6469
if (who_name == NULL || strnlen(who_name, 1) == 0)
6470
(void) printf("\t");
6471
else
6472
(void) printf("\t%s ", who_name);
6473
6474
for (deleg_node = uu_avl_first(avl); deleg_node != NULL;
6475
deleg_node = uu_avl_next(avl, deleg_node)) {
6476
if (first) {
6477
(void) printf("%s",
6478
deleg_node->dpn_perm.dp_name);
6479
first = B_FALSE;
6480
} else
6481
(void) printf(",%s",
6482
deleg_node->dpn_perm.dp_name);
6483
}
6484
6485
(void) printf("\n");
6486
}
6487
}
6488
6489
static void
6490
print_uge_deleg_perms(uu_avl_t *who_avl, boolean_t local, boolean_t descend,
6491
const char *title)
6492
{
6493
who_perm_node_t *who_node = NULL;
6494
boolean_t prt_title = B_TRUE;
6495
uu_avl_walk_t *walk;
6496
6497
if ((walk = uu_avl_walk_start(who_avl, UU_WALK_ROBUST)) == NULL)
6498
nomem();
6499
6500
while ((who_node = uu_avl_walk_next(walk)) != NULL) {
6501
const char *who_name = who_node->who_perm.who_name;
6502
const char *nice_who_name = who_node->who_perm.who_ug_name;
6503
uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl;
6504
zfs_deleg_who_type_t who_type = who_node->who_perm.who_type;
6505
char delim = ' ';
6506
deleg_perm_node_t *deleg_node;
6507
boolean_t prt_who = B_TRUE;
6508
6509
for (deleg_node = uu_avl_first(avl);
6510
deleg_node != NULL;
6511
deleg_node = uu_avl_next(avl, deleg_node)) {
6512
if (local != deleg_node->dpn_perm.dp_local ||
6513
descend != deleg_node->dpn_perm.dp_descend)
6514
continue;
6515
6516
if (prt_who) {
6517
const char *who = NULL;
6518
if (prt_title) {
6519
prt_title = B_FALSE;
6520
(void) printf("%s", title);
6521
}
6522
6523
switch (who_type) {
6524
case ZFS_DELEG_USER_SETS:
6525
case ZFS_DELEG_USER:
6526
who = gettext("user");
6527
if (nice_who_name)
6528
who_name = nice_who_name;
6529
break;
6530
case ZFS_DELEG_GROUP_SETS:
6531
case ZFS_DELEG_GROUP:
6532
who = gettext("group");
6533
if (nice_who_name)
6534
who_name = nice_who_name;
6535
break;
6536
case ZFS_DELEG_EVERYONE_SETS:
6537
case ZFS_DELEG_EVERYONE:
6538
who = gettext("everyone");
6539
who_name = NULL;
6540
break;
6541
6542
default:
6543
assert(who != NULL);
6544
}
6545
6546
prt_who = B_FALSE;
6547
if (who_name == NULL)
6548
(void) printf("\t%s", who);
6549
else
6550
(void) printf("\t%s %s", who, who_name);
6551
}
6552
6553
(void) printf("%c%s", delim,
6554
deleg_node->dpn_perm.dp_name);
6555
delim = ',';
6556
}
6557
6558
if (!prt_who)
6559
(void) printf("\n");
6560
}
6561
6562
uu_avl_walk_end(walk);
6563
}
6564
6565
static void
6566
print_fs_perms(fs_perm_set_t *fspset)
6567
{
6568
fs_perm_node_t *node = NULL;
6569
char buf[MAXNAMELEN + 32];
6570
const char *dsname = buf;
6571
6572
for (node = uu_list_first(fspset->fsps_list); node != NULL;
6573
node = uu_list_next(fspset->fsps_list, node)) {
6574
uu_avl_t *sc_avl = node->fspn_fsperm.fsp_sc_avl;
6575
uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl;
6576
int left = 0;
6577
6578
(void) snprintf(buf, sizeof (buf),
6579
gettext("---- Permissions on %s "),
6580
node->fspn_fsperm.fsp_name);
6581
(void) printf("%s", dsname);
6582
left = 70 - strlen(buf);
6583
while (left-- > 0)
6584
(void) printf("-");
6585
(void) printf("\n");
6586
6587
print_set_creat_perms(sc_avl);
6588
print_uge_deleg_perms(uge_avl, B_TRUE, B_FALSE,
6589
gettext("Local permissions:\n"));
6590
print_uge_deleg_perms(uge_avl, B_FALSE, B_TRUE,
6591
gettext("Descendent permissions:\n"));
6592
print_uge_deleg_perms(uge_avl, B_TRUE, B_TRUE,
6593
gettext("Local+Descendent permissions:\n"));
6594
}
6595
}
6596
6597
static fs_perm_set_t fs_perm_set = { NULL, NULL, NULL, NULL };
6598
6599
struct deleg_perms {
6600
boolean_t un;
6601
nvlist_t *nvl;
6602
};
6603
6604
static int
6605
set_deleg_perms(zfs_handle_t *zhp, void *data)
6606
{
6607
struct deleg_perms *perms = (struct deleg_perms *)data;
6608
zfs_type_t zfs_type = zfs_get_type(zhp);
6609
6610
if (zfs_type != ZFS_TYPE_FILESYSTEM && zfs_type != ZFS_TYPE_VOLUME)
6611
return (0);
6612
6613
return (zfs_set_fsacl(zhp, perms->un, perms->nvl));
6614
}
6615
6616
static int
6617
zfs_do_allow_unallow_impl(int argc, char **argv, boolean_t un)
6618
{
6619
zfs_handle_t *zhp;
6620
nvlist_t *perm_nvl = NULL;
6621
nvlist_t *update_perm_nvl = NULL;
6622
int error = 1;
6623
int c;
6624
struct allow_opts opts = { 0 };
6625
6626
const char *optstr = un ? "ldugecsrh" : "ldugecsh";
6627
6628
/* check opts */
6629
while ((c = getopt(argc, argv, optstr)) != -1) {
6630
switch (c) {
6631
case 'l':
6632
opts.local = B_TRUE;
6633
break;
6634
case 'd':
6635
opts.descend = B_TRUE;
6636
break;
6637
case 'u':
6638
opts.user = B_TRUE;
6639
break;
6640
case 'g':
6641
opts.group = B_TRUE;
6642
break;
6643
case 'e':
6644
opts.everyone = B_TRUE;
6645
break;
6646
case 's':
6647
opts.set = B_TRUE;
6648
break;
6649
case 'c':
6650
opts.create = B_TRUE;
6651
break;
6652
case 'r':
6653
opts.recursive = B_TRUE;
6654
break;
6655
case ':':
6656
(void) fprintf(stderr, gettext("missing argument for "
6657
"'%c' option\n"), optopt);
6658
usage(B_FALSE);
6659
break;
6660
case 'h':
6661
opts.prt_usage = B_TRUE;
6662
break;
6663
case '?':
6664
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6665
optopt);
6666
usage(B_FALSE);
6667
}
6668
}
6669
6670
argc -= optind;
6671
argv += optind;
6672
6673
/* check arguments */
6674
parse_allow_args(argc, argv, un, &opts);
6675
6676
/* try to open the dataset */
6677
if ((zhp = zfs_open(g_zfs, opts.dataset, ZFS_TYPE_FILESYSTEM |
6678
ZFS_TYPE_VOLUME)) == NULL) {
6679
(void) fprintf(stderr, "Failed to open dataset: %s\n",
6680
opts.dataset);
6681
return (-1);
6682
}
6683
6684
if (zfs_get_fsacl(zhp, &perm_nvl) != 0)
6685
goto cleanup2;
6686
6687
fs_perm_set_init(&fs_perm_set);
6688
if (parse_fs_perm_set(&fs_perm_set, perm_nvl) != 0) {
6689
(void) fprintf(stderr, "Failed to parse fsacl permissions\n");
6690
goto cleanup1;
6691
}
6692
6693
if (opts.prt_perms)
6694
print_fs_perms(&fs_perm_set);
6695
else {
6696
(void) construct_fsacl_list(un, &opts, &update_perm_nvl);
6697
if (zfs_set_fsacl(zhp, un, update_perm_nvl) != 0)
6698
goto cleanup0;
6699
6700
if (un && opts.recursive) {
6701
struct deleg_perms data = { un, update_perm_nvl };
6702
if (zfs_iter_filesystems_v2(zhp, 0, set_deleg_perms,
6703
&data) != 0)
6704
goto cleanup0;
6705
}
6706
}
6707
6708
error = 0;
6709
6710
cleanup0:
6711
nvlist_free(perm_nvl);
6712
nvlist_free(update_perm_nvl);
6713
cleanup1:
6714
fs_perm_set_fini(&fs_perm_set);
6715
cleanup2:
6716
zfs_close(zhp);
6717
6718
return (error);
6719
}
6720
6721
static int
6722
zfs_do_allow(int argc, char **argv)
6723
{
6724
return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE));
6725
}
6726
6727
static int
6728
zfs_do_unallow(int argc, char **argv)
6729
{
6730
return (zfs_do_allow_unallow_impl(argc, argv, B_TRUE));
6731
}
6732
6733
static int
6734
zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
6735
{
6736
int errors = 0;
6737
int i;
6738
const char *tag;
6739
boolean_t recursive = B_FALSE;
6740
const char *opts = holding ? "rt" : "r";
6741
int c;
6742
6743
/* check options */
6744
while ((c = getopt(argc, argv, opts)) != -1) {
6745
switch (c) {
6746
case 'r':
6747
recursive = B_TRUE;
6748
break;
6749
case '?':
6750
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6751
optopt);
6752
usage(B_FALSE);
6753
}
6754
}
6755
6756
argc -= optind;
6757
argv += optind;
6758
6759
/* check number of arguments */
6760
if (argc < 2)
6761
usage(B_FALSE);
6762
6763
tag = argv[0];
6764
--argc;
6765
++argv;
6766
6767
if (holding && tag[0] == '.') {
6768
/* tags starting with '.' are reserved for libzfs */
6769
(void) fprintf(stderr, gettext("tag may not start with '.'\n"));
6770
usage(B_FALSE);
6771
}
6772
6773
for (i = 0; i < argc; ++i) {
6774
zfs_handle_t *zhp;
6775
char parent[ZFS_MAX_DATASET_NAME_LEN];
6776
const char *delim;
6777
char *path = argv[i];
6778
6779
delim = strchr(path, '@');
6780
if (delim == NULL) {
6781
(void) fprintf(stderr,
6782
gettext("'%s' is not a snapshot\n"), path);
6783
++errors;
6784
continue;
6785
}
6786
(void) strlcpy(parent, path, MIN(sizeof (parent),
6787
delim - path + 1));
6788
6789
zhp = zfs_open(g_zfs, parent,
6790
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
6791
if (zhp == NULL) {
6792
++errors;
6793
continue;
6794
}
6795
if (holding) {
6796
if (zfs_hold(zhp, delim+1, tag, recursive, -1) != 0)
6797
++errors;
6798
} else {
6799
if (zfs_release(zhp, delim+1, tag, recursive) != 0)
6800
++errors;
6801
}
6802
zfs_close(zhp);
6803
}
6804
6805
return (errors != 0);
6806
}
6807
6808
/*
6809
* zfs hold [-r] [-t] <tag> <snap> ...
6810
*
6811
* -r Recursively hold
6812
*
6813
* Apply a user-hold with the given tag to the list of snapshots.
6814
*/
6815
static int
6816
zfs_do_hold(int argc, char **argv)
6817
{
6818
return (zfs_do_hold_rele_impl(argc, argv, B_TRUE));
6819
}
6820
6821
/*
6822
* zfs release [-r] <tag> <snap> ...
6823
*
6824
* -r Recursively release
6825
*
6826
* Release a user-hold with the given tag from the list of snapshots.
6827
*/
6828
static int
6829
zfs_do_release(int argc, char **argv)
6830
{
6831
return (zfs_do_hold_rele_impl(argc, argv, B_FALSE));
6832
}
6833
6834
typedef struct holds_cbdata {
6835
boolean_t cb_recursive;
6836
const char *cb_snapname;
6837
nvlist_t **cb_nvlp;
6838
size_t cb_max_namelen;
6839
size_t cb_max_taglen;
6840
} holds_cbdata_t;
6841
6842
#define STRFTIME_FMT_STR "%a %b %e %H:%M %Y"
6843
#define DATETIME_BUF_LEN (32)
6844
/*
6845
*
6846
*/
6847
static void
6848
print_holds(boolean_t scripted, int nwidth, int tagwidth, nvlist_t *nvl,
6849
boolean_t parsable)
6850
{
6851
int i;
6852
nvpair_t *nvp = NULL;
6853
const char *const hdr_cols[] = { "NAME", "TAG", "TIMESTAMP" };
6854
const char *col;
6855
6856
if (!scripted) {
6857
for (i = 0; i < 3; i++) {
6858
col = gettext(hdr_cols[i]);
6859
if (i < 2)
6860
(void) printf("%-*s ", i ? tagwidth : nwidth,
6861
col);
6862
else
6863
(void) printf("%s\n", col);
6864
}
6865
}
6866
6867
while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
6868
const char *zname = nvpair_name(nvp);
6869
nvlist_t *nvl2;
6870
nvpair_t *nvp2 = NULL;
6871
(void) nvpair_value_nvlist(nvp, &nvl2);
6872
while ((nvp2 = nvlist_next_nvpair(nvl2, nvp2)) != NULL) {
6873
char tsbuf[DATETIME_BUF_LEN];
6874
const char *tagname = nvpair_name(nvp2);
6875
uint64_t val = 0;
6876
time_t time;
6877
struct tm t;
6878
6879
(void) nvpair_value_uint64(nvp2, &val);
6880
time = (time_t)val;
6881
(void) localtime_r(&time, &t);
6882
(void) strftime(tsbuf, DATETIME_BUF_LEN,
6883
gettext(STRFTIME_FMT_STR), &t);
6884
6885
if (scripted) {
6886
if (parsable) {
6887
(void) printf("%s\t%s\t%lld\n", zname,
6888
tagname, (long long)time);
6889
} else {
6890
(void) printf("%s\t%s\t%s\n", zname,
6891
tagname, tsbuf);
6892
}
6893
} else {
6894
if (parsable) {
6895
(void) printf("%-*s %-*s %lld\n",
6896
nwidth, zname, tagwidth,
6897
tagname, (long long)time);
6898
} else {
6899
(void) printf("%-*s %-*s %s\n",
6900
nwidth, zname, tagwidth,
6901
tagname, tsbuf);
6902
}
6903
}
6904
}
6905
}
6906
}
6907
6908
/*
6909
* Generic callback function to list a dataset or snapshot.
6910
*/
6911
static int
6912
holds_callback(zfs_handle_t *zhp, void *data)
6913
{
6914
holds_cbdata_t *cbp = data;
6915
nvlist_t *top_nvl = *cbp->cb_nvlp;
6916
nvlist_t *nvl = NULL;
6917
nvpair_t *nvp = NULL;
6918
const char *zname = zfs_get_name(zhp);
6919
size_t znamelen = strlen(zname);
6920
6921
if (cbp->cb_recursive) {
6922
const char *snapname;
6923
char *delim = strchr(zname, '@');
6924
if (delim == NULL)
6925
return (0);
6926
6927
snapname = delim + 1;
6928
if (strcmp(cbp->cb_snapname, snapname))
6929
return (0);
6930
}
6931
6932
if (zfs_get_holds(zhp, &nvl) != 0)
6933
return (-1);
6934
6935
if (znamelen > cbp->cb_max_namelen)
6936
cbp->cb_max_namelen = znamelen;
6937
6938
while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
6939
const char *tag = nvpair_name(nvp);
6940
size_t taglen = strlen(tag);
6941
if (taglen > cbp->cb_max_taglen)
6942
cbp->cb_max_taglen = taglen;
6943
}
6944
6945
return (nvlist_add_nvlist(top_nvl, zname, nvl));
6946
}
6947
6948
/*
6949
* zfs holds [-rHp] <snap> ...
6950
*
6951
* -r Lists holds that are set on the named snapshots recursively.
6952
* -H Scripted mode; elide headers and separate columns by tabs.
6953
* -p Display values in parsable (literal) format.
6954
*/
6955
static int
6956
zfs_do_holds(int argc, char **argv)
6957
{
6958
int c;
6959
boolean_t errors = B_FALSE;
6960
boolean_t scripted = B_FALSE;
6961
boolean_t recursive = B_FALSE;
6962
boolean_t parsable = B_FALSE;
6963
6964
int types = ZFS_TYPE_SNAPSHOT;
6965
holds_cbdata_t cb = { 0 };
6966
6967
int limit = 0;
6968
int ret = 0;
6969
int flags = 0;
6970
6971
/* check options */
6972
while ((c = getopt(argc, argv, "rHp")) != -1) {
6973
switch (c) {
6974
case 'r':
6975
recursive = B_TRUE;
6976
break;
6977
case 'H':
6978
scripted = B_TRUE;
6979
break;
6980
case 'p':
6981
parsable = B_TRUE;
6982
break;
6983
case '?':
6984
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6985
optopt);
6986
usage(B_FALSE);
6987
}
6988
}
6989
6990
if (recursive) {
6991
types |= ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
6992
flags |= ZFS_ITER_RECURSE;
6993
}
6994
6995
argc -= optind;
6996
argv += optind;
6997
6998
/* check number of arguments */
6999
if (argc < 1)
7000
usage(B_FALSE);
7001
7002
nvlist_t *nvl = fnvlist_alloc();
7003
7004
for (int i = 0; i < argc; ++i) {
7005
char *snapshot = argv[i];
7006
const char *delim;
7007
const char *snapname;
7008
7009
delim = strchr(snapshot, '@');
7010
if (delim == NULL) {
7011
(void) fprintf(stderr,
7012
gettext("'%s' is not a snapshot\n"), snapshot);
7013
errors = B_TRUE;
7014
continue;
7015
}
7016
snapname = delim + 1;
7017
if (recursive)
7018
snapshot[delim - snapshot] = '\0';
7019
7020
cb.cb_recursive = recursive;
7021
cb.cb_snapname = snapname;
7022
cb.cb_nvlp = &nvl;
7023
7024
/*
7025
* 1. collect holds data, set format options
7026
*/
7027
ret = zfs_for_each(1, argv + i, flags, types, NULL, NULL, limit,
7028
holds_callback, &cb);
7029
if (ret != 0)
7030
errors = B_TRUE;
7031
}
7032
7033
/*
7034
* 2. print holds data
7035
*/
7036
print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl,
7037
parsable);
7038
7039
if (nvlist_empty(nvl))
7040
(void) fprintf(stderr, gettext("no datasets available\n"));
7041
7042
nvlist_free(nvl);
7043
7044
return (errors);
7045
}
7046
7047
#define CHECK_SPINNER 30
7048
#define SPINNER_TIME 3 /* seconds */
7049
#define MOUNT_TIME 1 /* seconds */
7050
7051
typedef struct get_all_state {
7052
char **ga_datasets;
7053
int ga_count;
7054
boolean_t ga_verbose;
7055
get_all_cb_t *ga_cbp;
7056
} get_all_state_t;
7057
7058
static int
7059
get_one_dataset(zfs_handle_t *zhp, void *data)
7060
{
7061
static const char *const spin[] = { "-", "\\", "|", "/" };
7062
static int spinval = 0;
7063
static int spincheck = 0;
7064
static time_t last_spin_time = (time_t)0;
7065
get_all_state_t *state = data;
7066
zfs_type_t type = zfs_get_type(zhp);
7067
7068
if (state->ga_verbose) {
7069
if (--spincheck < 0) {
7070
time_t now = time(NULL);
7071
if (last_spin_time + SPINNER_TIME < now) {
7072
update_progress(spin[spinval++ % 4]);
7073
last_spin_time = now;
7074
}
7075
spincheck = CHECK_SPINNER;
7076
}
7077
}
7078
7079
/*
7080
* Iterate over any nested datasets.
7081
*/
7082
if (zfs_iter_filesystems_v2(zhp, 0, get_one_dataset, data) != 0) {
7083
zfs_close(zhp);
7084
return (1);
7085
}
7086
7087
/*
7088
* Skip any datasets whose type does not match.
7089
*/
7090
if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
7091
zfs_close(zhp);
7092
return (0);
7093
}
7094
libzfs_add_handle(state->ga_cbp, zhp);
7095
assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
7096
7097
return (0);
7098
}
7099
7100
static int
7101
get_recursive_datasets(zfs_handle_t *zhp, void *data)
7102
{
7103
get_all_state_t *state = data;
7104
int len = strlen(zfs_get_name(zhp));
7105
for (int i = 0; i < state->ga_count; ++i) {
7106
if (strcmp(state->ga_datasets[i], zfs_get_name(zhp)) == 0)
7107
return (get_one_dataset(zhp, data));
7108
else if ((strncmp(state->ga_datasets[i], zfs_get_name(zhp),
7109
len) == 0) && state->ga_datasets[i][len] == '/') {
7110
(void) zfs_iter_filesystems_v2(zhp, 0,
7111
get_recursive_datasets, data);
7112
}
7113
}
7114
zfs_close(zhp);
7115
return (0);
7116
}
7117
7118
static void
7119
get_all_datasets(get_all_state_t *state)
7120
{
7121
if (state->ga_verbose)
7122
set_progress_header(gettext("Reading ZFS config"));
7123
if (state->ga_datasets == NULL)
7124
(void) zfs_iter_root(g_zfs, get_one_dataset, state);
7125
else
7126
(void) zfs_iter_root(g_zfs, get_recursive_datasets, state);
7127
7128
if (state->ga_verbose)
7129
finish_progress(gettext("done."));
7130
}
7131
7132
/*
7133
* Generic callback for sharing or mounting filesystems. Because the code is so
7134
* similar, we have a common function with an extra parameter to determine which
7135
* mode we are using.
7136
*/
7137
typedef enum { OP_SHARE, OP_MOUNT } share_mount_op_t;
7138
7139
typedef struct share_mount_state {
7140
share_mount_op_t sm_op;
7141
boolean_t sm_verbose;
7142
int sm_flags;
7143
char *sm_options;
7144
enum sa_protocol sm_proto; /* only valid for OP_SHARE */
7145
pthread_mutex_t sm_lock; /* protects the remaining fields */
7146
uint_t sm_total; /* number of filesystems to process */
7147
uint_t sm_done; /* number of filesystems processed */
7148
int sm_status; /* -1 if any of the share/mount operations failed */
7149
} share_mount_state_t;
7150
7151
/*
7152
* Share or mount a dataset.
7153
*/
7154
static int
7155
share_mount_one(zfs_handle_t *zhp, int op, int flags, enum sa_protocol protocol,
7156
boolean_t explicit, const char *options)
7157
{
7158
char mountpoint[ZFS_MAXPROPLEN];
7159
char shareopts[ZFS_MAXPROPLEN];
7160
char smbshareopts[ZFS_MAXPROPLEN];
7161
const char *cmdname = op == OP_SHARE ? "share" : "mount";
7162
struct mnttab mnt;
7163
uint64_t zoned, canmount;
7164
boolean_t shared_nfs, shared_smb;
7165
7166
assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM);
7167
7168
/*
7169
* Check to make sure we can mount/share this dataset. If we
7170
* are in the global zone and the filesystem is exported to a
7171
* local zone, or if we are in a local zone and the
7172
* filesystem is not exported, then it is an error.
7173
*/
7174
zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
7175
7176
if (zoned && getzoneid() == GLOBAL_ZONEID) {
7177
if (!explicit)
7178
return (0);
7179
7180
(void) fprintf(stderr, gettext("cannot %s '%s': "
7181
"dataset is exported to a local zone\n"), cmdname,
7182
zfs_get_name(zhp));
7183
return (1);
7184
7185
} else if (!zoned && getzoneid() != GLOBAL_ZONEID) {
7186
if (!explicit)
7187
return (0);
7188
7189
(void) fprintf(stderr, gettext("cannot %s '%s': "
7190
"permission denied\n"), cmdname,
7191
zfs_get_name(zhp));
7192
return (1);
7193
}
7194
7195
/*
7196
* Ignore any filesystems which don't apply to us. This
7197
* includes those with a legacy mountpoint, or those with
7198
* legacy share options.
7199
*/
7200
verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
7201
sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
7202
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
7203
sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
7204
verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts,
7205
sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0);
7206
7207
if (op == OP_SHARE && strcmp(shareopts, "off") == 0 &&
7208
strcmp(smbshareopts, "off") == 0) {
7209
if (!explicit)
7210
return (0);
7211
7212
(void) fprintf(stderr, gettext("cannot share '%s': "
7213
"legacy share\n"), zfs_get_name(zhp));
7214
(void) fprintf(stderr, gettext("use exports(5) or "
7215
"smb.conf(5) to share this filesystem, or set "
7216
"the sharenfs or sharesmb property\n"));
7217
return (1);
7218
}
7219
7220
/*
7221
* We cannot share or mount legacy filesystems. If the
7222
* shareopts is non-legacy but the mountpoint is legacy, we
7223
* treat it as a legacy share.
7224
*/
7225
if (strcmp(mountpoint, "legacy") == 0) {
7226
if (!explicit)
7227
return (0);
7228
7229
(void) fprintf(stderr, gettext("cannot %s '%s': "
7230
"legacy mountpoint\n"), cmdname, zfs_get_name(zhp));
7231
(void) fprintf(stderr, gettext("use %s(8) to "
7232
"%s this filesystem\n"), cmdname, cmdname);
7233
return (1);
7234
}
7235
7236
if (strcmp(mountpoint, "none") == 0) {
7237
if (!explicit)
7238
return (0);
7239
7240
(void) fprintf(stderr, gettext("cannot %s '%s': no "
7241
"mountpoint set\n"), cmdname, zfs_get_name(zhp));
7242
return (1);
7243
}
7244
7245
/*
7246
* canmount explicit outcome
7247
* on no pass through
7248
* on yes pass through
7249
* off no return 0
7250
* off yes display error, return 1
7251
* noauto no return 0
7252
* noauto yes pass through
7253
*/
7254
canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
7255
if (canmount == ZFS_CANMOUNT_OFF) {
7256
if (!explicit)
7257
return (0);
7258
7259
(void) fprintf(stderr, gettext("cannot %s '%s': "
7260
"'canmount' property is set to 'off'\n"), cmdname,
7261
zfs_get_name(zhp));
7262
return (1);
7263
} else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
7264
/*
7265
* When performing a 'zfs mount -a', we skip any mounts for
7266
* datasets that have 'noauto' set. Sharing a dataset with
7267
* 'noauto' set is only allowed if it's mounted.
7268
*/
7269
if (op == OP_MOUNT)
7270
return (0);
7271
if (op == OP_SHARE && !zfs_is_mounted(zhp, NULL)) {
7272
/* also purge it from existing exports */
7273
zfs_unshare(zhp, mountpoint, NULL);
7274
return (0);
7275
}
7276
}
7277
7278
/*
7279
* If this filesystem is encrypted and does not have
7280
* a loaded key, we can not mount it.
7281
*/
7282
if ((flags & MS_CRYPT) == 0 &&
7283
zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) != ZIO_CRYPT_OFF &&
7284
zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS) ==
7285
ZFS_KEYSTATUS_UNAVAILABLE) {
7286
if (!explicit)
7287
return (0);
7288
7289
(void) fprintf(stderr, gettext("cannot %s '%s': "
7290
"encryption key not loaded\n"), cmdname, zfs_get_name(zhp));
7291
return (1);
7292
}
7293
7294
/*
7295
* If this filesystem is inconsistent and has a receive resume
7296
* token, we can not mount it.
7297
*/
7298
if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
7299
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
7300
NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
7301
if (!explicit)
7302
return (0);
7303
7304
(void) fprintf(stderr, gettext("cannot %s '%s': "
7305
"Contains partially-completed state from "
7306
"\"zfs receive -s\", which can be resumed with "
7307
"\"zfs send -t\"\n"),
7308
cmdname, zfs_get_name(zhp));
7309
return (1);
7310
}
7311
7312
if (zfs_prop_get_int(zhp, ZFS_PROP_REDACTED) && !(flags & MS_FORCE)) {
7313
if (!explicit)
7314
return (0);
7315
7316
(void) fprintf(stderr, gettext("cannot %s '%s': "
7317
"Dataset is not complete, was created by receiving "
7318
"a redacted zfs send stream.\n"), cmdname,
7319
zfs_get_name(zhp));
7320
return (1);
7321
}
7322
7323
/*
7324
* At this point, we have verified that the mountpoint and/or
7325
* shareopts are appropriate for auto management. If the
7326
* filesystem is already mounted or shared, return (failing
7327
* for explicit requests); otherwise mount or share the
7328
* filesystem.
7329
*/
7330
switch (op) {
7331
case OP_SHARE: {
7332
enum sa_protocol prot[] = {SA_PROTOCOL_NFS, SA_NO_PROTOCOL};
7333
shared_nfs = zfs_is_shared(zhp, NULL, prot);
7334
*prot = SA_PROTOCOL_SMB;
7335
shared_smb = zfs_is_shared(zhp, NULL, prot);
7336
7337
if ((shared_nfs && shared_smb) ||
7338
(shared_nfs && strcmp(shareopts, "on") == 0 &&
7339
strcmp(smbshareopts, "off") == 0) ||
7340
(shared_smb && strcmp(smbshareopts, "on") == 0 &&
7341
strcmp(shareopts, "off") == 0)) {
7342
if (!explicit)
7343
return (0);
7344
7345
(void) fprintf(stderr, gettext("cannot share "
7346
"'%s': filesystem already shared\n"),
7347
zfs_get_name(zhp));
7348
return (1);
7349
}
7350
7351
if (!zfs_is_mounted(zhp, NULL) &&
7352
zfs_mount(zhp, NULL, flags) != 0)
7353
return (1);
7354
7355
*prot = protocol;
7356
if (zfs_share(zhp, protocol == SA_NO_PROTOCOL ? NULL : prot))
7357
return (1);
7358
7359
}
7360
break;
7361
7362
case OP_MOUNT:
7363
mnt.mnt_mntopts = (char *)(options ?: "");
7364
7365
if (!hasmntopt(&mnt, MNTOPT_REMOUNT) &&
7366
zfs_is_mounted(zhp, NULL)) {
7367
if (!explicit)
7368
return (0);
7369
7370
(void) fprintf(stderr, gettext("cannot mount "
7371
"'%s': filesystem already mounted\n"),
7372
zfs_get_name(zhp));
7373
return (1);
7374
}
7375
7376
if (zfs_mount(zhp, options, flags) != 0)
7377
return (1);
7378
break;
7379
}
7380
7381
return (0);
7382
}
7383
7384
/*
7385
* Reports progress in the form "(current/total)". Not thread-safe.
7386
*/
7387
static void
7388
report_mount_progress(int current, int total)
7389
{
7390
static time_t last_progress_time = 0;
7391
time_t now = time(NULL);
7392
char info[32];
7393
7394
/* display header if we're here for the first time */
7395
if (current == 1) {
7396
set_progress_header(gettext("Mounting ZFS filesystems"));
7397
} else if (current != total && last_progress_time + MOUNT_TIME >= now) {
7398
/* too soon to report again */
7399
return;
7400
}
7401
7402
last_progress_time = now;
7403
7404
(void) sprintf(info, "(%d/%d)", current, total);
7405
7406
if (current == total)
7407
finish_progress(info);
7408
else
7409
update_progress(info);
7410
}
7411
7412
/*
7413
* zfs_foreach_mountpoint() callback that mounts or shares one filesystem and
7414
* updates the progress meter.
7415
*/
7416
static int
7417
share_mount_one_cb(zfs_handle_t *zhp, void *arg)
7418
{
7419
share_mount_state_t *sms = arg;
7420
int ret;
7421
7422
ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
7423
B_FALSE, sms->sm_options);
7424
7425
pthread_mutex_lock(&sms->sm_lock);
7426
if (ret != 0)
7427
sms->sm_status = ret;
7428
sms->sm_done++;
7429
if (sms->sm_verbose)
7430
report_mount_progress(sms->sm_done, sms->sm_total);
7431
pthread_mutex_unlock(&sms->sm_lock);
7432
return (ret);
7433
}
7434
7435
static void
7436
append_options(char *mntopts, char *newopts)
7437
{
7438
int len = strlen(mntopts);
7439
7440
/* original length plus new string to append plus 1 for the comma */
7441
if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
7442
(void) fprintf(stderr, gettext("the opts argument for "
7443
"'%s' option is too long (more than %d chars)\n"),
7444
"-o", MNT_LINE_MAX);
7445
usage(B_FALSE);
7446
}
7447
7448
if (*mntopts)
7449
mntopts[len++] = ',';
7450
7451
(void) strcpy(&mntopts[len], newopts);
7452
}
7453
7454
static enum sa_protocol
7455
sa_protocol_decode(const char *protocol)
7456
{
7457
for (enum sa_protocol i = 0; i < ARRAY_SIZE(sa_protocol_names); ++i)
7458
if (strcmp(protocol, sa_protocol_names[i]) == 0)
7459
return (i);
7460
7461
(void) fputs(gettext("share type must be one of: "), stderr);
7462
for (enum sa_protocol i = 0;
7463
i < ARRAY_SIZE(sa_protocol_names); ++i)
7464
(void) fprintf(stderr, "%s%s",
7465
i != 0 ? ", " : "", sa_protocol_names[i]);
7466
(void) fputc('\n', stderr);
7467
usage(B_FALSE);
7468
}
7469
7470
static int
7471
share_mount(int op, int argc, char **argv)
7472
{
7473
int do_all = 0;
7474
int recursive = 0;
7475
boolean_t verbose = B_FALSE;
7476
boolean_t json = B_FALSE;
7477
int c, ret = 0;
7478
char *options = NULL;
7479
int flags = 0;
7480
nvlist_t *jsobj, *data, *item;
7481
const uint_t mount_nthr = 512;
7482
uint_t nthr;
7483
jsobj = data = item = NULL;
7484
7485
struct option long_options[] = {
7486
{"json", no_argument, NULL, 'j'},
7487
{0, 0, 0, 0}
7488
};
7489
7490
/* check options */
7491
while ((c = getopt_long(argc, argv,
7492
op == OP_MOUNT ? ":ajRlvo:Of" : "al",
7493
op == OP_MOUNT ? long_options : NULL, NULL)) != -1) {
7494
switch (c) {
7495
case 'a':
7496
do_all = 1;
7497
break;
7498
case 'R':
7499
recursive = 1;
7500
break;
7501
case 'v':
7502
verbose = B_TRUE;
7503
break;
7504
case 'l':
7505
flags |= MS_CRYPT;
7506
break;
7507
case 'j':
7508
json = B_TRUE;
7509
jsobj = zfs_json_schema(0, 1);
7510
data = fnvlist_alloc();
7511
break;
7512
case 'o':
7513
if (*optarg == '\0') {
7514
(void) fprintf(stderr, gettext("empty mount "
7515
"options (-o) specified\n"));
7516
usage(B_FALSE);
7517
}
7518
7519
if (options == NULL)
7520
options = safe_malloc(MNT_LINE_MAX + 1);
7521
7522
/* option validation is done later */
7523
append_options(options, optarg);
7524
break;
7525
case 'O':
7526
flags |= MS_OVERLAY;
7527
break;
7528
case 'f':
7529
flags |= MS_FORCE;
7530
break;
7531
case ':':
7532
(void) fprintf(stderr, gettext("missing argument for "
7533
"'%c' option\n"), optopt);
7534
usage(B_FALSE);
7535
break;
7536
case '?':
7537
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
7538
optopt);
7539
usage(B_FALSE);
7540
}
7541
}
7542
7543
argc -= optind;
7544
argv += optind;
7545
7546
if (json && argc != 0) {
7547
(void) fprintf(stderr, gettext("too many arguments\n"));
7548
usage(B_FALSE);
7549
}
7550
7551
/* check number of arguments */
7552
if (do_all || recursive) {
7553
enum sa_protocol protocol = SA_NO_PROTOCOL;
7554
7555
if (op == OP_SHARE && argc > 0) {
7556
protocol = sa_protocol_decode(argv[0]);
7557
argc--;
7558
argv++;
7559
}
7560
7561
if (argc != 0 && do_all) {
7562
(void) fprintf(stderr, gettext("too many arguments\n"));
7563
usage(B_FALSE);
7564
}
7565
7566
if (argc == 0 && recursive) {
7567
(void) fprintf(stderr,
7568
gettext("no dataset provided\n"));
7569
usage(B_FALSE);
7570
}
7571
7572
start_progress_timer();
7573
get_all_cb_t cb = { 0 };
7574
get_all_state_t state = { 0 };
7575
if (argc == 0) {
7576
state.ga_datasets = NULL;
7577
state.ga_count = -1;
7578
} else {
7579
zfs_handle_t *zhp;
7580
for (int i = 0; i < argc; i++) {
7581
zhp = zfs_open(g_zfs, argv[i],
7582
ZFS_TYPE_FILESYSTEM);
7583
if (zhp == NULL)
7584
usage(B_FALSE);
7585
zfs_close(zhp);
7586
}
7587
state.ga_datasets = argv;
7588
state.ga_count = argc;
7589
}
7590
state.ga_verbose = verbose;
7591
state.ga_cbp = &cb;
7592
get_all_datasets(&state);
7593
7594
if (cb.cb_used == 0) {
7595
free(options);
7596
return (0);
7597
}
7598
7599
share_mount_state_t share_mount_state = { 0 };
7600
share_mount_state.sm_op = op;
7601
share_mount_state.sm_verbose = verbose;
7602
share_mount_state.sm_flags = flags;
7603
share_mount_state.sm_options = options;
7604
share_mount_state.sm_proto = protocol;
7605
share_mount_state.sm_total = cb.cb_used;
7606
pthread_mutex_init(&share_mount_state.sm_lock, NULL);
7607
7608
/* For a 'zfs share -a' operation start with a clean slate. */
7609
if (op == OP_SHARE)
7610
zfs_truncate_shares(NULL);
7611
7612
/*
7613
* libshare isn't mt-safe, so only do the operation in parallel
7614
* if we're mounting. Additionally, the key-loading option must
7615
* be serialized so that we can prompt the user for their keys
7616
* in a consistent manner.
7617
*/
7618
nthr = op == OP_MOUNT && !(flags & MS_CRYPT) ? mount_nthr : 1;
7619
zfs_foreach_mountpoint(g_zfs, cb.cb_handles, cb.cb_used,
7620
share_mount_one_cb, &share_mount_state, nthr);
7621
zfs_commit_shares(NULL);
7622
7623
ret = share_mount_state.sm_status;
7624
7625
for (int i = 0; i < cb.cb_used; i++)
7626
zfs_close(cb.cb_handles[i]);
7627
free(cb.cb_handles);
7628
} else if (argc == 0) {
7629
FILE *mnttab;
7630
struct mnttab entry;
7631
7632
if ((op == OP_SHARE) || (options != NULL)) {
7633
(void) fprintf(stderr, gettext("missing filesystem "
7634
"argument (specify -a for all)\n"));
7635
usage(B_FALSE);
7636
}
7637
7638
/*
7639
* When mount is given no arguments, go through
7640
* /proc/self/mounts and display any active ZFS mounts.
7641
* We hide any snapshots, since they are controlled
7642
* automatically.
7643
*/
7644
7645
if ((mnttab = fopen(MNTTAB, "re")) == NULL) {
7646
free(options);
7647
return (ENOENT);
7648
}
7649
7650
while (getmntent(mnttab, &entry) == 0) {
7651
if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
7652
strchr(entry.mnt_special, '@') != NULL)
7653
continue;
7654
if (json) {
7655
item = fnvlist_alloc();
7656
fnvlist_add_string(item, "filesystem",
7657
entry.mnt_special);
7658
fnvlist_add_string(item, "mountpoint",
7659
entry.mnt_mountp);
7660
fnvlist_add_nvlist(data, entry.mnt_special,
7661
item);
7662
fnvlist_free(item);
7663
} else {
7664
(void) printf("%-30s %s\n", entry.mnt_special,
7665
entry.mnt_mountp);
7666
}
7667
}
7668
7669
(void) fclose(mnttab);
7670
if (json) {
7671
fnvlist_add_nvlist(jsobj, "datasets", data);
7672
if (nvlist_empty(data))
7673
fnvlist_free(jsobj);
7674
else
7675
zcmd_print_json(jsobj);
7676
fnvlist_free(data);
7677
}
7678
} else {
7679
zfs_handle_t *zhp;
7680
7681
if (argc > 1) {
7682
(void) fprintf(stderr,
7683
gettext("too many arguments\n"));
7684
usage(B_FALSE);
7685
}
7686
7687
if ((zhp = zfs_open(g_zfs, argv[0],
7688
ZFS_TYPE_FILESYSTEM)) == NULL) {
7689
ret = 1;
7690
} else {
7691
ret = share_mount_one(zhp, op, flags, SA_NO_PROTOCOL,
7692
B_TRUE, options);
7693
zfs_commit_shares(NULL);
7694
zfs_close(zhp);
7695
}
7696
}
7697
7698
free(options);
7699
return (ret);
7700
}
7701
7702
/*
7703
* zfs mount -a
7704
* zfs mount filesystem
7705
*
7706
* Mount all filesystems, or mount the given filesystem.
7707
*/
7708
static int
7709
zfs_do_mount(int argc, char **argv)
7710
{
7711
return (share_mount(OP_MOUNT, argc, argv));
7712
}
7713
7714
/*
7715
* zfs share -a [nfs | smb]
7716
* zfs share filesystem
7717
*
7718
* Share all filesystems, or share the given filesystem.
7719
*/
7720
static int
7721
zfs_do_share(int argc, char **argv)
7722
{
7723
return (share_mount(OP_SHARE, argc, argv));
7724
}
7725
7726
typedef struct unshare_unmount_node {
7727
zfs_handle_t *un_zhp;
7728
char *un_mountp;
7729
uu_avl_node_t un_avlnode;
7730
} unshare_unmount_node_t;
7731
7732
static int
7733
unshare_unmount_compare(const void *larg, const void *rarg, void *unused)
7734
{
7735
(void) unused;
7736
const unshare_unmount_node_t *l = larg;
7737
const unshare_unmount_node_t *r = rarg;
7738
7739
return (strcmp(l->un_mountp, r->un_mountp));
7740
}
7741
7742
/*
7743
* Convenience routine used by zfs_do_umount() and manual_unmount(). Given an
7744
* absolute path, find the entry /proc/self/mounts, verify that it's a
7745
* ZFS filesystem, and unmount it appropriately.
7746
*/
7747
static int
7748
unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
7749
{
7750
zfs_handle_t *zhp;
7751
int ret = 0;
7752
struct stat64 statbuf;
7753
struct extmnttab entry;
7754
const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount";
7755
ino_t path_inode;
7756
char *zfs_mntpnt, *entry_mntpnt;
7757
7758
/*
7759
* Search for the given (major,minor) pair in the mount table.
7760
*/
7761
7762
if (getextmntent(path, &entry, &statbuf) != 0) {
7763
if (op == OP_SHARE) {
7764
(void) fprintf(stderr, gettext("cannot %s '%s': not "
7765
"currently mounted\n"), cmdname, path);
7766
return (1);
7767
}
7768
(void) fprintf(stderr, gettext("warning: %s not in"
7769
"/proc/self/mounts\n"), path);
7770
if ((ret = umount2(path, flags)) != 0)
7771
(void) fprintf(stderr, gettext("%s: %s\n"), path,
7772
strerror(errno));
7773
return (ret != 0);
7774
}
7775
path_inode = statbuf.st_ino;
7776
7777
if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
7778
(void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS "
7779
"filesystem\n"), cmdname, path);
7780
return (1);
7781
}
7782
7783
if ((zhp = zfs_open(g_zfs, entry.mnt_special,
7784
ZFS_TYPE_FILESYSTEM)) == NULL)
7785
return (1);
7786
7787
ret = 1;
7788
if (stat64(entry.mnt_mountp, &statbuf) != 0) {
7789
(void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
7790
cmdname, path, strerror(errno));
7791
goto out;
7792
} else if (statbuf.st_ino != path_inode) {
7793
(void) fprintf(stderr, gettext("cannot "
7794
"%s '%s': not a mountpoint\n"), cmdname, path);
7795
goto out;
7796
}
7797
7798
/*
7799
* If the filesystem is mounted, check that the mountpoint matches
7800
* the one in the mnttab entry w.r.t. provided path. If it doesn't,
7801
* then we should not proceed further.
7802
*/
7803
entry_mntpnt = strdup(entry.mnt_mountp);
7804
if (zfs_is_mounted(zhp, &zfs_mntpnt)) {
7805
if (strcmp(zfs_mntpnt, entry_mntpnt) != 0) {
7806
(void) fprintf(stderr, gettext("cannot %s '%s': "
7807
"not an original mountpoint\n"), cmdname, path);
7808
free(zfs_mntpnt);
7809
free(entry_mntpnt);
7810
goto out;
7811
}
7812
free(zfs_mntpnt);
7813
}
7814
free(entry_mntpnt);
7815
7816
if (op == OP_SHARE) {
7817
char nfs_mnt_prop[ZFS_MAXPROPLEN];
7818
char smbshare_prop[ZFS_MAXPROPLEN];
7819
7820
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, nfs_mnt_prop,
7821
sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0);
7822
verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshare_prop,
7823
sizeof (smbshare_prop), NULL, NULL, 0, B_FALSE) == 0);
7824
7825
if (strcmp(nfs_mnt_prop, "off") == 0 &&
7826
strcmp(smbshare_prop, "off") == 0) {
7827
(void) fprintf(stderr, gettext("cannot unshare "
7828
"'%s': legacy share\n"), path);
7829
(void) fprintf(stderr, gettext("use exportfs(8) "
7830
"or smbcontrol(1) to unshare this filesystem\n"));
7831
} else if (!zfs_is_shared(zhp, NULL, NULL)) {
7832
(void) fprintf(stderr, gettext("cannot unshare '%s': "
7833
"not currently shared\n"), path);
7834
} else {
7835
ret = zfs_unshare(zhp, path, NULL);
7836
zfs_commit_shares(NULL);
7837
}
7838
} else {
7839
char mtpt_prop[ZFS_MAXPROPLEN];
7840
7841
verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mtpt_prop,
7842
sizeof (mtpt_prop), NULL, NULL, 0, B_FALSE) == 0);
7843
7844
if (is_manual) {
7845
ret = zfs_unmount(zhp, NULL, flags);
7846
} else if (strcmp(mtpt_prop, "legacy") == 0) {
7847
(void) fprintf(stderr, gettext("cannot unmount "
7848
"'%s': legacy mountpoint\n"),
7849
zfs_get_name(zhp));
7850
(void) fprintf(stderr, gettext("use umount(8) "
7851
"to unmount this filesystem\n"));
7852
} else {
7853
ret = zfs_unmountall(zhp, flags);
7854
}
7855
}
7856
7857
out:
7858
zfs_close(zhp);
7859
7860
return (ret != 0);
7861
}
7862
7863
/*
7864
* Generic callback for unsharing or unmounting a filesystem.
7865
*/
7866
static int
7867
unshare_unmount(int op, int argc, char **argv)
7868
{
7869
int do_all = 0;
7870
int flags = 0;
7871
int ret = 0;
7872
int c;
7873
zfs_handle_t *zhp;
7874
char nfs_mnt_prop[ZFS_MAXPROPLEN];
7875
char sharesmb[ZFS_MAXPROPLEN];
7876
7877
/* check options */
7878
while ((c = getopt(argc, argv, op == OP_SHARE ? ":a" : "afu")) != -1) {
7879
switch (c) {
7880
case 'a':
7881
do_all = 1;
7882
break;
7883
case 'f':
7884
flags |= MS_FORCE;
7885
break;
7886
case 'u':
7887
flags |= MS_CRYPT;
7888
break;
7889
case ':':
7890
(void) fprintf(stderr, gettext("missing argument for "
7891
"'%c' option\n"), optopt);
7892
usage(B_FALSE);
7893
break;
7894
case '?':
7895
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
7896
optopt);
7897
usage(B_FALSE);
7898
}
7899
}
7900
7901
argc -= optind;
7902
argv += optind;
7903
7904
if (do_all) {
7905
/*
7906
* We could make use of zfs_for_each() to walk all datasets in
7907
* the system, but this would be very inefficient, especially
7908
* since we would have to linearly search /proc/self/mounts for
7909
* each one. Instead, do one pass through /proc/self/mounts
7910
* looking for zfs entries and call zfs_unmount() for each one.
7911
*
7912
* Things get a little tricky if the administrator has created
7913
* mountpoints beneath other ZFS filesystems. In this case, we
7914
* have to unmount the deepest filesystems first. To accomplish
7915
* this, we place all the mountpoints in an AVL tree sorted by
7916
* the special type (dataset name), and walk the result in
7917
* reverse to make sure to get any snapshots first.
7918
*/
7919
FILE *mnttab;
7920
struct mnttab entry;
7921
uu_avl_pool_t *pool;
7922
uu_avl_t *tree = NULL;
7923
unshare_unmount_node_t *node;
7924
uu_avl_index_t idx;
7925
uu_avl_walk_t *walk;
7926
enum sa_protocol *protocol = NULL,
7927
single_protocol[] = {SA_NO_PROTOCOL, SA_NO_PROTOCOL};
7928
7929
if (op == OP_SHARE && argc > 0) {
7930
*single_protocol = sa_protocol_decode(argv[0]);
7931
protocol = single_protocol;
7932
argc--;
7933
argv++;
7934
}
7935
7936
if (argc != 0) {
7937
(void) fprintf(stderr, gettext("too many arguments\n"));
7938
usage(B_FALSE);
7939
}
7940
7941
if (((pool = uu_avl_pool_create("unmount_pool",
7942
sizeof (unshare_unmount_node_t),
7943
offsetof(unshare_unmount_node_t, un_avlnode),
7944
unshare_unmount_compare, UU_DEFAULT)) == NULL) ||
7945
((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL))
7946
nomem();
7947
7948
if ((mnttab = fopen(MNTTAB, "re")) == NULL) {
7949
uu_avl_destroy(tree);
7950
uu_avl_pool_destroy(pool);
7951
return (ENOENT);
7952
}
7953
7954
while (getmntent(mnttab, &entry) == 0) {
7955
7956
/* ignore non-ZFS entries */
7957
if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
7958
continue;
7959
7960
/* ignore snapshots */
7961
if (strchr(entry.mnt_special, '@') != NULL)
7962
continue;
7963
7964
if ((zhp = zfs_open(g_zfs, entry.mnt_special,
7965
ZFS_TYPE_FILESYSTEM)) == NULL) {
7966
ret = 1;
7967
continue;
7968
}
7969
7970
/*
7971
* Ignore datasets that are excluded/restricted by
7972
* parent pool name.
7973
*/
7974
if (zpool_skip_pool(zfs_get_pool_name(zhp))) {
7975
zfs_close(zhp);
7976
continue;
7977
}
7978
7979
switch (op) {
7980
case OP_SHARE:
7981
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
7982
nfs_mnt_prop,
7983
sizeof (nfs_mnt_prop),
7984
NULL, NULL, 0, B_FALSE) == 0);
7985
if (strcmp(nfs_mnt_prop, "off") != 0)
7986
break;
7987
verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
7988
nfs_mnt_prop,
7989
sizeof (nfs_mnt_prop),
7990
NULL, NULL, 0, B_FALSE) == 0);
7991
if (strcmp(nfs_mnt_prop, "off") == 0)
7992
continue;
7993
break;
7994
case OP_MOUNT:
7995
/* Ignore legacy mounts */
7996
verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
7997
nfs_mnt_prop,
7998
sizeof (nfs_mnt_prop),
7999
NULL, NULL, 0, B_FALSE) == 0);
8000
if (strcmp(nfs_mnt_prop, "legacy") == 0)
8001
continue;
8002
/* Ignore canmount=noauto mounts */
8003
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
8004
ZFS_CANMOUNT_NOAUTO)
8005
continue;
8006
break;
8007
default:
8008
break;
8009
}
8010
8011
node = safe_malloc(sizeof (unshare_unmount_node_t));
8012
node->un_zhp = zhp;
8013
node->un_mountp = safe_strdup(entry.mnt_mountp);
8014
8015
uu_avl_node_init(node, &node->un_avlnode, pool);
8016
8017
if (uu_avl_find(tree, node, NULL, &idx) == NULL) {
8018
uu_avl_insert(tree, node, idx);
8019
} else {
8020
zfs_close(node->un_zhp);
8021
free(node->un_mountp);
8022
free(node);
8023
}
8024
}
8025
(void) fclose(mnttab);
8026
8027
/*
8028
* Walk the AVL tree in reverse, unmounting each filesystem and
8029
* removing it from the AVL tree in the process.
8030
*/
8031
if ((walk = uu_avl_walk_start(tree,
8032
UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL)
8033
nomem();
8034
8035
while ((node = uu_avl_walk_next(walk)) != NULL) {
8036
const char *mntarg = NULL;
8037
8038
uu_avl_remove(tree, node);
8039
switch (op) {
8040
case OP_SHARE:
8041
if (zfs_unshare(node->un_zhp,
8042
node->un_mountp, protocol) != 0)
8043
ret = 1;
8044
break;
8045
8046
case OP_MOUNT:
8047
if (zfs_unmount(node->un_zhp,
8048
mntarg, flags) != 0)
8049
ret = 1;
8050
break;
8051
}
8052
8053
zfs_close(node->un_zhp);
8054
free(node->un_mountp);
8055
free(node);
8056
}
8057
8058
if (op == OP_SHARE)
8059
zfs_commit_shares(protocol);
8060
8061
uu_avl_walk_end(walk);
8062
uu_avl_destroy(tree);
8063
uu_avl_pool_destroy(pool);
8064
8065
} else {
8066
if (argc != 1) {
8067
if (argc == 0)
8068
(void) fprintf(stderr,
8069
gettext("missing filesystem argument\n"));
8070
else
8071
(void) fprintf(stderr,
8072
gettext("too many arguments\n"));
8073
usage(B_FALSE);
8074
}
8075
8076
/*
8077
* We have an argument, but it may be a full path or a ZFS
8078
* filesystem. Pass full paths off to unmount_path() (shared by
8079
* manual_unmount), otherwise open the filesystem and pass to
8080
* zfs_unmount().
8081
*/
8082
if (argv[0][0] == '/')
8083
return (unshare_unmount_path(op, argv[0],
8084
flags, B_FALSE));
8085
8086
if ((zhp = zfs_open(g_zfs, argv[0],
8087
ZFS_TYPE_FILESYSTEM)) == NULL)
8088
return (1);
8089
8090
verify(zfs_prop_get(zhp, op == OP_SHARE ?
8091
ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
8092
nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL,
8093
NULL, 0, B_FALSE) == 0);
8094
8095
switch (op) {
8096
case OP_SHARE:
8097
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
8098
nfs_mnt_prop,
8099
sizeof (nfs_mnt_prop),
8100
NULL, NULL, 0, B_FALSE) == 0);
8101
verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
8102
sharesmb, sizeof (sharesmb), NULL, NULL,
8103
0, B_FALSE) == 0);
8104
8105
if (strcmp(nfs_mnt_prop, "off") == 0 &&
8106
strcmp(sharesmb, "off") == 0) {
8107
(void) fprintf(stderr, gettext("cannot "
8108
"unshare '%s': legacy share\n"),
8109
zfs_get_name(zhp));
8110
(void) fprintf(stderr, gettext("use "
8111
"exports(5) or smb.conf(5) to unshare "
8112
"this filesystem\n"));
8113
ret = 1;
8114
} else if (!zfs_is_shared(zhp, NULL, NULL)) {
8115
(void) fprintf(stderr, gettext("cannot "
8116
"unshare '%s': not currently "
8117
"shared\n"), zfs_get_name(zhp));
8118
ret = 1;
8119
} else if (zfs_unshareall(zhp, NULL) != 0) {
8120
ret = 1;
8121
}
8122
break;
8123
8124
case OP_MOUNT:
8125
if (strcmp(nfs_mnt_prop, "legacy") == 0) {
8126
(void) fprintf(stderr, gettext("cannot "
8127
"unmount '%s': legacy "
8128
"mountpoint\n"), zfs_get_name(zhp));
8129
(void) fprintf(stderr, gettext("use "
8130
"umount(8) to unmount this "
8131
"filesystem\n"));
8132
ret = 1;
8133
} else if (!zfs_is_mounted(zhp, NULL)) {
8134
(void) fprintf(stderr, gettext("cannot "
8135
"unmount '%s': not currently "
8136
"mounted\n"),
8137
zfs_get_name(zhp));
8138
ret = 1;
8139
} else if (zfs_unmountall(zhp, flags) != 0) {
8140
ret = 1;
8141
}
8142
break;
8143
}
8144
8145
zfs_close(zhp);
8146
}
8147
8148
return (ret);
8149
}
8150
8151
/*
8152
* zfs unmount [-fu] -a
8153
* zfs unmount [-fu] filesystem
8154
*
8155
* Unmount all filesystems, or a specific ZFS filesystem.
8156
*/
8157
static int
8158
zfs_do_unmount(int argc, char **argv)
8159
{
8160
return (unshare_unmount(OP_MOUNT, argc, argv));
8161
}
8162
8163
/*
8164
* zfs unshare -a
8165
* zfs unshare filesystem
8166
*
8167
* Unshare all filesystems, or a specific ZFS filesystem.
8168
*/
8169
static int
8170
zfs_do_unshare(int argc, char **argv)
8171
{
8172
return (unshare_unmount(OP_SHARE, argc, argv));
8173
}
8174
8175
static int
8176
find_command_idx(const char *command, int *idx)
8177
{
8178
int i;
8179
8180
for (i = 0; i < NCOMMAND; i++) {
8181
if (command_table[i].name == NULL)
8182
continue;
8183
8184
if (strcmp(command, command_table[i].name) == 0) {
8185
*idx = i;
8186
return (0);
8187
}
8188
}
8189
return (1);
8190
}
8191
8192
static int
8193
zfs_do_diff(int argc, char **argv)
8194
{
8195
zfs_handle_t *zhp;
8196
int flags = 0;
8197
char *tosnap = NULL;
8198
char *fromsnap = NULL;
8199
char *atp, *copy;
8200
int err = 0;
8201
int c;
8202
struct sigaction sa;
8203
8204
while ((c = getopt(argc, argv, "FHth")) != -1) {
8205
switch (c) {
8206
case 'F':
8207
flags |= ZFS_DIFF_CLASSIFY;
8208
break;
8209
case 'H':
8210
flags |= ZFS_DIFF_PARSEABLE;
8211
break;
8212
case 't':
8213
flags |= ZFS_DIFF_TIMESTAMP;
8214
break;
8215
case 'h':
8216
flags |= ZFS_DIFF_NO_MANGLE;
8217
break;
8218
default:
8219
(void) fprintf(stderr,
8220
gettext("invalid option '%c'\n"), optopt);
8221
usage(B_FALSE);
8222
}
8223
}
8224
8225
argc -= optind;
8226
argv += optind;
8227
8228
if (argc < 1) {
8229
(void) fprintf(stderr,
8230
gettext("must provide at least one snapshot name\n"));
8231
usage(B_FALSE);
8232
}
8233
8234
if (argc > 2) {
8235
(void) fprintf(stderr, gettext("too many arguments\n"));
8236
usage(B_FALSE);
8237
}
8238
8239
fromsnap = argv[0];
8240
tosnap = (argc == 2) ? argv[1] : NULL;
8241
8242
copy = NULL;
8243
if (*fromsnap != '@')
8244
copy = strdup(fromsnap);
8245
else if (tosnap)
8246
copy = strdup(tosnap);
8247
if (copy == NULL)
8248
usage(B_FALSE);
8249
8250
if ((atp = strchr(copy, '@')) != NULL)
8251
*atp = '\0';
8252
8253
if ((zhp = zfs_open(g_zfs, copy, ZFS_TYPE_FILESYSTEM)) == NULL) {
8254
free(copy);
8255
return (1);
8256
}
8257
free(copy);
8258
8259
/*
8260
* Ignore SIGPIPE so that the library can give us
8261
* information on any failure
8262
*/
8263
if (sigemptyset(&sa.sa_mask) == -1) {
8264
err = errno;
8265
goto out;
8266
}
8267
sa.sa_flags = 0;
8268
sa.sa_handler = SIG_IGN;
8269
if (sigaction(SIGPIPE, &sa, NULL) == -1) {
8270
err = errno;
8271
goto out;
8272
}
8273
8274
err = zfs_show_diffs(zhp, STDOUT_FILENO, fromsnap, tosnap, flags);
8275
out:
8276
zfs_close(zhp);
8277
8278
return (err != 0);
8279
}
8280
8281
/*
8282
* zfs bookmark <fs@source>|<fs#source> <fs#bookmark>
8283
*
8284
* Creates a bookmark with the given name from the source snapshot
8285
* or creates a copy of an existing source bookmark.
8286
*/
8287
static int
8288
zfs_do_bookmark(int argc, char **argv)
8289
{
8290
char *source, *bookname;
8291
char expbuf[ZFS_MAX_DATASET_NAME_LEN];
8292
int source_type;
8293
nvlist_t *nvl;
8294
int ret = 0;
8295
int c;
8296
8297
/* check options */
8298
while ((c = getopt(argc, argv, "")) != -1) {
8299
switch (c) {
8300
case '?':
8301
(void) fprintf(stderr,
8302
gettext("invalid option '%c'\n"), optopt);
8303
goto usage;
8304
}
8305
}
8306
8307
argc -= optind;
8308
argv += optind;
8309
8310
/* check number of arguments */
8311
if (argc < 1) {
8312
(void) fprintf(stderr, gettext("missing source argument\n"));
8313
goto usage;
8314
}
8315
if (argc < 2) {
8316
(void) fprintf(stderr, gettext("missing bookmark argument\n"));
8317
goto usage;
8318
}
8319
8320
source = argv[0];
8321
bookname = argv[1];
8322
8323
if (strchr(source, '@') == NULL && strchr(source, '#') == NULL) {
8324
(void) fprintf(stderr,
8325
gettext("invalid source name '%s': "
8326
"must contain a '@' or '#'\n"), source);
8327
goto usage;
8328
}
8329
if (strchr(bookname, '#') == NULL) {
8330
(void) fprintf(stderr,
8331
gettext("invalid bookmark name '%s': "
8332
"must contain a '#'\n"), bookname);
8333
goto usage;
8334
}
8335
8336
/*
8337
* expand source or bookname to full path:
8338
* one of them may be specified as short name
8339
*/
8340
{
8341
char **expand;
8342
char *source_short, *bookname_short;
8343
source_short = strpbrk(source, "@#");
8344
bookname_short = strpbrk(bookname, "#");
8345
if (source_short == source &&
8346
bookname_short == bookname) {
8347
(void) fprintf(stderr, gettext(
8348
"either source or bookmark must be specified as "
8349
"full dataset paths"));
8350
goto usage;
8351
} else if (source_short != source &&
8352
bookname_short != bookname) {
8353
expand = NULL;
8354
} else if (source_short != source) {
8355
strlcpy(expbuf, source, sizeof (expbuf));
8356
expand = &bookname;
8357
} else if (bookname_short != bookname) {
8358
strlcpy(expbuf, bookname, sizeof (expbuf));
8359
expand = &source;
8360
} else {
8361
abort();
8362
}
8363
if (expand != NULL) {
8364
*strpbrk(expbuf, "@#") = '\0'; /* dataset name in buf */
8365
(void) strlcat(expbuf, *expand, sizeof (expbuf));
8366
*expand = expbuf;
8367
}
8368
}
8369
8370
/* determine source type */
8371
switch (*strpbrk(source, "@#")) {
8372
case '@': source_type = ZFS_TYPE_SNAPSHOT; break;
8373
case '#': source_type = ZFS_TYPE_BOOKMARK; break;
8374
default: abort();
8375
}
8376
8377
/* test the source exists */
8378
zfs_handle_t *zhp;
8379
zhp = zfs_open(g_zfs, source, source_type);
8380
if (zhp == NULL)
8381
goto usage;
8382
zfs_close(zhp);
8383
8384
nvl = fnvlist_alloc();
8385
fnvlist_add_string(nvl, bookname, source);
8386
ret = lzc_bookmark(nvl, NULL);
8387
fnvlist_free(nvl);
8388
8389
if (ret != 0) {
8390
const char *err_msg = NULL;
8391
char errbuf[1024];
8392
8393
(void) snprintf(errbuf, sizeof (errbuf),
8394
dgettext(TEXT_DOMAIN,
8395
"cannot create bookmark '%s'"), bookname);
8396
8397
switch (ret) {
8398
case EXDEV:
8399
err_msg = "bookmark is in a different pool";
8400
break;
8401
case ZFS_ERR_BOOKMARK_SOURCE_NOT_ANCESTOR:
8402
err_msg = "source is not an ancestor of the "
8403
"new bookmark's dataset";
8404
break;
8405
case EEXIST:
8406
err_msg = "bookmark exists";
8407
break;
8408
case EINVAL:
8409
err_msg = "invalid argument";
8410
break;
8411
case ENOTSUP:
8412
err_msg = "bookmark feature not enabled";
8413
break;
8414
case ENOSPC:
8415
err_msg = "out of space";
8416
break;
8417
case ENOENT:
8418
err_msg = "dataset does not exist";
8419
break;
8420
default:
8421
(void) zfs_standard_error(g_zfs, ret, errbuf);
8422
break;
8423
}
8424
if (err_msg != NULL) {
8425
(void) fprintf(stderr, "%s: %s\n", errbuf,
8426
dgettext(TEXT_DOMAIN, err_msg));
8427
}
8428
}
8429
8430
return (ret != 0);
8431
8432
usage:
8433
usage(B_FALSE);
8434
return (-1);
8435
}
8436
8437
static int
8438
zfs_do_channel_program(int argc, char **argv)
8439
{
8440
int ret, fd, c;
8441
size_t progsize, progread;
8442
nvlist_t *outnvl = NULL;
8443
uint64_t instrlimit = ZCP_DEFAULT_INSTRLIMIT;
8444
uint64_t memlimit = ZCP_DEFAULT_MEMLIMIT;
8445
boolean_t sync_flag = B_TRUE, json_output = B_FALSE;
8446
zpool_handle_t *zhp;
8447
8448
struct option long_options[] = {
8449
{"json", no_argument, NULL, 'j'},
8450
{0, 0, 0, 0}
8451
};
8452
8453
/* check options */
8454
while ((c = getopt_long(argc, argv, "nt:m:j", long_options,
8455
NULL)) != -1) {
8456
switch (c) {
8457
case 't':
8458
case 'm': {
8459
uint64_t arg;
8460
char *endp;
8461
8462
errno = 0;
8463
arg = strtoull(optarg, &endp, 0);
8464
if (errno != 0 || *endp != '\0') {
8465
(void) fprintf(stderr, gettext(
8466
"invalid argument "
8467
"'%s': expected integer\n"), optarg);
8468
goto usage;
8469
}
8470
8471
if (c == 't') {
8472
instrlimit = arg;
8473
} else {
8474
ASSERT3U(c, ==, 'm');
8475
memlimit = arg;
8476
}
8477
break;
8478
}
8479
case 'n': {
8480
sync_flag = B_FALSE;
8481
break;
8482
}
8483
case 'j': {
8484
json_output = B_TRUE;
8485
break;
8486
}
8487
case '?':
8488
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
8489
optopt);
8490
goto usage;
8491
}
8492
}
8493
8494
argc -= optind;
8495
argv += optind;
8496
8497
if (argc < 2) {
8498
(void) fprintf(stderr,
8499
gettext("invalid number of arguments\n"));
8500
goto usage;
8501
}
8502
8503
const char *poolname = argv[0];
8504
const char *filename = argv[1];
8505
if (strcmp(filename, "-") == 0) {
8506
fd = 0;
8507
filename = "standard input";
8508
} else if ((fd = open(filename, O_RDONLY)) < 0) {
8509
(void) fprintf(stderr, gettext("cannot open '%s': %s\n"),
8510
filename, strerror(errno));
8511
return (1);
8512
}
8513
8514
if ((zhp = zpool_open(g_zfs, poolname)) == NULL) {
8515
(void) fprintf(stderr, gettext("cannot open pool '%s'\n"),
8516
poolname);
8517
if (fd != 0)
8518
(void) close(fd);
8519
return (1);
8520
}
8521
zpool_close(zhp);
8522
8523
/*
8524
* Read in the channel program, expanding the program buffer as
8525
* necessary.
8526
*/
8527
progread = 0;
8528
progsize = 1024;
8529
char *progbuf = safe_malloc(progsize);
8530
do {
8531
ret = read(fd, progbuf + progread, progsize - progread);
8532
progread += ret;
8533
if (progread == progsize && ret > 0) {
8534
progsize *= 2;
8535
progbuf = safe_realloc(progbuf, progsize);
8536
}
8537
} while (ret > 0);
8538
8539
if (fd != 0)
8540
(void) close(fd);
8541
if (ret < 0) {
8542
free(progbuf);
8543
(void) fprintf(stderr,
8544
gettext("cannot read '%s': %s\n"),
8545
filename, strerror(errno));
8546
return (1);
8547
}
8548
progbuf[progread] = '\0';
8549
8550
/*
8551
* Any remaining arguments are passed as arguments to the lua script as
8552
* a string array:
8553
* {
8554
* "argv" -> [ "arg 1", ... "arg n" ],
8555
* }
8556
*/
8557
nvlist_t *argnvl = fnvlist_alloc();
8558
fnvlist_add_string_array(argnvl, ZCP_ARG_CLIARGV,
8559
(const char **)argv + 2, argc - 2);
8560
8561
if (sync_flag) {
8562
ret = lzc_channel_program(poolname, progbuf,
8563
instrlimit, memlimit, argnvl, &outnvl);
8564
} else {
8565
ret = lzc_channel_program_nosync(poolname, progbuf,
8566
instrlimit, memlimit, argnvl, &outnvl);
8567
}
8568
8569
if (ret != 0) {
8570
/*
8571
* On error, report the error message handed back by lua if one
8572
* exists. Otherwise, generate an appropriate error message,
8573
* falling back on strerror() for an unexpected return code.
8574
*/
8575
const char *errstring = NULL;
8576
const char *msg = gettext("Channel program execution failed");
8577
uint64_t instructions = 0;
8578
if (outnvl != NULL && nvlist_exists(outnvl, ZCP_RET_ERROR)) {
8579
const char *es = NULL;
8580
(void) nvlist_lookup_string(outnvl,
8581
ZCP_RET_ERROR, &es);
8582
if (es == NULL)
8583
errstring = strerror(ret);
8584
else
8585
errstring = es;
8586
if (ret == ETIME) {
8587
(void) nvlist_lookup_uint64(outnvl,
8588
ZCP_ARG_INSTRLIMIT, &instructions);
8589
}
8590
} else {
8591
switch (ret) {
8592
case EINVAL:
8593
errstring =
8594
"Invalid instruction or memory limit.";
8595
break;
8596
case ENOMEM:
8597
errstring = "Return value too large.";
8598
break;
8599
case ENOSPC:
8600
errstring = "Memory limit exhausted.";
8601
break;
8602
case ETIME:
8603
errstring = "Timed out.";
8604
break;
8605
case EPERM:
8606
errstring = "Permission denied. Channel "
8607
"programs must be run as root.";
8608
break;
8609
default:
8610
(void) zfs_standard_error(g_zfs, ret, msg);
8611
}
8612
}
8613
if (errstring != NULL)
8614
(void) fprintf(stderr, "%s:\n%s\n", msg, errstring);
8615
8616
if (ret == ETIME && instructions != 0)
8617
(void) fprintf(stderr,
8618
gettext("%llu Lua instructions\n"),
8619
(u_longlong_t)instructions);
8620
} else {
8621
if (json_output) {
8622
(void) nvlist_print_json(stdout, outnvl);
8623
} else if (nvlist_empty(outnvl)) {
8624
(void) fprintf(stdout, gettext("Channel program fully "
8625
"executed and did not produce output.\n"));
8626
} else {
8627
(void) fprintf(stdout, gettext("Channel program fully "
8628
"executed and produced output:\n"));
8629
dump_nvlist(outnvl, 4);
8630
}
8631
}
8632
8633
free(progbuf);
8634
fnvlist_free(outnvl);
8635
fnvlist_free(argnvl);
8636
return (ret != 0);
8637
8638
usage:
8639
usage(B_FALSE);
8640
return (-1);
8641
}
8642
8643
8644
typedef struct loadkey_cbdata {
8645
boolean_t cb_loadkey;
8646
boolean_t cb_recursive;
8647
boolean_t cb_noop;
8648
char *cb_keylocation;
8649
uint64_t cb_numfailed;
8650
uint64_t cb_numattempted;
8651
} loadkey_cbdata_t;
8652
8653
static int
8654
load_key_callback(zfs_handle_t *zhp, void *data)
8655
{
8656
int ret;
8657
boolean_t is_encroot;
8658
loadkey_cbdata_t *cb = data;
8659
uint64_t keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);
8660
8661
/*
8662
* If we are working recursively, we want to skip loading / unloading
8663
* keys for non-encryption roots and datasets whose keys are already
8664
* in the desired end-state.
8665
*/
8666
if (cb->cb_recursive) {
8667
ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL);
8668
if (ret != 0)
8669
return (ret);
8670
if (!is_encroot)
8671
return (0);
8672
8673
if ((cb->cb_loadkey && keystatus == ZFS_KEYSTATUS_AVAILABLE) ||
8674
(!cb->cb_loadkey && keystatus == ZFS_KEYSTATUS_UNAVAILABLE))
8675
return (0);
8676
}
8677
8678
cb->cb_numattempted++;
8679
8680
if (cb->cb_loadkey)
8681
ret = zfs_crypto_load_key(zhp, cb->cb_noop, cb->cb_keylocation);
8682
else
8683
ret = zfs_crypto_unload_key(zhp);
8684
8685
if (ret != 0) {
8686
cb->cb_numfailed++;
8687
return (ret);
8688
}
8689
8690
return (0);
8691
}
8692
8693
static int
8694
load_unload_keys(int argc, char **argv, boolean_t loadkey)
8695
{
8696
int c, ret = 0, flags = 0;
8697
boolean_t do_all = B_FALSE;
8698
loadkey_cbdata_t cb = { 0 };
8699
8700
cb.cb_loadkey = loadkey;
8701
8702
while ((c = getopt(argc, argv, "anrL:")) != -1) {
8703
/* noop and alternate keylocations only apply to zfs load-key */
8704
if (loadkey) {
8705
switch (c) {
8706
case 'n':
8707
cb.cb_noop = B_TRUE;
8708
continue;
8709
case 'L':
8710
cb.cb_keylocation = optarg;
8711
continue;
8712
default:
8713
break;
8714
}
8715
}
8716
8717
switch (c) {
8718
case 'a':
8719
do_all = B_TRUE;
8720
cb.cb_recursive = B_TRUE;
8721
break;
8722
case 'r':
8723
flags |= ZFS_ITER_RECURSE;
8724
cb.cb_recursive = B_TRUE;
8725
break;
8726
default:
8727
(void) fprintf(stderr,
8728
gettext("invalid option '%c'\n"), optopt);
8729
usage(B_FALSE);
8730
}
8731
}
8732
8733
argc -= optind;
8734
argv += optind;
8735
8736
if (!do_all && argc == 0) {
8737
(void) fprintf(stderr,
8738
gettext("Missing dataset argument or -a option\n"));
8739
usage(B_FALSE);
8740
}
8741
8742
if (do_all && argc != 0) {
8743
(void) fprintf(stderr,
8744
gettext("Cannot specify dataset with -a option\n"));
8745
usage(B_FALSE);
8746
}
8747
8748
if (cb.cb_recursive && cb.cb_keylocation != NULL &&
8749
strcmp(cb.cb_keylocation, "prompt") != 0) {
8750
(void) fprintf(stderr, gettext("alternate keylocation may only "
8751
"be 'prompt' with -r or -a\n"));
8752
usage(B_FALSE);
8753
}
8754
8755
ret = zfs_for_each(argc, argv, flags,
8756
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, NULL, NULL, 0,
8757
load_key_callback, &cb);
8758
8759
if (cb.cb_noop || (cb.cb_recursive && cb.cb_numattempted != 0)) {
8760
(void) printf(gettext("%llu / %llu key(s) successfully %s\n"),
8761
(u_longlong_t)(cb.cb_numattempted - cb.cb_numfailed),
8762
(u_longlong_t)cb.cb_numattempted,
8763
loadkey ? (cb.cb_noop ? "verified" : "loaded") :
8764
"unloaded");
8765
}
8766
8767
if (cb.cb_numfailed != 0)
8768
ret = -1;
8769
8770
return (ret);
8771
}
8772
8773
static int
8774
zfs_do_load_key(int argc, char **argv)
8775
{
8776
return (load_unload_keys(argc, argv, B_TRUE));
8777
}
8778
8779
8780
static int
8781
zfs_do_unload_key(int argc, char **argv)
8782
{
8783
return (load_unload_keys(argc, argv, B_FALSE));
8784
}
8785
8786
static int
8787
zfs_do_change_key(int argc, char **argv)
8788
{
8789
int c, ret;
8790
uint64_t keystatus;
8791
boolean_t loadkey = B_FALSE, inheritkey = B_FALSE;
8792
zfs_handle_t *zhp = NULL;
8793
nvlist_t *props = fnvlist_alloc();
8794
8795
while ((c = getopt(argc, argv, "lio:")) != -1) {
8796
switch (c) {
8797
case 'l':
8798
loadkey = B_TRUE;
8799
break;
8800
case 'i':
8801
inheritkey = B_TRUE;
8802
break;
8803
case 'o':
8804
if (!parseprop(props, optarg)) {
8805
nvlist_free(props);
8806
return (1);
8807
}
8808
break;
8809
default:
8810
(void) fprintf(stderr,
8811
gettext("invalid option '%c'\n"), optopt);
8812
usage(B_FALSE);
8813
}
8814
}
8815
8816
if (inheritkey && !nvlist_empty(props)) {
8817
(void) fprintf(stderr,
8818
gettext("Properties not allowed for inheriting\n"));
8819
usage(B_FALSE);
8820
}
8821
8822
argc -= optind;
8823
argv += optind;
8824
8825
if (argc < 1) {
8826
(void) fprintf(stderr, gettext("Missing dataset argument\n"));
8827
usage(B_FALSE);
8828
}
8829
8830
if (argc > 1) {
8831
(void) fprintf(stderr, gettext("Too many arguments\n"));
8832
usage(B_FALSE);
8833
}
8834
8835
zhp = zfs_open(g_zfs, argv[argc - 1],
8836
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
8837
if (zhp == NULL)
8838
usage(B_FALSE);
8839
8840
if (loadkey) {
8841
keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);
8842
if (keystatus != ZFS_KEYSTATUS_AVAILABLE) {
8843
ret = zfs_crypto_load_key(zhp, B_FALSE, NULL);
8844
if (ret != 0) {
8845
nvlist_free(props);
8846
zfs_close(zhp);
8847
return (-1);
8848
}
8849
}
8850
8851
/* refresh the properties so the new keystatus is visible */
8852
zfs_refresh_properties(zhp);
8853
}
8854
8855
ret = zfs_crypto_rewrap(zhp, props, inheritkey);
8856
if (ret != 0) {
8857
nvlist_free(props);
8858
zfs_close(zhp);
8859
return (-1);
8860
}
8861
8862
nvlist_free(props);
8863
zfs_close(zhp);
8864
return (0);
8865
}
8866
8867
/*
8868
* 1) zfs project [-d|-r] <file|directory ...>
8869
* List project ID and inherit flag of file(s) or directories.
8870
* -d: List the directory itself, not its children.
8871
* -r: List subdirectories recursively.
8872
*
8873
* 2) zfs project -C [-k] [-r] <file|directory ...>
8874
* Clear project inherit flag and/or ID on the file(s) or directories.
8875
* -k: Keep the project ID unchanged. If not specified, the project ID
8876
* will be reset as zero.
8877
* -r: Clear on subdirectories recursively.
8878
*
8879
* 3) zfs project -c [-0] [-d|-r] [-p id] <file|directory ...>
8880
* Check project ID and inherit flag on the file(s) or directories,
8881
* report the outliers.
8882
* -0: Print file name followed by a NUL instead of newline.
8883
* -d: Check the directory itself, not its children.
8884
* -p: Specify the referenced ID for comparing with the target file(s)
8885
* or directories' project IDs. If not specified, the target (top)
8886
* directory's project ID will be used as the referenced one.
8887
* -r: Check subdirectories recursively.
8888
*
8889
* 4) zfs project [-p id] [-r] [-s] <file|directory ...>
8890
* Set project ID and/or inherit flag on the file(s) or directories.
8891
* -p: Set the project ID as the given id.
8892
* -r: Set on subdirectories recursively. If not specify "-p" option,
8893
* it will use top-level directory's project ID as the given id,
8894
* then set both project ID and inherit flag on all descendants
8895
* of the top-level directory.
8896
* -s: Set project inherit flag.
8897
*/
8898
static int
8899
zfs_do_project(int argc, char **argv)
8900
{
8901
zfs_project_control_t zpc = {
8902
.zpc_expected_projid = ZFS_INVALID_PROJID,
8903
.zpc_op = ZFS_PROJECT_OP_DEFAULT,
8904
.zpc_dironly = B_FALSE,
8905
.zpc_keep_projid = B_FALSE,
8906
.zpc_newline = B_TRUE,
8907
.zpc_recursive = B_FALSE,
8908
.zpc_set_flag = B_FALSE,
8909
};
8910
int ret = 0, c;
8911
8912
if (argc < 2)
8913
usage(B_FALSE);
8914
8915
while ((c = getopt(argc, argv, "0Ccdkp:rs")) != -1) {
8916
switch (c) {
8917
case '0':
8918
zpc.zpc_newline = B_FALSE;
8919
break;
8920
case 'C':
8921
if (zpc.zpc_op != ZFS_PROJECT_OP_DEFAULT) {
8922
(void) fprintf(stderr, gettext("cannot "
8923
"specify '-C' '-c' '-s' together\n"));
8924
usage(B_FALSE);
8925
}
8926
8927
zpc.zpc_op = ZFS_PROJECT_OP_CLEAR;
8928
break;
8929
case 'c':
8930
if (zpc.zpc_op != ZFS_PROJECT_OP_DEFAULT) {
8931
(void) fprintf(stderr, gettext("cannot "
8932
"specify '-C' '-c' '-s' together\n"));
8933
usage(B_FALSE);
8934
}
8935
8936
zpc.zpc_op = ZFS_PROJECT_OP_CHECK;
8937
break;
8938
case 'd':
8939
zpc.zpc_dironly = B_TRUE;
8940
/* overwrite "-r" option */
8941
zpc.zpc_recursive = B_FALSE;
8942
break;
8943
case 'k':
8944
zpc.zpc_keep_projid = B_TRUE;
8945
break;
8946
case 'p': {
8947
char *endptr;
8948
8949
errno = 0;
8950
zpc.zpc_expected_projid = strtoull(optarg, &endptr, 0);
8951
if (errno != 0 || *endptr != '\0') {
8952
(void) fprintf(stderr,
8953
gettext("project ID must be less than "
8954
"%u\n"), UINT32_MAX);
8955
usage(B_FALSE);
8956
}
8957
if (zpc.zpc_expected_projid >= UINT32_MAX) {
8958
(void) fprintf(stderr,
8959
gettext("invalid project ID\n"));
8960
usage(B_FALSE);
8961
}
8962
break;
8963
}
8964
case 'r':
8965
zpc.zpc_recursive = B_TRUE;
8966
/* overwrite "-d" option */
8967
zpc.zpc_dironly = B_FALSE;
8968
break;
8969
case 's':
8970
if (zpc.zpc_op != ZFS_PROJECT_OP_DEFAULT) {
8971
(void) fprintf(stderr, gettext("cannot "
8972
"specify '-C' '-c' '-s' together\n"));
8973
usage(B_FALSE);
8974
}
8975
8976
zpc.zpc_set_flag = B_TRUE;
8977
zpc.zpc_op = ZFS_PROJECT_OP_SET;
8978
break;
8979
default:
8980
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
8981
optopt);
8982
usage(B_FALSE);
8983
}
8984
}
8985
8986
if (zpc.zpc_op == ZFS_PROJECT_OP_DEFAULT) {
8987
if (zpc.zpc_expected_projid != ZFS_INVALID_PROJID)
8988
zpc.zpc_op = ZFS_PROJECT_OP_SET;
8989
else
8990
zpc.zpc_op = ZFS_PROJECT_OP_LIST;
8991
}
8992
8993
switch (zpc.zpc_op) {
8994
case ZFS_PROJECT_OP_LIST:
8995
if (zpc.zpc_keep_projid) {
8996
(void) fprintf(stderr,
8997
gettext("'-k' is only valid together with '-C'\n"));
8998
usage(B_FALSE);
8999
}
9000
if (!zpc.zpc_newline) {
9001
(void) fprintf(stderr,
9002
gettext("'-0' is only valid together with '-c'\n"));
9003
usage(B_FALSE);
9004
}
9005
break;
9006
case ZFS_PROJECT_OP_CHECK:
9007
if (zpc.zpc_keep_projid) {
9008
(void) fprintf(stderr,
9009
gettext("'-k' is only valid together with '-C'\n"));
9010
usage(B_FALSE);
9011
}
9012
break;
9013
case ZFS_PROJECT_OP_CLEAR:
9014
if (zpc.zpc_dironly) {
9015
(void) fprintf(stderr,
9016
gettext("'-d' is useless together with '-C'\n"));
9017
usage(B_FALSE);
9018
}
9019
if (!zpc.zpc_newline) {
9020
(void) fprintf(stderr,
9021
gettext("'-0' is only valid together with '-c'\n"));
9022
usage(B_FALSE);
9023
}
9024
if (zpc.zpc_expected_projid != ZFS_INVALID_PROJID) {
9025
(void) fprintf(stderr,
9026
gettext("'-p' is useless together with '-C'\n"));
9027
usage(B_FALSE);
9028
}
9029
break;
9030
case ZFS_PROJECT_OP_SET:
9031
if (zpc.zpc_dironly) {
9032
(void) fprintf(stderr,
9033
gettext("'-d' is useless for set project ID and/or "
9034
"inherit flag\n"));
9035
usage(B_FALSE);
9036
}
9037
if (zpc.zpc_keep_projid) {
9038
(void) fprintf(stderr,
9039
gettext("'-k' is only valid together with '-C'\n"));
9040
usage(B_FALSE);
9041
}
9042
if (!zpc.zpc_newline) {
9043
(void) fprintf(stderr,
9044
gettext("'-0' is only valid together with '-c'\n"));
9045
usage(B_FALSE);
9046
}
9047
break;
9048
default:
9049
ASSERT(0);
9050
break;
9051
}
9052
9053
argv += optind;
9054
argc -= optind;
9055
if (argc == 0) {
9056
(void) fprintf(stderr,
9057
gettext("missing file or directory target(s)\n"));
9058
usage(B_FALSE);
9059
}
9060
9061
for (int i = 0; i < argc; i++) {
9062
int err;
9063
9064
err = zfs_project_handle(argv[i], &zpc);
9065
if (err && !ret)
9066
ret = err;
9067
}
9068
9069
return (ret);
9070
}
9071
9072
static int
9073
zfs_rewrite_file(const char *path, boolean_t verbose, zfs_rewrite_args_t *args)
9074
{
9075
int fd, ret = 0;
9076
9077
fd = open(path, O_WRONLY);
9078
if (fd < 0) {
9079
ret = errno;
9080
(void) fprintf(stderr, gettext("failed to open %s: %s\n"),
9081
path, strerror(errno));
9082
return (ret);
9083
}
9084
9085
if (ioctl(fd, ZFS_IOC_REWRITE, args) < 0) {
9086
ret = errno;
9087
(void) fprintf(stderr, gettext("failed to rewrite %s: %s\n"),
9088
path, strerror(errno));
9089
} else if (verbose) {
9090
printf("%s\n", path);
9091
}
9092
9093
close(fd);
9094
return (ret);
9095
}
9096
9097
static int
9098
zfs_rewrite_dir(const char *path, boolean_t verbose, boolean_t xdev, dev_t dev,
9099
zfs_rewrite_args_t *args, nvlist_t *dirs)
9100
{
9101
struct dirent *ent;
9102
DIR *dir;
9103
int ret = 0, err;
9104
9105
dir = opendir(path);
9106
if (dir == NULL) {
9107
if (errno == ENOENT)
9108
return (0);
9109
ret = errno;
9110
(void) fprintf(stderr, gettext("failed to opendir %s: %s\n"),
9111
path, strerror(errno));
9112
return (ret);
9113
}
9114
9115
size_t plen = strlen(path) + 1;
9116
while ((ent = readdir(dir)) != NULL) {
9117
char *fullname;
9118
struct stat st;
9119
9120
if (ent->d_type != DT_REG && ent->d_type != DT_DIR)
9121
continue;
9122
9123
if (strcmp(ent->d_name, ".") == 0 ||
9124
strcmp(ent->d_name, "..") == 0)
9125
continue;
9126
9127
if (plen + strlen(ent->d_name) >= PATH_MAX) {
9128
(void) fprintf(stderr, gettext("path too long %s/%s\n"),
9129
path, ent->d_name);
9130
ret = ENAMETOOLONG;
9131
continue;
9132
}
9133
9134
if (asprintf(&fullname, "%s/%s", path, ent->d_name) == -1) {
9135
(void) fprintf(stderr,
9136
gettext("failed to allocate memory\n"));
9137
ret = ENOMEM;
9138
continue;
9139
}
9140
9141
if (xdev) {
9142
if (lstat(fullname, &st) < 0) {
9143
ret = errno;
9144
(void) fprintf(stderr,
9145
gettext("failed to stat %s: %s\n"),
9146
fullname, strerror(errno));
9147
free(fullname);
9148
continue;
9149
}
9150
if (st.st_dev != dev) {
9151
free(fullname);
9152
continue;
9153
}
9154
}
9155
9156
if (ent->d_type == DT_REG) {
9157
err = zfs_rewrite_file(fullname, verbose, args);
9158
if (err)
9159
ret = err;
9160
} else { /* DT_DIR */
9161
fnvlist_add_uint64(dirs, fullname, dev);
9162
}
9163
9164
free(fullname);
9165
}
9166
9167
closedir(dir);
9168
return (ret);
9169
}
9170
9171
static int
9172
zfs_rewrite_path(const char *path, boolean_t verbose, boolean_t recurse,
9173
boolean_t xdev, zfs_rewrite_args_t *args, nvlist_t *dirs)
9174
{
9175
struct stat st;
9176
int ret = 0;
9177
9178
if (lstat(path, &st) < 0) {
9179
ret = errno;
9180
(void) fprintf(stderr, gettext("failed to stat %s: %s\n"),
9181
path, strerror(errno));
9182
return (ret);
9183
}
9184
9185
if (S_ISREG(st.st_mode)) {
9186
ret = zfs_rewrite_file(path, verbose, args);
9187
} else if (S_ISDIR(st.st_mode) && recurse) {
9188
ret = zfs_rewrite_dir(path, verbose, xdev, st.st_dev, args,
9189
dirs);
9190
}
9191
return (ret);
9192
}
9193
9194
static int
9195
zfs_do_rewrite(int argc, char **argv)
9196
{
9197
int ret = 0, err, c;
9198
boolean_t recurse = B_FALSE, verbose = B_FALSE, xdev = B_FALSE;
9199
9200
if (argc < 2)
9201
usage(B_FALSE);
9202
9203
zfs_rewrite_args_t args;
9204
memset(&args, 0, sizeof (args));
9205
9206
while ((c = getopt(argc, argv, "Pl:o:rvx")) != -1) {
9207
switch (c) {
9208
case 'P':
9209
args.flags |= ZFS_REWRITE_PHYSICAL;
9210
break;
9211
case 'l':
9212
args.len = strtoll(optarg, NULL, 0);
9213
break;
9214
case 'o':
9215
args.off = strtoll(optarg, NULL, 0);
9216
break;
9217
case 'r':
9218
recurse = B_TRUE;
9219
break;
9220
case 'v':
9221
verbose = B_TRUE;
9222
break;
9223
case 'x':
9224
xdev = B_TRUE;
9225
break;
9226
default:
9227
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
9228
optopt);
9229
usage(B_FALSE);
9230
}
9231
}
9232
9233
argv += optind;
9234
argc -= optind;
9235
if (argc == 0) {
9236
(void) fprintf(stderr,
9237
gettext("missing file or directory target(s)\n"));
9238
usage(B_FALSE);
9239
}
9240
9241
nvlist_t *dirs = fnvlist_alloc();
9242
for (int i = 0; i < argc; i++) {
9243
err = zfs_rewrite_path(argv[i], verbose, recurse, xdev, &args,
9244
dirs);
9245
if (err)
9246
ret = err;
9247
}
9248
nvpair_t *dir;
9249
while ((dir = nvlist_next_nvpair(dirs, NULL)) != NULL) {
9250
err = zfs_rewrite_dir(nvpair_name(dir), verbose, xdev,
9251
fnvpair_value_uint64(dir), &args, dirs);
9252
if (err)
9253
ret = err;
9254
fnvlist_remove_nvpair(dirs, dir);
9255
}
9256
fnvlist_free(dirs);
9257
9258
return (ret);
9259
}
9260
9261
static int
9262
zfs_do_wait(int argc, char **argv)
9263
{
9264
boolean_t enabled[ZFS_WAIT_NUM_ACTIVITIES];
9265
int error = 0, i;
9266
int c;
9267
9268
/* By default, wait for all types of activity. */
9269
for (i = 0; i < ZFS_WAIT_NUM_ACTIVITIES; i++)
9270
enabled[i] = B_TRUE;
9271
9272
while ((c = getopt(argc, argv, "t:")) != -1) {
9273
switch (c) {
9274
case 't':
9275
/* Reset activities array */
9276
memset(&enabled, 0, sizeof (enabled));
9277
9278
for (char *tok; (tok = strsep(&optarg, ",")); ) {
9279
static const char *const col_subopts[
9280
ZFS_WAIT_NUM_ACTIVITIES] = { "deleteq" };
9281
9282
for (i = 0; i < ARRAY_SIZE(col_subopts); ++i)
9283
if (strcmp(tok, col_subopts[i]) == 0) {
9284
enabled[i] = B_TRUE;
9285
goto found;
9286
}
9287
9288
(void) fprintf(stderr,
9289
gettext("invalid activity '%s'\n"), tok);
9290
usage(B_FALSE);
9291
found:;
9292
}
9293
break;
9294
case '?':
9295
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
9296
optopt);
9297
usage(B_FALSE);
9298
}
9299
}
9300
9301
argv += optind;
9302
argc -= optind;
9303
if (argc < 1) {
9304
(void) fprintf(stderr, gettext("missing 'filesystem' "
9305
"argument\n"));
9306
usage(B_FALSE);
9307
}
9308
if (argc > 1) {
9309
(void) fprintf(stderr, gettext("too many arguments\n"));
9310
usage(B_FALSE);
9311
}
9312
9313
zfs_handle_t *zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM);
9314
if (zhp == NULL)
9315
return (1);
9316
9317
for (;;) {
9318
boolean_t missing = B_FALSE;
9319
boolean_t any_waited = B_FALSE;
9320
9321
for (int i = 0; i < ZFS_WAIT_NUM_ACTIVITIES; i++) {
9322
boolean_t waited;
9323
9324
if (!enabled[i])
9325
continue;
9326
9327
error = zfs_wait_status(zhp, i, &missing, &waited);
9328
if (error != 0 || missing)
9329
break;
9330
9331
any_waited = (any_waited || waited);
9332
}
9333
9334
if (error != 0 || missing || !any_waited)
9335
break;
9336
}
9337
9338
zfs_close(zhp);
9339
9340
return (error);
9341
}
9342
9343
/*
9344
* Display version message
9345
*/
9346
static int
9347
zfs_do_version(int argc, char **argv)
9348
{
9349
int c;
9350
nvlist_t *jsobj = NULL, *zfs_ver = NULL;
9351
boolean_t json = B_FALSE;
9352
9353
struct option long_options[] = {
9354
{"json", no_argument, NULL, 'j'},
9355
{0, 0, 0, 0}
9356
};
9357
9358
while ((c = getopt_long(argc, argv, "j", long_options, NULL)) != -1) {
9359
switch (c) {
9360
case 'j':
9361
json = B_TRUE;
9362
jsobj = zfs_json_schema(0, 1);
9363
break;
9364
case '?':
9365
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
9366
optopt);
9367
usage(B_FALSE);
9368
}
9369
}
9370
9371
argc -= optind;
9372
if (argc != 0) {
9373
(void) fprintf(stderr, "too many arguments\n");
9374
usage(B_FALSE);
9375
}
9376
9377
if (json) {
9378
zfs_ver = zfs_version_nvlist();
9379
if (zfs_ver) {
9380
fnvlist_add_nvlist(jsobj, "zfs_version", zfs_ver);
9381
zcmd_print_json(jsobj);
9382
fnvlist_free(zfs_ver);
9383
return (0);
9384
} else
9385
return (-1);
9386
} else
9387
return (zfs_version_print() != 0);
9388
}
9389
9390
/* Display documentation */
9391
static int
9392
zfs_do_help(int argc, char **argv)
9393
{
9394
char page[MAXNAMELEN];
9395
if (argc < 3 || strcmp(argv[2], "zfs") == 0)
9396
strcpy(page, "zfs");
9397
else if (strcmp(argv[2], "concepts") == 0 ||
9398
strcmp(argv[2], "props") == 0)
9399
snprintf(page, sizeof (page), "zfs%s", argv[2]);
9400
else
9401
snprintf(page, sizeof (page), "zfs-%s", argv[2]);
9402
9403
execlp("man", "man", page, NULL);
9404
9405
fprintf(stderr, "couldn't run man program: %s", strerror(errno));
9406
return (-1);
9407
}
9408
9409
int
9410
main(int argc, char **argv)
9411
{
9412
int ret = 0;
9413
int i = 0;
9414
const char *cmdname;
9415
char **newargv;
9416
9417
(void) setlocale(LC_ALL, "");
9418
(void) setlocale(LC_NUMERIC, "C");
9419
(void) textdomain(TEXT_DOMAIN);
9420
9421
opterr = 0;
9422
9423
/*
9424
* Make sure the user has specified some command.
9425
*/
9426
if (argc < 2) {
9427
(void) fprintf(stderr, gettext("missing command\n"));
9428
usage(B_FALSE);
9429
}
9430
9431
cmdname = argv[1];
9432
9433
/*
9434
* The 'umount' command is an alias for 'unmount'
9435
*/
9436
if (strcmp(cmdname, "umount") == 0)
9437
cmdname = "unmount";
9438
9439
/*
9440
* The 'recv' command is an alias for 'receive'
9441
*/
9442
if (strcmp(cmdname, "recv") == 0)
9443
cmdname = "receive";
9444
9445
/*
9446
* The 'snap' command is an alias for 'snapshot'
9447
*/
9448
if (strcmp(cmdname, "snap") == 0)
9449
cmdname = "snapshot";
9450
9451
/*
9452
* Special case '-?'
9453
*/
9454
if ((strcmp(cmdname, "-?") == 0) ||
9455
(strcmp(cmdname, "--help") == 0))
9456
usage(B_TRUE);
9457
9458
/*
9459
* Special case '-V|--version'
9460
*/
9461
if ((strcmp(cmdname, "-V") == 0) || (strcmp(cmdname, "--version") == 0))
9462
return (zfs_version_print() != 0);
9463
9464
/*
9465
* Special case 'help'
9466
*/
9467
if (strcmp(cmdname, "help") == 0)
9468
return (zfs_do_help(argc, argv));
9469
9470
if ((g_zfs = libzfs_init()) == NULL) {
9471
(void) fprintf(stderr, "%s\n", libzfs_error_init(errno));
9472
return (1);
9473
}
9474
9475
zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
9476
9477
libzfs_print_on_error(g_zfs, B_TRUE);
9478
9479
zfs_setproctitle_init(argc, argv, environ);
9480
9481
/*
9482
* Many commands modify input strings for string parsing reasons.
9483
* We create a copy to protect the original argv.
9484
*/
9485
newargv = safe_malloc((argc + 1) * sizeof (newargv[0]));
9486
for (i = 0; i < argc; i++)
9487
newargv[i] = strdup(argv[i]);
9488
newargv[argc] = NULL;
9489
9490
/*
9491
* Run the appropriate command.
9492
*/
9493
libzfs_mnttab_cache(g_zfs, B_TRUE);
9494
if (find_command_idx(cmdname, &i) == 0) {
9495
current_command = &command_table[i];
9496
ret = command_table[i].func(argc - 1, newargv + 1);
9497
} else if (strchr(cmdname, '=') != NULL) {
9498
verify(find_command_idx("set", &i) == 0);
9499
current_command = &command_table[i];
9500
ret = command_table[i].func(argc, newargv);
9501
} else {
9502
(void) fprintf(stderr, gettext("unrecognized "
9503
"command '%s'\n"), cmdname);
9504
usage(B_FALSE);
9505
ret = 1;
9506
}
9507
9508
for (i = 0; i < argc; i++)
9509
free(newargv[i]);
9510
free(newargv);
9511
9512
if (ret == 0 && log_history)
9513
(void) zpool_log_history(g_zfs, history_str);
9514
9515
libzfs_fini(g_zfs);
9516
9517
/*
9518
* The 'ZFS_ABORT' environment variable causes us to dump core on exit
9519
* for the purposes of running ::findleaks.
9520
*/
9521
if (getenv("ZFS_ABORT") != NULL) {
9522
(void) printf("dumping core by request\n");
9523
abort();
9524
}
9525
9526
return (ret);
9527
}
9528
9529
/*
9530
* zfs zone nsfile filesystem
9531
*
9532
* Add or delete the given dataset to/from the namespace.
9533
*/
9534
#ifdef __linux__
9535
static int
9536
zfs_do_zone_impl(int argc, char **argv, boolean_t attach)
9537
{
9538
zfs_handle_t *zhp;
9539
int ret;
9540
9541
if (argc < 3) {
9542
(void) fprintf(stderr, gettext("missing argument(s)\n"));
9543
usage(B_FALSE);
9544
}
9545
if (argc > 3) {
9546
(void) fprintf(stderr, gettext("too many arguments\n"));
9547
usage(B_FALSE);
9548
}
9549
9550
zhp = zfs_open(g_zfs, argv[2], ZFS_TYPE_FILESYSTEM);
9551
if (zhp == NULL)
9552
return (1);
9553
9554
ret = (zfs_userns(zhp, argv[1], attach) != 0);
9555
9556
zfs_close(zhp);
9557
return (ret);
9558
}
9559
9560
static int
9561
zfs_do_zone(int argc, char **argv)
9562
{
9563
return (zfs_do_zone_impl(argc, argv, B_TRUE));
9564
}
9565
9566
static int
9567
zfs_do_unzone(int argc, char **argv)
9568
{
9569
return (zfs_do_zone_impl(argc, argv, B_FALSE));
9570
}
9571
#endif
9572
9573
#ifdef __FreeBSD__
9574
#include <sys/jail.h>
9575
#include <jail.h>
9576
/*
9577
* Attach/detach the given dataset to/from the given jail
9578
*/
9579
static int
9580
zfs_do_jail_impl(int argc, char **argv, boolean_t attach)
9581
{
9582
zfs_handle_t *zhp;
9583
int jailid, ret;
9584
9585
/* check number of arguments */
9586
if (argc < 3) {
9587
(void) fprintf(stderr, gettext("missing argument(s)\n"));
9588
usage(B_FALSE);
9589
}
9590
if (argc > 3) {
9591
(void) fprintf(stderr, gettext("too many arguments\n"));
9592
usage(B_FALSE);
9593
}
9594
9595
jailid = jail_getid(argv[1]);
9596
if (jailid < 0) {
9597
(void) fprintf(stderr, gettext("invalid jail id or name\n"));
9598
usage(B_FALSE);
9599
}
9600
9601
zhp = zfs_open(g_zfs, argv[2], ZFS_TYPE_FILESYSTEM);
9602
if (zhp == NULL)
9603
return (1);
9604
9605
ret = (zfs_jail(zhp, jailid, attach) != 0);
9606
9607
zfs_close(zhp);
9608
return (ret);
9609
}
9610
9611
/*
9612
* zfs jail jailid filesystem
9613
*
9614
* Attach the given dataset to the given jail
9615
*/
9616
static int
9617
zfs_do_jail(int argc, char **argv)
9618
{
9619
return (zfs_do_jail_impl(argc, argv, B_TRUE));
9620
}
9621
9622
/*
9623
* zfs unjail jailid filesystem
9624
*
9625
* Detach the given dataset from the given jail
9626
*/
9627
static int
9628
zfs_do_unjail(int argc, char **argv)
9629
{
9630
return (zfs_do_jail_impl(argc, argv, B_FALSE));
9631
}
9632
#endif
9633
9634