Print this page
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/dfs.cmds/sharemgr/commands.c
+++ new/usr/src/cmd/dfs.cmds/sharemgr/commands.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 + */
26 +
27 +/*
25 28 * Copyright 2012 Milan Jurik. All rights reserved.
29 + * Copyright 2018 Nexenta Systems, Inc.
26 30 */
27 31
28 32 #include <sys/types.h>
29 33 #include <sys/stat.h>
30 34 #include <fcntl.h>
31 35 #include <stdlib.h>
32 36 #include <stdio.h>
33 37 #include <string.h>
34 38 #include <ctype.h>
35 39 #include <unistd.h>
36 40 #include <getopt.h>
37 41 #include <utmpx.h>
38 42 #include <pwd.h>
39 43 #include <auth_attr.h>
40 44 #include <secdb.h>
41 45 #include <sys/param.h>
42 46 #include <sys/stat.h>
43 47 #include <errno.h>
44 48
45 49 #include <libshare.h>
46 50 #include "sharemgr.h"
47 51 #include <libscf.h>
48 52 #include <libxml/tree.h>
49 53 #include <libintl.h>
50 54 #include <assert.h>
51 55 #include <iconv.h>
52 56 #include <langinfo.h>
53 57 #include <dirent.h>
54 58
55 59 static char *sa_get_usage(sa_usage_t);
56 60
57 61 /*
58 62 * Implementation of the common sub-commands supported by sharemgr.
59 63 * A number of helper functions are also included.
60 64 */
61 65
62 66 /*
63 67 * has_protocol(group, proto)
64 68 * If the group has an optionset with the specified protocol,
65 69 * return true (1) otherwise false (0).
66 70 */
67 71 static int
68 72 has_protocol(sa_group_t group, char *protocol)
69 73 {
70 74 sa_optionset_t optionset;
71 75 int result = 0;
72 76
73 77 optionset = sa_get_optionset(group, protocol);
74 78 if (optionset != NULL) {
75 79 result++;
76 80 }
77 81 return (result);
78 82 }
79 83
80 84 /*
81 85 * validresource(name)
82 86 *
83 87 * Check that name only has valid characters in it. The current valid
84 88 * set are the printable characters but not including:
85 89 * " / \ [ ] : | < > + ; , ? * = \t
86 90 * Note that space is included and there is a maximum length.
87 91 */
88 92 static int
89 93 validresource(const char *name)
90 94 {
91 95 const char *cp;
92 96 size_t len;
93 97
94 98 if (name == NULL)
95 99 return (B_FALSE);
96 100
97 101 len = strlen(name);
98 102 if (len == 0 || len > SA_MAX_RESOURCE_NAME)
99 103 return (B_FALSE);
100 104
101 105 if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
102 106 return (B_FALSE);
103 107 }
104 108
105 109 for (cp = name; *cp != '\0'; cp++)
106 110 if (iscntrl(*cp))
107 111 return (B_FALSE);
108 112
109 113 return (B_TRUE);
110 114 }
111 115
112 116 /*
113 117 * conv_to_utf8(input)
114 118 *
115 119 * Convert the input string to utf8 from the current locale. If the
116 120 * conversion fails, use the current locale, it is likely close
117 121 * enough. For example, the "C" locale is a subset of utf-8. The
118 122 * return value may be a new string or the original input string.
119 123 */
120 124
121 125 static char *
122 126 conv_to_utf8(char *input)
123 127 {
124 128 iconv_t cd;
125 129 char *inval = input;
126 130 char *output = input;
127 131 char *outleft;
128 132 char *curlocale;
129 133 size_t bytesleft;
130 134 size_t size;
131 135 size_t osize;
132 136 static int warned = 0;
133 137
134 138 curlocale = nl_langinfo(CODESET);
135 139 if (curlocale == NULL)
136 140 curlocale = "C";
137 141 cd = iconv_open("UTF-8", curlocale);
138 142 if (cd != NULL && cd != (iconv_t)-1) {
139 143 size = strlen(input);
140 144 /* Assume worst case of characters expanding to 4 bytes. */
141 145 bytesleft = size * 4;
142 146 output = calloc(bytesleft, 1);
143 147 if (output != NULL) {
144 148 outleft = output;
145 149 /* inval can be modified on return */
146 150 osize = iconv(cd, (const char **)&inval, &size,
147 151 &outleft, &bytesleft);
148 152 if (osize == (size_t)-1 || size != 0) {
149 153 free(output);
150 154 output = input;
151 155 }
152 156 } else {
153 157 /* Need to return something. */
154 158 output = input;
155 159 }
156 160 (void) iconv_close(cd);
157 161 } else {
158 162 if (!warned)
159 163 (void) fprintf(stderr,
160 164 gettext("Cannot convert to UTF-8 from %s\n"),
161 165 curlocale ? curlocale : gettext("unknown"));
162 166 warned = 1;
163 167 }
164 168 return (output);
165 169 }
166 170
167 171 /*
168 172 * conv_from(input)
169 173 *
170 174 * Convert the input string from utf8 to current locale. If the
171 175 * conversion isn't supported, just use as is. The return value may be
172 176 * a new string or the original input string.
173 177 */
174 178
175 179 static char *
176 180 conv_from_utf8(char *input)
177 181 {
178 182 iconv_t cd;
179 183 char *output = input;
180 184 char *inval = input;
181 185 char *outleft;
182 186 char *curlocale;
183 187 size_t bytesleft;
184 188 size_t size;
185 189 size_t osize;
186 190 static int warned = 0;
187 191
188 192 curlocale = nl_langinfo(CODESET);
189 193 if (curlocale == NULL)
190 194 curlocale = "C";
191 195 cd = iconv_open(curlocale, "UTF-8");
192 196 if (cd != NULL && cd != (iconv_t)-1) {
193 197 size = strlen(input);
194 198 /* Assume worst case of characters expanding to 4 bytes. */
195 199 bytesleft = size * 4;
196 200 output = calloc(bytesleft, 1);
197 201 if (output != NULL) {
198 202 outleft = output;
199 203 osize = iconv(cd, (const char **)&inval, &size,
200 204 &outleft, &bytesleft);
201 205 if (osize == (size_t)-1 || size != 0)
202 206 output = input;
203 207 } else {
204 208 /* Need to return something. */
205 209 output = input;
206 210 }
207 211 (void) iconv_close(cd);
208 212 } else {
209 213 if (!warned)
210 214 (void) fprintf(stderr,
211 215 gettext("Cannot convert to %s from UTF-8\n"),
212 216 curlocale ? curlocale : gettext("unknown"));
213 217 warned = 1;
214 218 }
215 219 return (output);
216 220 }
217 221
218 222 /*
219 223 * print_rsrc_desc(resource, sharedesc)
220 224 *
221 225 * Print the resource description string after converting from UTF8 to
222 226 * the current locale. If sharedesc is not NULL and there is no
223 227 * description on the resource, use sharedesc. sharedesc will already
224 228 * be converted to UTF8.
225 229 */
226 230
227 231 static void
228 232 print_rsrc_desc(sa_resource_t resource, char *sharedesc)
229 233 {
230 234 char *description;
231 235 char *desc;
232 236
233 237 if (resource == NULL)
234 238 return;
235 239
236 240 description = sa_get_resource_description(resource);
237 241 if (description != NULL) {
238 242 desc = conv_from_utf8(description);
239 243 if (desc != description) {
240 244 sa_free_share_description(description);
241 245 description = desc;
242 246 }
243 247 } else if (sharedesc != NULL) {
244 248 description = strdup(sharedesc);
245 249 }
246 250 if (description != NULL) {
247 251 (void) printf("\t\"%s\"", description);
248 252 sa_free_share_description(description);
249 253 }
250 254 }
251 255
252 256 /*
253 257 * set_resource_desc(share, description)
254 258 *
255 259 * Set the share description value after converting the description
256 260 * string to UTF8 from the current locale.
257 261 */
258 262
259 263 static int
260 264 set_resource_desc(sa_share_t share, char *description)
261 265 {
262 266 char *desc;
263 267 int ret;
264 268
265 269 desc = conv_to_utf8(description);
266 270 ret = sa_set_resource_description(share, desc);
267 271 if (description != desc)
268 272 sa_free_share_description(desc);
269 273 return (ret);
270 274 }
271 275
272 276 /*
273 277 * set_share_desc(share, description)
274 278 *
275 279 * Set the resource description value after converting the description
276 280 * string to UTF8 from the current locale.
277 281 */
278 282
279 283 static int
280 284 set_share_desc(sa_share_t share, char *description)
281 285 {
282 286 char *desc;
283 287 int ret;
284 288
285 289 desc = conv_to_utf8(description);
286 290 ret = sa_set_share_description(share, desc);
287 291 if (description != desc)
288 292 sa_free_share_description(desc);
289 293 return (ret);
290 294 }
291 295
292 296 /*
293 297 * add_list(list, item, data, proto)
294 298 * Adds a new list member that points holds item in the list.
295 299 * If list is NULL, it starts a new list. The function returns
296 300 * the first member of the list.
297 301 */
298 302 struct list *
299 303 add_list(struct list *listp, void *item, void *data, char *proto)
300 304 {
301 305 struct list *new, *tmp;
302 306
303 307 new = malloc(sizeof (struct list));
304 308 if (new != NULL) {
305 309 new->next = NULL;
306 310 new->item = item;
307 311 new->itemdata = data;
308 312 new->proto = proto;
309 313 } else {
310 314 return (listp);
311 315 }
312 316
313 317 if (listp == NULL)
314 318 return (new);
315 319
316 320 for (tmp = listp; tmp->next != NULL; tmp = tmp->next) {
317 321 /* get to end of list */
318 322 }
319 323 tmp->next = new;
320 324 return (listp);
321 325 }
322 326
323 327 /*
324 328 * free_list(list)
325 329 * Given a list, free all the members of the list;
326 330 */
327 331 static void
328 332 free_list(struct list *listp)
329 333 {
330 334 struct list *tmp;
331 335 while (listp != NULL) {
332 336 tmp = listp;
333 337 listp = listp->next;
334 338 free(tmp);
335 339 }
336 340 }
337 341
338 342 /*
339 343 * check_authorization(instname, which)
340 344 *
341 345 * Checks to see if the specific type of authorization in which is
342 346 * enabled for the user in this SMF service instance.
343 347 */
344 348
345 349 static int
346 350 check_authorization(char *instname, int which)
347 351 {
348 352 scf_handle_t *handle = NULL;
349 353 scf_simple_prop_t *prop = NULL;
350 354 char svcstring[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
351 355 char *authstr = NULL;
352 356 ssize_t numauths;
353 357 int ret = B_TRUE;
354 358 uid_t uid;
355 359 struct passwd *pw = NULL;
356 360
357 361 uid = getuid();
358 362 pw = getpwuid(uid);
359 363 if (pw == NULL) {
360 364 ret = B_FALSE;
361 365 } else {
362 366 /*
363 367 * Since names are restricted to SA_MAX_NAME_LEN won't
364 368 * overflow.
365 369 */
366 370 (void) snprintf(svcstring, sizeof (svcstring), "%s:%s",
367 371 SA_SVC_FMRI_BASE, instname);
368 372 handle = scf_handle_create(SCF_VERSION);
369 373 if (handle != NULL) {
370 374 if (scf_handle_bind(handle) == 0) {
371 375 switch (which) {
372 376 case SVC_SET:
373 377 prop = scf_simple_prop_get(handle,
374 378 svcstring, "general",
375 379 SVC_AUTH_VALUE);
376 380 break;
377 381 case SVC_ACTION:
378 382 prop = scf_simple_prop_get(handle,
379 383 svcstring, "general",
380 384 SVC_AUTH_ACTION);
381 385 break;
382 386 }
383 387 }
384 388 }
385 389 }
386 390 /* make sure we have an authorization string property */
387 391 if (prop != NULL) {
388 392 int i;
389 393 numauths = scf_simple_prop_numvalues(prop);
390 394 for (ret = 0, i = 0; i < numauths; i++) {
391 395 authstr = scf_simple_prop_next_astring(prop);
392 396 if (authstr != NULL) {
393 397 /* check if this user has one of the strings */
394 398 if (chkauthattr(authstr, pw->pw_name)) {
395 399 ret = 1;
396 400 break;
397 401 }
398 402 }
399 403 }
400 404 endauthattr();
401 405 scf_simple_prop_free(prop);
402 406 } else {
403 407 /* no authorization string defined */
404 408 ret = 0;
405 409 }
406 410 if (handle != NULL)
407 411 scf_handle_destroy(handle);
408 412 return (ret);
409 413 }
410 414
411 415 /*
412 416 * check_authorizations(instname, flags)
413 417 *
414 418 * check all the needed authorizations for the user in this service
415 419 * instance. Return value of 1(true) or 0(false) indicates whether
416 420 * there are authorizations for the user or not.
417 421 */
418 422
419 423 static int
420 424 check_authorizations(char *instname, int flags)
421 425 {
422 426 int ret1 = 0;
423 427 int ret2 = 0;
424 428 int ret;
425 429
426 430 if (flags & SVC_SET)
427 431 ret1 = check_authorization(instname, SVC_SET);
428 432 if (flags & SVC_ACTION)
429 433 ret2 = check_authorization(instname, SVC_ACTION);
430 434 switch (flags) {
431 435 case SVC_ACTION:
432 436 ret = ret2;
433 437 break;
434 438 case SVC_SET:
435 439 ret = ret1;
436 440 break;
437 441 case SVC_ACTION|SVC_SET:
438 442 ret = ret1 & ret2;
439 443 break;
440 444 default:
441 445 /* if not flags set, we assume we don't need authorizations */
442 446 ret = 1;
443 447 }
444 448 return (ret);
445 449 }
446 450
447 451 /*
448 452 * notify_or_enable_share(share, protocol)
449 453 *
450 454 * Since some protocols don't want an "enable" when properties change,
451 455 * this function will use the protocol specific notify function
452 456 * first. If that fails, it will then attempt to use the
453 457 * sa_enable_share(). "protocol" is the protocol that was specified
454 458 * on the command line.
455 459 */
456 460 static void
457 461 notify_or_enable_share(sa_share_t share, char *protocol)
458 462 {
459 463 sa_group_t group;
460 464 sa_optionset_t opt;
461 465 int ret = SA_OK;
462 466 char *path;
463 467 char *groupproto;
464 468 sa_share_t parent = share;
465 469
466 470 /* If really a resource, get parent share */
467 471 if (!sa_is_share(share)) {
468 472 parent = sa_get_resource_parent((sa_resource_t)share);
469 473 }
470 474
471 475 /*
472 476 * Now that we've got a share in "parent", make sure it has a path.
473 477 */
474 478 path = sa_get_share_attr(parent, "path");
475 479 if (path == NULL)
476 480 return;
477 481
478 482 group = sa_get_parent_group(parent);
479 483
480 484 if (group == NULL) {
481 485 sa_free_attr_string(path);
482 486 return;
483 487 }
484 488 for (opt = sa_get_optionset(group, NULL);
485 489 opt != NULL;
486 490 opt = sa_get_next_optionset(opt)) {
487 491 groupproto = sa_get_optionset_attr(opt, "type");
488 492 if (groupproto == NULL ||
489 493 (protocol != NULL && strcmp(groupproto, protocol) != 0)) {
490 494 if (groupproto != NULL)
491 495 sa_free_attr_string(groupproto);
492 496 continue;
493 497 }
494 498 if (sa_is_share(share)) {
495 499 if ((ret = sa_proto_change_notify(share,
496 500 groupproto)) != SA_OK) {
497 501 ret = sa_enable_share(share, groupproto);
498 502 if (ret != SA_OK) {
499 503 (void) printf(
500 504 gettext("Could not reenable"
501 505 " share %s: %s\n"),
502 506 path, sa_errorstr(ret));
503 507 }
504 508 }
505 509 } else {
506 510 /* Must be a resource */
507 511 if ((ret = sa_proto_notify_resource(share,
508 512 groupproto)) != SA_OK) {
509 513 ret = sa_enable_resource(share, groupproto);
510 514 if (ret != SA_OK) {
511 515 (void) printf(
512 516 gettext("Could not "
513 517 "reenable resource %s: "
514 518 "%s\n"), path,
515 519 sa_errorstr(ret));
516 520 }
517 521 }
518 522 }
519 523 sa_free_attr_string(groupproto);
520 524 }
521 525 sa_free_attr_string(path);
522 526 }
523 527
524 528 /*
525 529 * enable_group(group, updateproto, notify, proto)
526 530 *
527 531 * enable all the shares in the specified group. This is a helper for
528 532 * enable_all_groups in order to simplify regular and subgroup (zfs)
529 533 * enabling. Group has already been checked for non-NULL. If notify
530 534 * is non-zero, attempt to use the notify interface rather than
531 535 * enable.
532 536 */
533 537 static void
534 538 enable_group(sa_group_t group, char *updateproto, int notify, char *proto)
535 539 {
536 540 sa_share_t share;
537 541
538 542 /* If the protocol isn't enabled for this group skip it */
539 543 if (!has_protocol(group, proto))
540 544 return;
541 545
542 546 for (share = sa_get_share(group, NULL);
543 547 share != NULL;
544 548 share = sa_get_next_share(share)) {
545 549 if (updateproto != NULL)
546 550 (void) sa_update_legacy(share, updateproto);
547 551 if (notify)
548 552 notify_or_enable_share(share, proto);
549 553 else
550 554 (void) sa_enable_share(share, proto);
551 555 }
552 556 }
553 557
554 558 /*
555 559 * isenabled(group)
556 560 *
557 561 * Returns B_TRUE if the group is enabled or B_FALSE if it isn't.
558 562 * Moved to separate function to reduce clutter in the code.
559 563 */
560 564
561 565 static int
562 566 isenabled(sa_group_t group)
563 567 {
564 568 char *state;
565 569 int ret = B_FALSE;
566 570
567 571 if (group != NULL) {
568 572 state = sa_get_group_attr(group, "state");
569 573 if (state != NULL) {
570 574
571 575 if (strcmp(state, "enabled") == 0)
572 576 ret = B_TRUE;
573 577 sa_free_attr_string(state);
574 578 }
575 579 }
576 580 return (ret);
577 581 }
578 582
579 583 /*
580 584 * enable_all_groups(list, setstate, online, updateproto)
581 585 *
582 586 * Given a list of groups, enable each one found. If updateproto is
583 587 * not NULL, then update all the shares for the protocol that was
584 588 * passed in. If enable is non-zero, tell enable_group to try the
585 589 * notify interface since this is a property change.
586 590 */
587 591 static int
588 592 enable_all_groups(sa_handle_t handle, struct list *work, int setstate,
589 593 int online, char *updateproto, int enable)
590 594 {
591 595 int ret;
592 596 char instance[SA_MAX_NAME_LEN + sizeof (SA_SVC_FMRI_BASE) + 1];
593 597 char *state;
594 598 char *name;
595 599 char *zfs = NULL;
596 600 sa_group_t group;
597 601 sa_group_t subgroup;
598 602
599 603 for (ret = SA_OK; work != NULL; work = work->next) {
600 604 group = (sa_group_t)work->item;
601 605
602 606 /*
603 607 * If setstate == TRUE, then make sure to set
604 608 * enabled. This needs to be done here in order for
605 609 * the isenabled check to succeed on a newly enabled
606 610 * group.
607 611 */
608 612 if (setstate == B_TRUE) {
609 613 ret = sa_set_group_attr(group, "state", "enabled");
610 614 if (ret != SA_OK)
611 615 break;
612 616 }
613 617
614 618 /*
615 619 * Check to see if group is enabled. If it isn't, skip
616 620 * the rest. We don't want shares starting if the
617 621 * group is disabled. The properties may have been
618 622 * updated, but there won't be a change until the
619 623 * group is enabled.
620 624 */
621 625 if (!isenabled(group))
622 626 continue;
623 627
624 628 /* if itemdata != NULL then a single share */
625 629 if (work->itemdata != NULL) {
626 630 if (enable) {
627 631 if (work->itemdata != NULL)
628 632 notify_or_enable_share(work->itemdata,
629 633 updateproto);
630 634 else
631 635 ret = SA_CONFIG_ERR;
632 636 } else {
633 637 if (sa_is_share(work->itemdata)) {
634 638 ret = sa_enable_share(
635 639 (sa_share_t)work->itemdata,
636 640 updateproto);
637 641 } else {
638 642 ret = sa_enable_resource(
639 643 (sa_resource_t)work->itemdata,
640 644 updateproto);
641 645 }
642 646 }
643 647 }
644 648 if (ret != SA_OK)
645 649 break;
646 650
647 651 /* if itemdata == NULL then the whole group */
648 652 if (work->itemdata == NULL) {
649 653 zfs = sa_get_group_attr(group, "zfs");
650 654 /*
651 655 * If the share is managed by ZFS, don't
652 656 * update any of the protocols since ZFS is
653 657 * handling this. Updateproto will contain
654 658 * the name of the protocol that we want to
655 659 * update legacy files for.
656 660 */
657 661 enable_group(group, zfs == NULL ? updateproto : NULL,
658 662 enable, work->proto);
659 663 if (zfs != NULL)
660 664 sa_free_attr_string(zfs);
661 665
662 666 for (subgroup = sa_get_sub_group(group);
663 667 subgroup != NULL;
664 668 subgroup = sa_get_next_group(subgroup)) {
665 669 /* never update legacy for ZFS subgroups */
666 670 enable_group(subgroup, NULL, enable,
667 671 work->proto);
668 672 }
669 673 }
670 674 if (online) {
671 675 zfs = sa_get_group_attr(group, "zfs");
672 676 name = sa_get_group_attr(group, "name");
673 677 if (name != NULL) {
674 678 if (zfs == NULL) {
675 679 (void) snprintf(instance,
676 680 sizeof (instance), "%s:%s",
677 681 SA_SVC_FMRI_BASE, name);
678 682 state = smf_get_state(instance);
679 683 if (state == NULL ||
680 684 strcmp(state, "online") != 0) {
681 685 (void) smf_enable_instance(
682 686 instance, 0);
683 687 free(state);
684 688 }
685 689 } else {
686 690 sa_free_attr_string(zfs);
687 691 zfs = NULL;
688 692 }
689 693 if (name != NULL)
690 694 sa_free_attr_string(name);
691 695 }
692 696 }
693 697 }
694 698 if (ret == SA_OK) {
695 699 ret = sa_update_config(handle);
696 700 }
697 701 return (ret);
698 702 }
699 703
700 704 /*
701 705 * chk_opt(optlistp, security, proto)
702 706 *
703 707 * Do a sanity check on the optlist provided for the protocol. This
704 708 * is a syntax check and verification that the property is either a
705 709 * general or specific to a names optionset.
706 710 */
707 711
708 712 static int
709 713 chk_opt(struct options *optlistp, int security, char *proto)
710 714 {
711 715 struct options *optlist;
712 716 char *sep = "";
713 717 int notfirst = 0;
714 718 int ret;
715 719
716 720 for (optlist = optlistp; optlist != NULL; optlist = optlist->next) {
717 721 char *optname;
718 722
719 723 optname = optlist->optname;
720 724 ret = OPT_ADD_OK;
721 725 /* extract property/value pair */
722 726 if (sa_is_security(optname, proto)) {
723 727 if (!security)
724 728 ret = OPT_ADD_SECURITY;
725 729 } else {
726 730 if (security)
727 731 ret = OPT_ADD_PROPERTY;
728 732 }
729 733 if (ret != OPT_ADD_OK) {
730 734 if (notfirst == 0)
731 735 (void) printf(
732 736 gettext("Property syntax error: "));
733 737 switch (ret) {
734 738 case OPT_ADD_SYNTAX:
735 739 (void) printf(gettext("%ssyntax error: %s"),
736 740 sep, optname);
737 741 sep = ", ";
738 742 break;
739 743 case OPT_ADD_SECURITY:
740 744 (void) printf(gettext("%s%s requires -S"),
741 745 optname, sep);
742 746 sep = ", ";
743 747 break;
744 748 case OPT_ADD_PROPERTY:
745 749 (void) printf(
746 750 gettext("%s%s not supported with -S"),
747 751 optname, sep);
748 752 sep = ", ";
749 753 break;
750 754 }
751 755 notfirst++;
752 756 }
753 757 }
754 758 if (notfirst) {
755 759 (void) printf("\n");
756 760 ret = SA_SYNTAX_ERR;
757 761 }
758 762 return (ret);
759 763 }
760 764
761 765 /*
762 766 * free_opt(optlist)
763 767 * Free the specified option list.
764 768 */
765 769 static void
766 770 free_opt(struct options *optlist)
767 771 {
768 772 struct options *nextopt;
769 773 while (optlist != NULL) {
770 774 nextopt = optlist->next;
771 775 free(optlist);
772 776 optlist = nextopt;
773 777 }
774 778 }
775 779
776 780 /*
777 781 * check property list for valid properties
778 782 * A null value is a remove which is always valid.
779 783 */
780 784 static int
781 785 valid_options(sa_handle_t handle, struct options *optlist, char *proto,
782 786 void *object, char *sec)
783 787 {
784 788 int ret = SA_OK;
785 789 struct options *cur;
786 790 sa_property_t prop;
787 791 sa_optionset_t parent = NULL;
788 792
789 793 if (object != NULL) {
790 794 if (sec == NULL)
791 795 parent = sa_get_optionset(object, proto);
792 796 else
793 797 parent = sa_get_security(object, sec, proto);
794 798 }
795 799
796 800 for (cur = optlist; cur != NULL; cur = cur->next) {
797 801 if (cur->optvalue == NULL)
798 802 continue;
799 803 prop = sa_create_property(cur->optname, cur->optvalue);
800 804 if (prop == NULL)
801 805 ret = SA_NO_MEMORY;
802 806 if (ret != SA_OK ||
803 807 (ret = sa_valid_property(handle, parent, proto, prop)) !=
804 808 SA_OK) {
805 809 (void) printf(
806 810 gettext("Could not add property %s: %s\n"),
807 811 cur->optname, sa_errorstr(ret));
808 812 }
809 813 (void) sa_remove_property(prop);
810 814 }
811 815 return (ret);
812 816 }
813 817
814 818 /*
815 819 * add_optionset(group, optlist, protocol, *err)
816 820 * Add the options in optlist to an optionset and then add the optionset
817 821 * to the group.
818 822 *
819 823 * The return value indicates if there was a "change" while errors are
820 824 * returned via the *err parameters.
821 825 */
822 826 static int
823 827 add_optionset(sa_group_t group, struct options *optlist, char *proto, int *err)
824 828 {
825 829 sa_optionset_t optionset;
826 830 int ret = SA_OK;
827 831 int result = B_FALSE;
828 832 sa_handle_t handle;
829 833
830 834 optionset = sa_get_optionset(group, proto);
831 835 if (optionset == NULL) {
832 836 optionset = sa_create_optionset(group, proto);
833 837 if (optionset == NULL)
834 838 ret = SA_NO_MEMORY;
835 839 result = B_TRUE; /* adding a protocol is a change */
836 840 }
837 841 if (optionset == NULL) {
838 842 ret = SA_NO_MEMORY;
839 843 goto out;
840 844 }
841 845 handle = sa_find_group_handle(group);
842 846 if (handle == NULL) {
843 847 ret = SA_CONFIG_ERR;
844 848 goto out;
845 849 }
846 850 while (optlist != NULL) {
847 851 sa_property_t prop;
848 852 prop = sa_get_property(optionset, optlist->optname);
849 853 if (prop == NULL) {
850 854 /*
851 855 * add the property, but only if it is
852 856 * a non-NULL or non-zero length value
853 857 */
854 858 if (optlist->optvalue != NULL) {
855 859 prop = sa_create_property(optlist->optname,
856 860 optlist->optvalue);
857 861 if (prop != NULL) {
858 862 ret = sa_valid_property(handle,
859 863 optionset, proto, prop);
860 864 if (ret != SA_OK) {
861 865 (void) sa_remove_property(prop);
862 866 (void) printf(gettext("Could "
863 867 "not add property "
864 868 "%s: %s\n"),
865 869 optlist->optname,
866 870 sa_errorstr(ret));
867 871 }
868 872 }
869 873 if (ret == SA_OK) {
870 874 ret = sa_add_property(optionset, prop);
871 875 if (ret != SA_OK) {
872 876 (void) printf(gettext(
873 877 "Could not add property "
874 878 "%s: %s\n"),
875 879 optlist->optname,
876 880 sa_errorstr(ret));
877 881 } else {
878 882 /* there was a change */
879 883 result = B_TRUE;
880 884 }
881 885 }
882 886 }
883 887 } else {
884 888 ret = sa_update_property(prop, optlist->optvalue);
885 889 /* should check to see if value changed */
886 890 if (ret != SA_OK) {
887 891 (void) printf(gettext("Could not update "
888 892 "property %s: %s\n"), optlist->optname,
889 893 sa_errorstr(ret));
890 894 } else {
891 895 result = B_TRUE;
892 896 }
893 897 }
894 898 optlist = optlist->next;
895 899 }
896 900 ret = sa_commit_properties(optionset, 0);
897 901
898 902 out:
899 903 if (err != NULL)
900 904 *err = ret;
901 905 return (result);
902 906 }
903 907
904 908 /*
905 909 * resource_compliant(group)
906 910 *
907 911 * Go through all the shares in the group. Assume compliant, but if
908 912 * any share doesn't have at least one resource name, it isn't
909 913 * compliant.
910 914 */
911 915 static int
912 916 resource_compliant(sa_group_t group)
913 917 {
914 918 sa_share_t share;
915 919
916 920 for (share = sa_get_share(group, NULL); share != NULL;
917 921 share = sa_get_next_share(share)) {
918 922 if (sa_get_share_resource(share, NULL) == NULL) {
919 923 return (B_FALSE);
920 924 }
921 925 }
922 926 return (B_TRUE);
923 927 }
924 928
925 929 /*
926 930 * fix_path(path)
927 931 *
928 932 * change all illegal characters to something else. For now, all get
929 933 * converted to '_' and the leading '/' is stripped off. This is used
930 934 * to construct an resource name (SMB share name) that is valid.
931 935 * Caller must pass a valid path.
932 936 */
933 937 static void
934 938 fix_path(char *path)
935 939 {
936 940 char *cp;
937 941 size_t len;
938 942
939 943 assert(path != NULL);
940 944
941 945 /* make sure we are appropriate length */
942 946 cp = path + 1; /* skip leading slash */
943 947 while (cp != NULL && strlen(cp) > SA_MAX_RESOURCE_NAME) {
944 948 cp = strchr(cp, '/');
945 949 if (cp != NULL)
946 950 cp++;
947 951 }
948 952 /* two cases - cp == NULL and cp is substring of path */
949 953 if (cp == NULL) {
950 954 /* just take last SA_MAX_RESOURCE_NAME chars */
951 955 len = 1 + strlen(path) - SA_MAX_RESOURCE_NAME;
952 956 (void) memmove(path, path + len, SA_MAX_RESOURCE_NAME);
953 957 path[SA_MAX_RESOURCE_NAME] = '\0';
954 958 } else {
955 959 len = strlen(cp) + 1;
956 960 (void) memmove(path, cp, len);
957 961 }
958 962
959 963 /*
960 964 * Don't want any of the characters that are not allowed
961 965 * in and SMB share name. Replace them with '_'.
962 966 */
963 967 while (*path) {
964 968 switch (*path) {
965 969 case '/':
966 970 case '"':
967 971 case '\\':
968 972 case '[':
969 973 case ']':
970 974 case ':':
971 975 case '|':
972 976 case '<':
973 977 case '>':
974 978 case '+':
975 979 case ';':
976 980 case ',':
977 981 case '?':
978 982 case '*':
979 983 case '=':
980 984 case '\t':
981 985 *path = '_';
982 986 break;
983 987 }
984 988 path++;
985 989 }
986 990 }
987 991
988 992 /*
989 993 * name_adjust(path, count)
990 994 *
991 995 * Add a ~<count> in place of last few characters. The total number of
992 996 * characters is dependent on count.
993 997 */
994 998 #define MAX_MANGLE_NUMBER 10000
995 999
996 1000 static int
997 1001 name_adjust(char *path, int count)
998 1002 {
999 1003 size_t len;
1000 1004
1001 1005 len = strlen(path) - 2;
1002 1006 if (count > 10)
1003 1007 len--;
1004 1008 if (count > 100)
1005 1009 len--;
1006 1010 if (count > 1000)
1007 1011 len--;
1008 1012 if (len > 0)
1009 1013 (void) sprintf(path + len, "~%d", count);
1010 1014 else
1011 1015 return (SA_BAD_VALUE);
1012 1016
1013 1017 return (SA_OK);
1014 1018 }
1015 1019
1016 1020 /*
1017 1021 * make_resources(group)
1018 1022 *
1019 1023 * Go through all the shares in the group and make them have resource
1020 1024 * names.
1021 1025 */
1022 1026 static void
1023 1027 make_resources(sa_group_t group)
1024 1028 {
1025 1029 sa_share_t share;
1026 1030 int count;
1027 1031 int err = SA_OK;
1028 1032
1029 1033 for (share = sa_get_share(group, NULL); share != NULL;
1030 1034 share = sa_get_next_share(share)) {
1031 1035 /* Skip those with resources */
1032 1036 if (sa_get_share_resource(share, NULL) == NULL) {
1033 1037 char *path;
1034 1038 path = sa_get_share_attr(share, "path");
1035 1039 if (path == NULL)
1036 1040 continue;
1037 1041 fix_path(path);
1038 1042 count = 0; /* reset for next resource */
1039 1043 while (sa_add_resource(share, path,
1040 1044 SA_SHARE_PERMANENT, &err) == NULL &&
1041 1045 err == SA_DUPLICATE_NAME) {
1042 1046 int ret;
1043 1047 ret = name_adjust(path, count);
1044 1048 count++;
1045 1049 if (ret != SA_OK ||
1046 1050 count >= MAX_MANGLE_NUMBER) {
1047 1051 (void) printf(gettext(
1048 1052 "Cannot create resource name for"
1049 1053 " path: %s\n"), path);
1050 1054 break;
1051 1055 }
1052 1056 }
1053 1057 sa_free_attr_string(path);
1054 1058 }
1055 1059 }
1056 1060 }
1057 1061
1058 1062 /*
1059 1063 * check_valid_group(group, protocol)
1060 1064 *
1061 1065 * Check to see that the group should have the protocol added (if
1062 1066 * there is one specified).
1063 1067 */
1064 1068
1065 1069 static int
1066 1070 check_valid_group(sa_group_t group, char *groupname, char *protocol)
1067 1071 {
1068 1072
1069 1073 if (protocol != NULL) {
1070 1074 if (has_protocol(group, protocol)) {
1071 1075 (void) printf(gettext(
1072 1076 "Group \"%s\" already exists"
1073 1077 " with protocol %s\n"), groupname,
1074 1078 protocol);
1075 1079 return (SA_DUPLICATE_NAME);
1076 1080 } else if (strcmp(groupname, "default") == 0 &&
1077 1081 strcmp(protocol, "nfs") != 0) {
1078 1082 (void) printf(gettext(
1079 1083 "Group \"%s\" only allows protocol "
1080 1084 "\"%s\"\n"), groupname, "nfs");
1081 1085 return (SA_INVALID_PROTOCOL);
1082 1086 }
1083 1087 } else {
1084 1088 /* must add new protocol */
1085 1089 (void) printf(gettext(
1086 1090 "Group already exists and no protocol "
1087 1091 "specified.\n"));
1088 1092 return (SA_DUPLICATE_NAME);
1089 1093 }
1090 1094 return (SA_OK);
1091 1095 }
1092 1096
1093 1097 /*
1094 1098 * enforce_featureset(group, protocol, dryrun, force)
1095 1099 *
1096 1100 * Check the protocol featureset against the group and enforce any
1097 1101 * rules that might be imposed.
1098 1102 */
1099 1103
1100 1104 static int
1101 1105 enforce_featureset(sa_group_t group, char *protocol, boolean_t dryrun,
1102 1106 boolean_t force)
1103 1107 {
1104 1108 uint64_t features;
1105 1109
1106 1110 if (protocol == NULL)
1107 1111 return (SA_OK);
1108 1112
1109 1113 /*
1110 1114 * First check to see if specified protocol is one we want to
1111 1115 * allow on a group. Only server protocols are allowed here.
1112 1116 */
1113 1117 features = sa_proto_get_featureset(protocol);
1114 1118 if (!(features & SA_FEATURE_SERVER)) {
1115 1119 (void) printf(
1116 1120 gettext("Protocol \"%s\" not supported.\n"), protocol);
1117 1121 return (SA_INVALID_PROTOCOL);
1118 1122 }
1119 1123
1120 1124 /*
1121 1125 * Check to see if the new protocol is one that requires
1122 1126 * resource names and make sure we are compliant before
1123 1127 * proceeding.
1124 1128 */
1125 1129 if ((features & SA_FEATURE_RESOURCE) &&
1126 1130 !resource_compliant(group)) {
1127 1131 if (force && !dryrun) {
1128 1132 make_resources(group);
1129 1133 } else {
1130 1134 (void) printf(
1131 1135 gettext("Protocol requires resource names to be "
1132 1136 "set: %s\n"), protocol);
1133 1137 return (SA_RESOURCE_REQUIRED);
1134 1138 }
1135 1139 }
1136 1140 return (SA_OK);
1137 1141 }
1138 1142
1139 1143 /*
1140 1144 * set_all_protocols(group)
1141 1145 *
1142 1146 * Get the list of all protocols and add all server protocols to the
1143 1147 * group.
1144 1148 */
1145 1149
1146 1150 static int
1147 1151 set_all_protocols(sa_group_t group)
1148 1152 {
1149 1153 char **protolist;
1150 1154 int numprotos, i;
1151 1155 uint64_t features;
1152 1156 sa_optionset_t optionset;
1153 1157 int ret = SA_OK;
1154 1158
1155 1159 /*
1156 1160 * Now make sure we really want to put this protocol on a
1157 1161 * group. Only server protocols can go here.
1158 1162 */
1159 1163 numprotos = sa_get_protocols(&protolist);
1160 1164 for (i = 0; i < numprotos; i++) {
1161 1165 features = sa_proto_get_featureset(protolist[i]);
1162 1166 if (features & SA_FEATURE_SERVER) {
1163 1167 optionset = sa_create_optionset(group, protolist[i]);
1164 1168 if (optionset == NULL) {
1165 1169 ret = SA_NO_MEMORY;
1166 1170 break;
1167 1171 }
1168 1172 }
1169 1173 }
1170 1174
1171 1175 if (protolist != NULL)
1172 1176 free(protolist);
1173 1177
1174 1178 return (ret);
1175 1179 }
1176 1180
1177 1181 /*
1178 1182 * sa_create(flags, argc, argv)
1179 1183 * create a new group
1180 1184 * this may or may not have a protocol associated with it.
1181 1185 * No protocol means "all" protocols in this case.
1182 1186 */
1183 1187 static int
1184 1188 sa_create(sa_handle_t handle, int flags, int argc, char *argv[])
1185 1189 {
1186 1190 char *groupname;
1187 1191
1188 1192 sa_group_t group;
1189 1193 boolean_t force = B_FALSE;
1190 1194 boolean_t verbose = B_FALSE;
1191 1195 boolean_t dryrun = B_FALSE;
1192 1196 int c;
1193 1197 char *protocol = NULL;
1194 1198 int ret = SA_OK;
1195 1199 struct options *optlist = NULL;
1196 1200 int err = SA_OK;
1197 1201 int auth;
1198 1202 boolean_t created = B_FALSE;
1199 1203
1200 1204 while ((c = getopt(argc, argv, "?fhvnP:p:")) != EOF) {
1201 1205 switch (c) {
1202 1206 case 'f':
1203 1207 force = B_TRUE;
1204 1208 break;
1205 1209 case 'v':
1206 1210 verbose = B_TRUE;
1207 1211 break;
1208 1212 case 'n':
1209 1213 dryrun = B_TRUE;
1210 1214 break;
1211 1215 case 'P':
1212 1216 if (protocol != NULL) {
1213 1217 (void) printf(gettext("Specifying "
1214 1218 "multiple protocols "
1215 1219 "not supported: %s\n"), protocol);
1216 1220 return (SA_SYNTAX_ERR);
1217 1221 }
1218 1222 protocol = optarg;
1219 1223 if (sa_valid_protocol(protocol))
1220 1224 break;
1221 1225 (void) printf(gettext(
1222 1226 "Invalid protocol specified: %s\n"), protocol);
1223 1227 return (SA_INVALID_PROTOCOL);
1224 1228 case 'p':
1225 1229 ret = add_opt(&optlist, optarg, 0);
1226 1230 switch (ret) {
1227 1231 case OPT_ADD_SYNTAX:
1228 1232 (void) printf(gettext(
1229 1233 "Property syntax error for property: %s\n"),
1230 1234 optarg);
1231 1235 return (SA_SYNTAX_ERR);
1232 1236 case OPT_ADD_SECURITY:
1233 1237 (void) printf(gettext(
1234 1238 "Security properties need "
1235 1239 "to be set with set-security: %s\n"),
1236 1240 optarg);
1237 1241 return (SA_SYNTAX_ERR);
1238 1242 default:
1239 1243 break;
1240 1244 }
1241 1245 break;
1242 1246 case 'h':
1243 1247 /* optopt on valid arg isn't defined */
1244 1248 optopt = c;
1245 1249 /*FALLTHROUGH*/
1246 1250 case '?':
1247 1251 default:
1248 1252 /*
1249 1253 * Since a bad option gets to here, sort it
1250 1254 * out and return a syntax error return value
1251 1255 * if necessary.
1252 1256 */
1253 1257 switch (optopt) {
1254 1258 default:
1255 1259 err = SA_SYNTAX_ERR;
1256 1260 break;
1257 1261 case 'h':
1258 1262 case '?':
1259 1263 break;
1260 1264 }
1261 1265 (void) printf(gettext("usage: %s\n"),
1262 1266 sa_get_usage(USAGE_CREATE));
1263 1267 return (err);
1264 1268 }
1265 1269 }
1266 1270
1267 1271 if (optind >= argc) {
1268 1272 (void) printf(gettext("usage: %s\n"),
1269 1273 sa_get_usage(USAGE_CREATE));
1270 1274 (void) printf(gettext("\tgroup must be specified.\n"));
1271 1275 return (SA_BAD_PATH);
1272 1276 }
1273 1277
1274 1278 if ((optind + 1) < argc) {
1275 1279 (void) printf(gettext("usage: %s\n"),
1276 1280 sa_get_usage(USAGE_CREATE));
1277 1281 (void) printf(gettext("\textraneous group(s) at end\n"));
1278 1282 return (SA_SYNTAX_ERR);
1279 1283 }
1280 1284
1281 1285 if (protocol == NULL && optlist != NULL) {
1282 1286 /* lookup default protocol */
1283 1287 (void) printf(gettext("usage: %s\n"),
1284 1288 sa_get_usage(USAGE_CREATE));
1285 1289 (void) printf(gettext("\tprotocol must be specified "
1286 1290 "with properties\n"));
1287 1291 return (SA_INVALID_PROTOCOL);
1288 1292 }
1289 1293
1290 1294 if (optlist != NULL)
1291 1295 ret = chk_opt(optlist, 0, protocol);
1292 1296 if (ret == OPT_ADD_SECURITY) {
1293 1297 (void) printf(gettext("Security properties not "
1294 1298 "supported with create\n"));
1295 1299 return (SA_SYNTAX_ERR);
1296 1300 }
1297 1301
1298 1302 /*
1299 1303 * If a group already exists, we can only add a new protocol
1300 1304 * to it and not create a new one or add the same protocol
1301 1305 * again.
1302 1306 */
1303 1307
1304 1308 groupname = argv[optind];
1305 1309
1306 1310 auth = check_authorizations(groupname, flags);
1307 1311
1308 1312 group = sa_get_group(handle, groupname);
1309 1313 if (group != NULL) {
1310 1314 /* group exists so must be a protocol add */
1311 1315 ret = check_valid_group(group, groupname, protocol);
1312 1316 } else {
1313 1317 /*
1314 1318 * is it a valid name? Must comply with SMF instance
1315 1319 * name restrictions.
1316 1320 */
1317 1321 if (!sa_valid_group_name(groupname)) {
1318 1322 ret = SA_INVALID_NAME;
1319 1323 (void) printf(gettext("Invalid group name: %s\n"),
1320 1324 groupname);
1321 1325 }
1322 1326 }
1323 1327 if (ret == SA_OK) {
1324 1328 /* check protocol vs optlist */
1325 1329 if (optlist != NULL) {
1326 1330 /* check options, if any, for validity */
1327 1331 ret = valid_options(handle, optlist, protocol,
1328 1332 group, NULL);
1329 1333 }
1330 1334 }
1331 1335 if (ret == SA_OK && !dryrun) {
1332 1336 if (group == NULL) {
1333 1337 group = sa_create_group(handle, (char *)groupname,
1334 1338 &err);
1335 1339 created = B_TRUE;
1336 1340 }
1337 1341 if (group != NULL) {
1338 1342 sa_optionset_t optionset;
1339 1343
1340 1344 /*
1341 1345 * Check group and protocol against featureset
1342 1346 * requirements.
1343 1347 */
1344 1348 ret = enforce_featureset(group, protocol,
1345 1349 dryrun, force);
1346 1350 if (ret != SA_OK)
1347 1351 goto err;
1348 1352
1349 1353 /*
1350 1354 * So far so good. Now add the required
1351 1355 * optionset(s) to the group.
1352 1356 */
1353 1357 if (optlist != NULL) {
1354 1358 (void) add_optionset(group, optlist, protocol,
1355 1359 &ret);
1356 1360 } else if (protocol != NULL) {
1357 1361 optionset = sa_create_optionset(group,
1358 1362 protocol);
1359 1363 if (optionset == NULL)
1360 1364 ret = SA_NO_MEMORY;
1361 1365 } else if (protocol == NULL) {
1362 1366 /* default group create so add all protocols */
1363 1367 ret = set_all_protocols(group);
1364 1368 }
1365 1369 /*
1366 1370 * We have a group and legal additions
1367 1371 */
1368 1372 if (ret == SA_OK) {
1369 1373 /*
1370 1374 * Commit to configuration for protocols that
1371 1375 * need to do block updates. For NFS, this
1372 1376 * doesn't do anything but it will be run for
1373 1377 * all protocols that implement the
1374 1378 * appropriate plugin.
1375 1379 */
1376 1380 ret = sa_update_config(handle);
1377 1381 } else {
1378 1382 if (group != NULL)
1379 1383 (void) sa_remove_group(group);
1380 1384 }
1381 1385 } else {
1382 1386 ret = err;
1383 1387 (void) printf(gettext("Could not create group: %s\n"),
1384 1388 sa_errorstr(ret));
1385 1389 }
1386 1390 }
1387 1391 if (dryrun && ret == SA_OK && !auth && verbose) {
1388 1392 (void) printf(gettext("Command would fail: %s\n"),
1389 1393 sa_errorstr(SA_NO_PERMISSION));
1390 1394 ret = SA_NO_PERMISSION;
1391 1395 }
1392 1396 err:
1393 1397 if (ret != SA_OK && created)
1394 1398 ret = sa_remove_group(group);
1395 1399
1396 1400 free_opt(optlist);
1397 1401 return (ret);
1398 1402 }
1399 1403
1400 1404 /*
1401 1405 * group_status(group)
1402 1406 *
1403 1407 * return the current status (enabled/disabled) of the group.
1404 1408 */
1405 1409
1406 1410 static char *
1407 1411 group_status(sa_group_t group)
1408 1412 {
1409 1413 char *state;
1410 1414 int enabled = 0;
1411 1415
1412 1416 state = sa_get_group_attr(group, "state");
1413 1417 if (state != NULL) {
1414 1418 if (strcmp(state, "enabled") == 0) {
1415 1419 enabled = 1;
1416 1420 }
1417 1421 sa_free_attr_string(state);
1418 1422 }
1419 1423 return (enabled ? "enabled" : "disabled");
1420 1424 }
1421 1425
1422 1426 /*
1423 1427 * sa_delete(flags, argc, argv)
1424 1428 *
1425 1429 * Delete a group.
1426 1430 */
1427 1431
1428 1432 static int
1429 1433 sa_delete(sa_handle_t handle, int flags, int argc, char *argv[])
1430 1434 {
1431 1435 char *groupname;
1432 1436 sa_group_t group;
1433 1437 sa_share_t share;
1434 1438 int verbose = 0;
1435 1439 int dryrun = 0;
1436 1440 int force = 0;
1437 1441 int c;
1438 1442 char *protocol = NULL;
1439 1443 char *sectype = NULL;
1440 1444 int ret = SA_OK;
1441 1445 int auth;
1442 1446
1443 1447 while ((c = getopt(argc, argv, "?hvnP:fS:")) != EOF) {
1444 1448 switch (c) {
1445 1449 case 'v':
1446 1450 verbose++;
1447 1451 break;
1448 1452 case 'n':
1449 1453 dryrun++;
1450 1454 break;
1451 1455 case 'P':
1452 1456 if (protocol != NULL) {
1453 1457 (void) printf(gettext("Specifying "
1454 1458 "multiple protocols "
1455 1459 "not supported: %s\n"), protocol);
1456 1460 return (SA_SYNTAX_ERR);
1457 1461 }
1458 1462 protocol = optarg;
1459 1463 if (!sa_valid_protocol(protocol)) {
1460 1464 (void) printf(gettext("Invalid protocol "
1461 1465 "specified: %s\n"), protocol);
1462 1466 return (SA_INVALID_PROTOCOL);
1463 1467 }
1464 1468 break;
1465 1469 case 'S':
1466 1470 if (sectype != NULL) {
1467 1471 (void) printf(gettext("Specifying "
1468 1472 "multiple property "
1469 1473 "spaces not supported: %s\n"), sectype);
1470 1474 return (SA_SYNTAX_ERR);
1471 1475 }
1472 1476 sectype = optarg;
1473 1477 break;
1474 1478 case 'f':
1475 1479 force++;
1476 1480 break;
1477 1481 case 'h':
1478 1482 /* optopt on valid arg isn't defined */
1479 1483 optopt = c;
1480 1484 /*FALLTHROUGH*/
1481 1485 case '?':
1482 1486 default:
1483 1487 /*
1484 1488 * Since a bad option gets to here, sort it
1485 1489 * out and return a syntax error return value
1486 1490 * if necessary.
1487 1491 */
1488 1492 switch (optopt) {
1489 1493 default:
1490 1494 ret = SA_SYNTAX_ERR;
1491 1495 break;
1492 1496 case 'h':
1493 1497 case '?':
1494 1498 break;
1495 1499 }
1496 1500 (void) printf(gettext("usage: %s\n"),
1497 1501 sa_get_usage(USAGE_DELETE));
1498 1502 return (ret);
1499 1503 }
1500 1504 }
1501 1505
1502 1506 if (optind >= argc) {
1503 1507 (void) printf(gettext("usage: %s\n"),
1504 1508 sa_get_usage(USAGE_DELETE));
1505 1509 (void) printf(gettext("\tgroup must be specified.\n"));
1506 1510 return (SA_SYNTAX_ERR);
1507 1511 }
1508 1512
1509 1513 if ((optind + 1) < argc) {
1510 1514 (void) printf(gettext("usage: %s\n"),
1511 1515 sa_get_usage(USAGE_DELETE));
1512 1516 (void) printf(gettext("\textraneous group(s) at end\n"));
1513 1517 return (SA_SYNTAX_ERR);
1514 1518 }
1515 1519
1516 1520 if (sectype != NULL && protocol == NULL) {
1517 1521 (void) printf(gettext("usage: %s\n"),
1518 1522 sa_get_usage(USAGE_DELETE));
1519 1523 (void) printf(gettext("\tsecurity requires protocol to be "
1520 1524 "specified.\n"));
1521 1525 return (SA_SYNTAX_ERR);
1522 1526 }
1523 1527
1524 1528 /*
1525 1529 * Determine if the group already exists since it must in
1526 1530 * order to be removed.
1527 1531 *
1528 1532 * We can delete when:
1529 1533 *
1530 1534 * - group is empty
1531 1535 * - force flag is set
1532 1536 * - if protocol specified, only delete the protocol
1533 1537 */
1534 1538
1535 1539 groupname = argv[optind];
1536 1540 group = sa_get_group(handle, groupname);
1537 1541 if (group == NULL) {
1538 1542 ret = SA_NO_SUCH_GROUP;
1539 1543 goto done;
1540 1544 }
1541 1545 auth = check_authorizations(groupname, flags);
1542 1546 if (protocol == NULL) {
1543 1547 share = sa_get_share(group, NULL);
1544 1548 if (share != NULL)
1545 1549 ret = SA_BUSY;
1546 1550 if (share == NULL || (share != NULL && force == 1)) {
1547 1551 ret = SA_OK;
1548 1552 if (!dryrun) {
1549 1553 while (share != NULL) {
1550 1554 sa_share_t next_share;
1551 1555 next_share = sa_get_next_share(share);
1552 1556 /*
1553 1557 * need to do the disable of
1554 1558 * each share, but don't
1555 1559 * actually do anything on a
1556 1560 * dryrun.
1557 1561 */
1558 1562 ret = sa_disable_share(share, NULL);
1559 1563 ret = sa_remove_share(share);
1560 1564 share = next_share;
1561 1565 }
1562 1566 ret = sa_remove_group(group);
1563 1567 }
1564 1568 }
1565 1569 /* Commit to configuration if not a dryrun */
1566 1570 if (!dryrun && ret == SA_OK) {
1567 1571 ret = sa_update_config(handle);
1568 1572 }
1569 1573 } else {
1570 1574 /* a protocol delete */
1571 1575 sa_optionset_t optionset;
1572 1576 sa_security_t security;
1573 1577 if (sectype != NULL) {
1574 1578 /* only delete specified security */
1575 1579 security = sa_get_security(group, sectype, protocol);
1576 1580 if (security != NULL && !dryrun)
1577 1581 ret = sa_destroy_security(security);
1578 1582 else
1579 1583 ret = SA_INVALID_PROTOCOL;
1580 1584 } else {
1581 1585 optionset = sa_get_optionset(group, protocol);
1582 1586 if (optionset != NULL && !dryrun) {
1583 1587 /*
1584 1588 * have an optionset with
1585 1589 * protocol to delete
1586 1590 */
1587 1591 ret = sa_destroy_optionset(optionset);
1588 1592 /*
1589 1593 * Now find all security sets
1590 1594 * for the protocol and remove
1591 1595 * them. Don't remove other
1592 1596 * protocols.
1593 1597 */
1594 1598 for (security =
1595 1599 sa_get_security(group, NULL, NULL);
1596 1600 ret == SA_OK && security != NULL;
1597 1601 security = sa_get_next_security(security)) {
1598 1602 char *secprot;
1599 1603 secprot = sa_get_security_attr(security,
1600 1604 "type");
1601 1605 if (secprot != NULL &&
1602 1606 strcmp(secprot, protocol) == 0)
1603 1607 ret = sa_destroy_security(
1604 1608 security);
1605 1609 if (secprot != NULL)
1606 1610 sa_free_attr_string(secprot);
1607 1611 }
1608 1612 } else {
1609 1613 if (!dryrun)
1610 1614 ret = SA_INVALID_PROTOCOL;
1611 1615 }
1612 1616 }
1613 1617 /*
1614 1618 * With the protocol items removed, make sure that all
1615 1619 * the shares are updated in the legacy files, if
1616 1620 * necessary.
1617 1621 */
1618 1622 for (share = sa_get_share(group, NULL);
1619 1623 share != NULL;
1620 1624 share = sa_get_next_share(share)) {
1621 1625 (void) sa_delete_legacy(share, protocol);
1622 1626 }
1623 1627 }
1624 1628
1625 1629 done:
1626 1630 if (ret != SA_OK) {
1627 1631 (void) printf(gettext("Could not delete group: %s\n"),
1628 1632 sa_errorstr(ret));
1629 1633 } else if (dryrun && !auth && verbose) {
1630 1634 (void) printf(gettext("Command would fail: %s\n"),
1631 1635 sa_errorstr(SA_NO_PERMISSION));
1632 1636 }
1633 1637 return (ret);
1634 1638 }
1635 1639
1636 1640 /*
1637 1641 * strndupr(*buff, str, buffsize)
1638 1642 *
1639 1643 * used with small strings to duplicate and possibly increase the
1640 1644 * buffer size of a string.
1641 1645 */
1642 1646 static char *
1643 1647 strndupr(char *buff, char *str, int *buffsize)
1644 1648 {
1645 1649 int limit;
1646 1650 char *orig_buff = buff;
1647 1651
1648 1652 if (buff == NULL) {
1649 1653 buff = (char *)malloc(64);
1650 1654 if (buff == NULL)
1651 1655 return (NULL);
1652 1656 *buffsize = 64;
1653 1657 buff[0] = '\0';
1654 1658 }
1655 1659 limit = strlen(buff) + strlen(str) + 1;
1656 1660 if (limit > *buffsize) {
1657 1661 limit = *buffsize = *buffsize + ((limit / 64) + 64);
1658 1662 buff = realloc(buff, limit);
1659 1663 }
1660 1664 if (buff != NULL) {
1661 1665 (void) strcat(buff, str);
1662 1666 } else {
1663 1667 /* if it fails, fail it hard */
1664 1668 if (orig_buff != NULL)
1665 1669 free(orig_buff);
1666 1670 }
1667 1671 return (buff);
1668 1672 }
1669 1673
1670 1674 /*
1671 1675 * group_proto(group)
1672 1676 *
1673 1677 * return a string of all the protocols (space separated) associated
1674 1678 * with this group.
1675 1679 */
1676 1680
1677 1681 static char *
1678 1682 group_proto(sa_group_t group)
1679 1683 {
1680 1684 sa_optionset_t optionset;
1681 1685 char *proto;
1682 1686 char *buff = NULL;
1683 1687 int buffsize = 0;
1684 1688 int addspace = 0;
1685 1689 /*
1686 1690 * get the protocol list by finding the optionsets on this
1687 1691 * group and extracting the type value. The initial call to
1688 1692 * strndupr() initailizes buff.
1689 1693 */
1690 1694 buff = strndupr(buff, "", &buffsize);
1691 1695 if (buff != NULL) {
1692 1696 for (optionset = sa_get_optionset(group, NULL);
1693 1697 optionset != NULL && buff != NULL;
1694 1698 optionset = sa_get_next_optionset(optionset)) {
1695 1699 /*
1696 1700 * extract out the protocol type from this optionset
1697 1701 * and append it to the buffer "buff". strndupr() will
1698 1702 * reallocate space as necessay.
1699 1703 */
1700 1704 proto = sa_get_optionset_attr(optionset, "type");
1701 1705 if (proto != NULL) {
1702 1706 if (addspace++)
1703 1707 buff = strndupr(buff, " ", &buffsize);
1704 1708 buff = strndupr(buff, proto, &buffsize);
1705 1709 sa_free_attr_string(proto);
1706 1710 }
1707 1711 }
1708 1712 }
1709 1713 return (buff);
1710 1714 }
1711 1715
1712 1716 /*
1713 1717 * sa_list(flags, argc, argv)
1714 1718 *
1715 1719 * implements the "list" subcommand to list groups and optionally
1716 1720 * their state and protocols.
1717 1721 */
1718 1722
1719 1723 static int
1720 1724 sa_list(sa_handle_t handle, int flags, int argc, char *argv[])
1721 1725 {
1722 1726 sa_group_t group;
1723 1727 int verbose = 0;
1724 1728 int c;
1725 1729 char *protocol = NULL;
1726 1730 int ret = SA_OK;
1727 1731 #ifdef lint
1728 1732 flags = flags;
1729 1733 #endif
1730 1734
1731 1735 while ((c = getopt(argc, argv, "?hvP:")) != EOF) {
1732 1736 switch (c) {
1733 1737 case 'v':
1734 1738 verbose++;
1735 1739 break;
1736 1740 case 'P':
1737 1741 if (protocol != NULL) {
1738 1742 (void) printf(gettext(
1739 1743 "Specifying multiple protocols "
1740 1744 "not supported: %s\n"),
1741 1745 protocol);
1742 1746 return (SA_SYNTAX_ERR);
1743 1747 }
1744 1748 protocol = optarg;
1745 1749 if (!sa_valid_protocol(protocol)) {
1746 1750 (void) printf(gettext(
1747 1751 "Invalid protocol specified: %s\n"),
1748 1752 protocol);
1749 1753 return (SA_INVALID_PROTOCOL);
1750 1754 }
1751 1755 break;
1752 1756 case 'h':
1753 1757 /* optopt on valid arg isn't defined */
1754 1758 optopt = c;
1755 1759 /*FALLTHROUGH*/
1756 1760 case '?':
1757 1761 default:
1758 1762 /*
1759 1763 * Since a bad option gets to here, sort it
1760 1764 * out and return a syntax error return value
1761 1765 * if necessary.
1762 1766 */
1763 1767 switch (optopt) {
1764 1768 default:
1765 1769 ret = SA_SYNTAX_ERR;
1766 1770 break;
1767 1771 case 'h':
1768 1772 case '?':
1769 1773 break;
1770 1774 }
1771 1775 (void) printf(gettext("usage: %s\n"),
1772 1776 sa_get_usage(USAGE_LIST));
1773 1777 return (ret);
1774 1778 }
1775 1779 }
1776 1780
1777 1781 if (optind != argc) {
1778 1782 (void) printf(gettext("usage: %s\n"),
1779 1783 sa_get_usage(USAGE_LIST));
1780 1784 return (SA_SYNTAX_ERR);
1781 1785 }
1782 1786
1783 1787 for (group = sa_get_group(handle, NULL);
1784 1788 group != NULL;
1785 1789 group = sa_get_next_group(group)) {
1786 1790 char *name;
1787 1791 char *proto;
1788 1792 if (protocol == NULL || has_protocol(group, protocol)) {
1789 1793 name = sa_get_group_attr(group, "name");
1790 1794 if (name != NULL && (verbose > 1 || name[0] != '#')) {
1791 1795 (void) printf("%s", (char *)name);
1792 1796 if (verbose) {
1793 1797 /*
1794 1798 * Need the list of protocols
1795 1799 * and current status once
1796 1800 * available. We do want to
1797 1801 * translate the
1798 1802 * enabled/disabled text here.
1799 1803 */
1800 1804 (void) printf("\t%s", isenabled(group) ?
1801 1805 gettext("enabled") :
1802 1806 gettext("disabled"));
1803 1807 proto = group_proto(group);
1804 1808 if (proto != NULL) {
1805 1809 (void) printf("\t%s",
1806 1810 (char *)proto);
1807 1811 free(proto);
1808 1812 }
1809 1813 }
1810 1814 (void) printf("\n");
1811 1815 }
1812 1816 if (name != NULL)
1813 1817 sa_free_attr_string(name);
1814 1818 }
1815 1819 }
1816 1820 return (0);
1817 1821 }
1818 1822
1819 1823 /*
1820 1824 * out_properties(optionset, proto, sec)
1821 1825 *
1822 1826 * Format the properties and encode the protocol and optional named
1823 1827 * optionset into the string.
1824 1828 *
1825 1829 * format is protocol[:name]=(property-list)
1826 1830 */
1827 1831
1828 1832 static void
1829 1833 out_properties(sa_optionset_t optionset, char *proto, char *sec)
1830 1834 {
1831 1835 char *type;
1832 1836 char *value;
1833 1837 int spacer;
1834 1838 sa_property_t prop;
1835 1839
1836 1840 if (sec == NULL)
1837 1841 (void) printf(" %s=(", proto ? proto : gettext("all"));
1838 1842 else
1839 1843 (void) printf(" %s:%s=(", proto ? proto : gettext("all"), sec);
1840 1844
1841 1845 for (spacer = 0, prop = sa_get_property(optionset, NULL);
1842 1846 prop != NULL;
1843 1847 prop = sa_get_next_property(prop)) {
1844 1848
1845 1849 /*
1846 1850 * extract the property name/value and output with
1847 1851 * appropriate spacing. I.e. no prefixed space the
1848 1852 * first time through but a space on subsequent
1849 1853 * properties.
1850 1854 */
1851 1855 type = sa_get_property_attr(prop, "type");
1852 1856 value = sa_get_property_attr(prop, "value");
1853 1857 if (type != NULL) {
1854 1858 (void) printf("%s%s=", spacer ? " " : "", type);
1855 1859 spacer = 1;
1856 1860 if (value != NULL)
1857 1861 (void) printf("\"%s\"", value);
1858 1862 else
1859 1863 (void) printf("\"\"");
1860 1864 }
1861 1865 if (type != NULL)
1862 1866 sa_free_attr_string(type);
1863 1867 if (value != NULL)
1864 1868 sa_free_attr_string(value);
1865 1869 }
1866 1870 (void) printf(")");
1867 1871 }
1868 1872
1869 1873 /*
1870 1874 * show_properties(group, protocol, prefix)
1871 1875 *
1872 1876 * print the properties for a group. If protocol is NULL, do all
1873 1877 * protocols otherwise only the specified protocol. All security
1874 1878 * (named groups specific to the protocol) are included.
1875 1879 *
1876 1880 * The "prefix" is always applied. The caller knows whether it wants
1877 1881 * some type of prefix string (white space) or not. Once the prefix
1878 1882 * has been output, it is reduced to the zero length string for the
1879 1883 * remainder of the property output.
1880 1884 */
1881 1885
1882 1886 static void
1883 1887 show_properties(sa_group_t group, char *protocol, char *prefix)
1884 1888 {
1885 1889 sa_optionset_t optionset;
1886 1890 sa_security_t security;
1887 1891 char *value;
1888 1892 char *secvalue;
1889 1893
1890 1894 if (protocol != NULL) {
1891 1895 optionset = sa_get_optionset(group, protocol);
1892 1896 if (optionset != NULL) {
1893 1897 (void) printf("%s", prefix);
1894 1898 prefix = "";
1895 1899 out_properties(optionset, protocol, NULL);
1896 1900 }
1897 1901 security = sa_get_security(group, protocol, NULL);
1898 1902 if (security != NULL) {
1899 1903 (void) printf("%s", prefix);
1900 1904 prefix = "";
1901 1905 out_properties(security, protocol, NULL);
1902 1906 }
1903 1907 } else {
1904 1908 for (optionset = sa_get_optionset(group, protocol);
1905 1909 optionset != NULL;
1906 1910 optionset = sa_get_next_optionset(optionset)) {
1907 1911
1908 1912 value = sa_get_optionset_attr(optionset, "type");
1909 1913 (void) printf("%s", prefix);
1910 1914 prefix = "";
1911 1915 out_properties(optionset, value, 0);
1912 1916 if (value != NULL)
1913 1917 sa_free_attr_string(value);
1914 1918 }
1915 1919 for (security = sa_get_security(group, NULL, protocol);
1916 1920 security != NULL;
1917 1921 security = sa_get_next_security(security)) {
1918 1922
1919 1923 value = sa_get_security_attr(security, "type");
1920 1924 secvalue = sa_get_security_attr(security, "sectype");
1921 1925 (void) printf("%s", prefix);
1922 1926 prefix = "";
1923 1927 out_properties(security, value, secvalue);
1924 1928 if (value != NULL)
1925 1929 sa_free_attr_string(value);
1926 1930 if (secvalue != NULL)
1927 1931 sa_free_attr_string(secvalue);
1928 1932 }
1929 1933 }
1930 1934 }
1931 1935
1932 1936 /*
1933 1937 * get_resource(share)
1934 1938 *
1935 1939 * Get the first resource name, if any, and fix string to be in
1936 1940 * current locale and have quotes if it has embedded spaces. Return
1937 1941 * an attr string that must be freed.
1938 1942 */
1939 1943
1940 1944 static char *
1941 1945 get_resource(sa_share_t share)
1942 1946 {
1943 1947 sa_resource_t resource;
1944 1948 char *resstring = NULL;
1945 1949 char *retstring;
1946 1950
1947 1951 if ((resource = sa_get_share_resource(share, NULL)) != NULL) {
1948 1952 resstring = sa_get_resource_attr(resource, "name");
1949 1953 if (resstring != NULL) {
1950 1954 char *cp;
1951 1955 int len;
1952 1956
1953 1957 retstring = conv_from_utf8(resstring);
1954 1958 if (retstring != resstring) {
1955 1959 sa_free_attr_string(resstring);
1956 1960 resstring = retstring;
1957 1961 }
1958 1962 if (strpbrk(resstring, " ") != NULL) {
1959 1963 /* account for quotes */
1960 1964 len = strlen(resstring) + 3;
1961 1965 cp = calloc(len, sizeof (char));
1962 1966 if (cp != NULL) {
1963 1967 (void) snprintf(cp, len,
1964 1968 "\"%s\"", resstring);
1965 1969 sa_free_attr_string(resstring);
1966 1970 resstring = cp;
1967 1971 } else {
1968 1972 sa_free_attr_string(resstring);
1969 1973 resstring = NULL;
1970 1974 }
1971 1975 }
1972 1976 }
1973 1977 }
1974 1978 return (resstring);
1975 1979 }
1976 1980
1977 1981 /*
1978 1982 * has_resource_with_opt(share)
1979 1983 *
1980 1984 * Check to see if the share has any resource names with optionsets
1981 1985 * set. Also indicate if multiple resource names since the syntax
1982 1986 * would be about the same.
1983 1987 */
1984 1988 static int
1985 1989 has_resource_with_opt(sa_share_t share)
1986 1990 {
1987 1991 sa_resource_t resource;
1988 1992 int ret = B_FALSE;
1989 1993
1990 1994 for (resource = sa_get_share_resource(share, NULL);
1991 1995 resource != NULL;
1992 1996 resource = sa_get_next_resource(resource)) {
1993 1997
1994 1998 if (sa_get_optionset(resource, NULL) != NULL) {
1995 1999 ret = B_TRUE;
1996 2000 break;
1997 2001 }
1998 2002 }
1999 2003 return (ret);
2000 2004 }
2001 2005
2002 2006 /*
2003 2007 * has_multiple_resource(share)
2004 2008 *
2005 2009 * Check to see if the share has multiple resource names since
2006 2010 * the syntax would be about the same.
2007 2011 */
2008 2012 static boolean_t
2009 2013 has_multiple_resource(sa_share_t share)
2010 2014 {
2011 2015 sa_resource_t resource;
2012 2016 int num;
2013 2017
2014 2018 for (num = 0, resource = sa_get_share_resource(share, NULL);
2015 2019 resource != NULL;
2016 2020 resource = sa_get_next_resource(resource)) {
2017 2021 num++;
2018 2022 if (num > 1)
2019 2023 return (B_TRUE);
2020 2024 }
2021 2025 return (B_FALSE);
2022 2026 }
2023 2027
2024 2028 /*
2025 2029 * show_share(share, verbose, properties, proto, iszfs, sharepath)
2026 2030 *
2027 2031 * print out the share information. With the addition of resource as a
2028 2032 * full object that can have multiple instances below the share, we
2029 2033 * need to display that as well.
2030 2034 */
2031 2035
2032 2036 static void
2033 2037 show_share(sa_share_t share, int verbose, int properties, char *proto,
2034 2038 int iszfs, char *sharepath)
2035 2039 {
2036 2040 char *drive;
2037 2041 char *exclude;
2038 2042 sa_resource_t resource = NULL;
2039 2043 char *description;
2040 2044 char *rsrcname;
2041 2045 int rsrcwithopt;
2042 2046 boolean_t multiple;
2043 2047 char *type;
2044 2048
2045 2049 rsrcwithopt = has_resource_with_opt(share);
2046 2050
2047 2051 if (verbose || (properties && rsrcwithopt)) {
2048 2052 /* First, indicate if transient */
2049 2053 type = sa_get_share_attr(share, "type");
2050 2054 if (type != NULL && !iszfs && verbose &&
2051 2055 strcmp(type, "transient") == 0)
2052 2056 (void) printf("\t* ");
2053 2057 else
2054 2058 (void) printf("\t ");
2055 2059
2056 2060 if (type != NULL)
2057 2061 sa_free_attr_string(type);
2058 2062
2059 2063 /*
2060 2064 * If we came in with verbose, we want to handle the case of
2061 2065 * multiple resources as though they had properties set.
2062 2066 */
2063 2067 multiple = has_multiple_resource(share);
2064 2068
2065 2069 /*
2066 2070 * if there is a description on the share and there
2067 2071 * are resources, treat as multiple resources in order
2068 2072 * to get all descriptions displayed.
2069 2073 */
2070 2074 description = sa_get_share_description(share);
2071 2075 resource = sa_get_share_resource(share, NULL);
2072 2076
2073 2077 if (description != NULL && resource != NULL)
2074 2078 multiple = B_TRUE;
2075 2079
2076 2080 /* Next, if not multiple follow old model */
2077 2081 if (!multiple && !rsrcwithopt) {
2078 2082 rsrcname = get_resource(share);
2079 2083 if (rsrcname != NULL && strlen(rsrcname) > 0) {
2080 2084 (void) printf("%s=%s", rsrcname, sharepath);
2081 2085 } else {
2082 2086 (void) printf("%s", sharepath);
2083 2087 }
2084 2088 if (rsrcname != NULL)
2085 2089 sa_free_attr_string(rsrcname);
2086 2090 /* Print the description string if there is one. */
2087 2091 print_rsrc_desc(resource, description);
2088 2092 } else {
2089 2093 /* Treat as simple and then resources come later */
2090 2094 (void) printf("%s", sharepath);
2091 2095 }
2092 2096 drive = sa_get_share_attr(share, "drive-letter");
2093 2097 if (drive != NULL) {
2094 2098 if (strlen(drive) > 0)
2095 2099 (void) printf(gettext("\tdrive-letter=\"%s:\""),
2096 2100 drive);
2097 2101 sa_free_attr_string(drive);
2098 2102 }
2099 2103 if (properties)
2100 2104 show_properties(share, proto, "\t");
2101 2105 exclude = sa_get_share_attr(share, "exclude");
2102 2106 if (exclude != NULL) {
2103 2107 (void) printf(gettext("\tnot-shared-with=[%s]"),
2104 2108 exclude);
2105 2109 sa_free_attr_string(exclude);
2106 2110 }
2107 2111
2108 2112 if (description != NULL) {
2109 2113 print_rsrc_desc((sa_resource_t)share, description);
2110 2114 }
2111 2115 /*
2112 2116 * If there are resource names with options, show them
2113 2117 * here, with one line per resource. Resource specific
2114 2118 * options are at the end of the line followed by
2115 2119 * description, if any.
2116 2120 */
2117 2121 if (rsrcwithopt || multiple) {
2118 2122 for (resource = sa_get_share_resource(share, NULL);
2119 2123 resource != NULL;
2120 2124 resource = sa_get_next_resource(resource)) {
2121 2125 int has_space;
2122 2126 char *rsrc;
2123 2127
2124 2128 (void) printf("\n\t\t ");
2125 2129 rsrcname = sa_get_resource_attr(resource,
2126 2130 "name");
2127 2131 if (rsrcname == NULL)
2128 2132 continue;
2129 2133
2130 2134 rsrc = conv_from_utf8(rsrcname);
2131 2135 has_space = strpbrk(rsrc, " ") != NULL;
2132 2136
2133 2137 if (has_space)
2134 2138 (void) printf("\"%s\"=%s", rsrc,
2135 2139 sharepath);
2136 2140 else
2137 2141 (void) printf("%s=%s", rsrc,
2138 2142 sharepath);
2139 2143 if (rsrc != rsrcname)
2140 2144 sa_free_attr_string(rsrc);
2141 2145 sa_free_attr_string(rsrcname);
2142 2146 if (properties || rsrcwithopt)
2143 2147 show_properties(resource, proto, "\t");
2144 2148
2145 2149 /* Get description string if any */
2146 2150 print_rsrc_desc(resource, description);
2147 2151 }
2148 2152 }
2149 2153 if (description != NULL)
2150 2154 sa_free_share_description(description);
2151 2155 } else {
2152 2156 (void) printf("\t %s", sharepath);
2153 2157 if (properties)
2154 2158 show_properties(share, proto, "\t");
2155 2159 }
2156 2160 (void) printf("\n");
2157 2161 }
2158 2162
|
↓ open down ↓ |
2123 lines elided |
↑ open up ↑ |
2159 2163 /*
2160 2164 * show_group(group, verbose, properties, proto, subgroup)
2161 2165 *
2162 2166 * helper function to show the contents of a group.
2163 2167 */
2164 2168
2165 2169 static void
2166 2170 show_group(sa_group_t group, int verbose, int properties, char *proto,
2167 2171 char *subgroup)
2168 2172 {
2169 - sa_share_t share;
2170 2173 char *groupname;
2171 2174 char *zfs = NULL;
2172 2175 int iszfs = 0;
2173 2176 char *sharepath;
2174 2177
2175 2178 groupname = sa_get_group_attr(group, "name");
2176 2179 if (groupname != NULL) {
2180 + sa_share_t share;
2181 +
2177 2182 if (proto != NULL && !has_protocol(group, proto)) {
2178 2183 sa_free_attr_string(groupname);
2179 2184 return;
2180 2185 }
2181 2186 /*
2182 2187 * check to see if the group is managed by ZFS. If
2183 2188 * there is an attribute, then it is. A non-NULL zfs
2184 2189 * variable will trigger the different way to display
2185 2190 * and will remove the transient property indicator
2186 2191 * from the output.
2187 2192 */
2188 2193 zfs = sa_get_group_attr(group, "zfs");
2189 2194 if (zfs != NULL) {
2190 2195 iszfs = 1;
2191 2196 sa_free_attr_string(zfs);
2192 2197 }
2193 - share = sa_get_share(group, NULL);
2198 +
2194 2199 if (subgroup == NULL)
2195 2200 (void) printf("%s", groupname);
2196 2201 else
2197 2202 (void) printf(" %s/%s", subgroup, groupname);
2198 2203 if (properties)
2199 2204 show_properties(group, proto, "");
2200 2205 (void) printf("\n");
2201 2206 if (strcmp(groupname, "zfs") == 0) {
2202 2207 sa_group_t zgroup;
2203 2208
2204 2209 for (zgroup = sa_get_sub_group(group);
2205 2210 zgroup != NULL;
2206 2211 zgroup = sa_get_next_group(zgroup)) {
2207 2212 show_group(zgroup, verbose, properties, proto,
2208 2213 "zfs");
2209 2214 }
2210 2215 sa_free_attr_string(groupname);
2211 2216 return;
2212 2217 }
2213 2218 /*
2214 2219 * Have a group, so list the contents. Resource and
2215 2220 * description are only listed if verbose is set.
2216 2221 */
2217 2222 for (share = sa_get_share(group, NULL);
2218 2223 share != NULL;
2219 2224 share = sa_get_next_share(share)) {
2220 2225 sharepath = sa_get_share_attr(share, "path");
2221 2226 if (sharepath != NULL) {
2222 2227 show_share(share, verbose, properties, proto,
2223 2228 iszfs, sharepath);
2224 2229 sa_free_attr_string(sharepath);
2225 2230 }
2226 2231 }
2227 2232 }
2228 2233 if (groupname != NULL) {
2229 2234 sa_free_attr_string(groupname);
2230 2235 }
2231 2236 }
2232 2237
2233 2238 /*
2234 2239 * show_group_xml_init()
2235 2240 *
2236 2241 * Create an XML document that will be used to display config info via
2237 2242 * XML format.
2238 2243 */
2239 2244
2240 2245 xmlDocPtr
2241 2246 show_group_xml_init()
2242 2247 {
2243 2248 xmlDocPtr doc;
2244 2249 xmlNodePtr root;
2245 2250
2246 2251 doc = xmlNewDoc((xmlChar *)"1.0");
2247 2252 if (doc != NULL) {
2248 2253 root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
2249 2254 if (root != NULL)
2250 2255 (void) xmlDocSetRootElement(doc, root);
2251 2256 }
2252 2257 return (doc);
2253 2258 }
2254 2259
2255 2260 /*
2256 2261 * show_group_xml(doc, group)
2257 2262 *
2258 2263 * Copy the group info into the XML doc.
2259 2264 */
2260 2265
2261 2266 static void
2262 2267 show_group_xml(xmlDocPtr doc, sa_group_t group)
2263 2268 {
2264 2269 xmlNodePtr node;
2265 2270 xmlNodePtr root;
2266 2271
2267 2272 root = xmlDocGetRootElement(doc);
2268 2273 node = xmlCopyNode((xmlNodePtr)group, 1);
2269 2274 if (node != NULL && root != NULL) {
2270 2275 (void) xmlAddChild(root, node);
2271 2276 /*
2272 2277 * In the future, we may have interally used tags that
2273 2278 * should not appear in the XML output. Remove
2274 2279 * anything we don't want to show here.
2275 2280 */
2276 2281 }
2277 2282 }
2278 2283
2279 2284 /*
2280 2285 * sa_show(flags, argc, argv)
2281 2286 *
2282 2287 * Implements the show subcommand.
2283 2288 */
2284 2289
2285 2290 int
2286 2291 sa_show(sa_handle_t handle, int flags, int argc, char *argv[])
2287 2292 {
2288 2293 sa_group_t group;
2289 2294 int verbose = 0;
2290 2295 int properties = 0;
2291 2296 int c;
2292 2297 int ret = SA_OK;
2293 2298 char *protocol = NULL;
2294 2299 int xml = 0;
2295 2300 xmlDocPtr doc;
2296 2301 #ifdef lint
2297 2302 flags = flags;
2298 2303 #endif
2299 2304
2300 2305 while ((c = getopt(argc, argv, "?hvP:px")) != EOF) {
2301 2306 switch (c) {
2302 2307 case 'v':
2303 2308 verbose++;
2304 2309 break;
2305 2310 case 'p':
2306 2311 properties++;
2307 2312 break;
2308 2313 case 'P':
2309 2314 if (protocol != NULL) {
2310 2315 (void) printf(gettext(
2311 2316 "Specifying multiple protocols "
2312 2317 "not supported: %s\n"),
2313 2318 protocol);
2314 2319 return (SA_SYNTAX_ERR);
2315 2320 }
2316 2321 protocol = optarg;
2317 2322 if (!sa_valid_protocol(protocol)) {
2318 2323 (void) printf(gettext(
2319 2324 "Invalid protocol specified: %s\n"),
2320 2325 protocol);
2321 2326 return (SA_INVALID_PROTOCOL);
2322 2327 }
2323 2328 break;
2324 2329 case 'x':
2325 2330 xml++;
2326 2331 break;
2327 2332 case 'h':
2328 2333 /* optopt on valid arg isn't defined */
2329 2334 optopt = c;
2330 2335 /*FALLTHROUGH*/
2331 2336 case '?':
2332 2337 default:
2333 2338 /*
2334 2339 * Since a bad option gets to here, sort it
2335 2340 * out and return a syntax error return value
2336 2341 * if necessary.
2337 2342 */
2338 2343 switch (optopt) {
2339 2344 default:
2340 2345 ret = SA_SYNTAX_ERR;
2341 2346 break;
2342 2347 case 'h':
2343 2348 case '?':
2344 2349 break;
2345 2350 }
2346 2351 (void) printf(gettext("usage: %s\n"),
2347 2352 sa_get_usage(USAGE_SHOW));
2348 2353 return (ret);
2349 2354 }
2350 2355 }
2351 2356
2352 2357 if (xml) {
2353 2358 doc = show_group_xml_init();
2354 2359 if (doc == NULL)
2355 2360 ret = SA_NO_MEMORY;
2356 2361 }
2357 2362
2358 2363 if (optind == argc) {
2359 2364 /* No group specified so go through them all */
2360 2365 for (group = sa_get_group(handle, NULL);
2361 2366 group != NULL;
2362 2367 group = sa_get_next_group(group)) {
2363 2368 /*
2364 2369 * Have a group so check if one we want and then list
2365 2370 * contents with appropriate options.
2366 2371 */
2367 2372 if (xml)
2368 2373 show_group_xml(doc, group);
2369 2374 else
2370 2375 show_group(group, verbose, properties, protocol,
2371 2376 NULL);
2372 2377 }
2373 2378 } else {
2374 2379 /* Have a specified list of groups */
2375 2380 for (; optind < argc; optind++) {
2376 2381 group = sa_get_group(handle, argv[optind]);
2377 2382 if (group != NULL) {
2378 2383 if (xml)
2379 2384 show_group_xml(doc, group);
2380 2385 else
2381 2386 show_group(group, verbose, properties,
2382 2387 protocol, NULL);
2383 2388 } else {
2384 2389 (void) printf(gettext("%s: not found\n"),
2385 2390 argv[optind]);
2386 2391 ret = SA_NO_SUCH_GROUP;
2387 2392 }
2388 2393 }
2389 2394 }
2390 2395 if (xml && ret == SA_OK) {
2391 2396 (void) xmlDocFormatDump(stdout, doc, 1);
2392 2397 xmlFreeDoc(doc);
2393 2398 }
2394 2399 return (ret);
2395 2400
2396 2401 }
2397 2402
2398 2403 /*
2399 2404 * enable_share(group, share, update_legacy)
2400 2405 *
2401 2406 * helper function to enable a share if the group is enabled.
2402 2407 */
2403 2408
2404 2409 static int
2405 2410 enable_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
2406 2411 int update_legacy)
2407 2412 {
2408 2413 char *value;
2409 2414 int enabled;
2410 2415 sa_optionset_t optionset;
2411 2416 int err;
2412 2417 int ret = SA_OK;
2413 2418 char *zfs = NULL;
2414 2419 int iszfs = 0;
2415 2420 int isshare;
2416 2421
2417 2422 /*
2418 2423 * need to enable this share if the group is enabled but not
2419 2424 * otherwise. The enable is also done on each protocol
2420 2425 * represented in the group.
2421 2426 */
2422 2427 value = sa_get_group_attr(group, "state");
2423 2428 enabled = value != NULL && strcmp(value, "enabled") == 0;
2424 2429 if (value != NULL)
2425 2430 sa_free_attr_string(value);
2426 2431 /* remove legacy config if necessary */
2427 2432 if (update_legacy)
2428 2433 ret = sa_delete_legacy(share, NULL);
2429 2434 zfs = sa_get_group_attr(group, "zfs");
2430 2435 if (zfs != NULL) {
2431 2436 iszfs++;
2432 2437 sa_free_attr_string(zfs);
2433 2438 }
2434 2439
2435 2440 /*
2436 2441 * Step through each optionset at the group level and
2437 2442 * enable the share based on the protocol type. This
2438 2443 * works because protocols must be set on the group
2439 2444 * for the protocol to be enabled.
2440 2445 */
2441 2446 isshare = sa_is_share(share);
2442 2447 for (optionset = sa_get_optionset(group, NULL);
2443 2448 optionset != NULL && ret == SA_OK;
2444 2449 optionset = sa_get_next_optionset(optionset)) {
2445 2450 value = sa_get_optionset_attr(optionset, "type");
2446 2451 if (value != NULL) {
2447 2452 if (enabled) {
2448 2453 if (isshare) {
2449 2454 err = sa_enable_share(share, value);
2450 2455 } else {
2451 2456 err = sa_enable_resource(share, value);
2452 2457 if (err == SA_NOT_SUPPORTED) {
2453 2458 sa_share_t parent;
2454 2459 parent = sa_get_resource_parent(
2455 2460 share);
2456 2461 if (parent != NULL)
2457 2462 err = sa_enable_share(
2458 2463 parent, value);
2459 2464 }
2460 2465 }
2461 2466 if (err != SA_OK) {
2462 2467 ret = err;
2463 2468 (void) printf(gettext(
2464 2469 "Failed to enable share for "
2465 2470 "\"%s\": %s\n"),
2466 2471 value, sa_errorstr(ret));
2467 2472 }
2468 2473 }
2469 2474 /*
2470 2475 * If we want to update the legacy, use a copy of
2471 2476 * share so we can avoid breaking the loop we are in
2472 2477 * since we might also need to go up the tree to the
2473 2478 * parent.
2474 2479 */
2475 2480 if (update_legacy && !iszfs) {
2476 2481 sa_share_t update = share;
2477 2482 if (!sa_is_share(share)) {
2478 2483 update = sa_get_resource_parent(share);
2479 2484 }
2480 2485 (void) sa_update_legacy(update, value);
2481 2486 }
2482 2487 sa_free_attr_string(value);
2483 2488 }
2484 2489 }
2485 2490 if (ret == SA_OK)
2486 2491 (void) sa_update_config(handle);
2487 2492 return (ret);
2488 2493 }
2489 2494
2490 2495 /*
2491 2496 * sa_require_resource(group)
2492 2497 *
2493 2498 * if any of the defined protocols on the group require resource
2494 2499 * names, then all shares must have them.
2495 2500 */
2496 2501
2497 2502 static int
2498 2503 sa_require_resource(sa_group_t group)
2499 2504 {
2500 2505 sa_optionset_t optionset;
2501 2506
2502 2507 for (optionset = sa_get_optionset(group, NULL);
2503 2508 optionset != NULL;
2504 2509 optionset = sa_get_next_optionset(optionset)) {
2505 2510 char *proto;
2506 2511
2507 2512 proto = sa_get_optionset_attr(optionset, "type");
2508 2513 if (proto != NULL) {
2509 2514 uint64_t features;
2510 2515
2511 2516 features = sa_proto_get_featureset(proto);
2512 2517 if (features & SA_FEATURE_RESOURCE) {
2513 2518 sa_free_attr_string(proto);
2514 2519 return (B_TRUE);
2515 2520 }
2516 2521 sa_free_attr_string(proto);
2517 2522 }
2518 2523 }
2519 2524 return (B_FALSE);
2520 2525 }
2521 2526
2522 2527 /*
2523 2528 * sa_addshare(flags, argc, argv)
2524 2529 *
2525 2530 * implements add-share subcommand.
2526 2531 */
2527 2532
2528 2533 static int
2529 2534 sa_addshare(sa_handle_t handle, int flags, int argc, char *argv[])
2530 2535 {
2531 2536 int verbose = 0;
2532 2537 int dryrun = 0;
2533 2538 int c;
2534 2539 int ret = SA_OK;
2535 2540 sa_group_t group;
2536 2541 sa_share_t share;
2537 2542 sa_resource_t resource = NULL;
2538 2543 char *sharepath = NULL;
2539 2544 char *description = NULL;
2540 2545 char *rsrcname = NULL;
2541 2546 char *rsrc = NULL;
2542 2547 int persist = SA_SHARE_PERMANENT; /* default to persist */
2543 2548 int auth;
2544 2549 char dir[MAXPATHLEN];
2545 2550
2546 2551 while ((c = getopt(argc, argv, "?hvns:d:r:t")) != EOF) {
2547 2552 switch (c) {
2548 2553 case 'n':
2549 2554 dryrun++;
2550 2555 break;
2551 2556 case 'v':
2552 2557 verbose++;
2553 2558 break;
2554 2559 case 'd':
2555 2560 description = optarg;
2556 2561 break;
2557 2562 case 'r':
2558 2563 if (rsrcname != NULL) {
2559 2564 (void) printf(gettext("Adding multiple "
2560 2565 "resource names not"
2561 2566 " supported\n"));
2562 2567 return (SA_SYNTAX_ERR);
2563 2568 }
2564 2569 rsrcname = optarg;
2565 2570 break;
2566 2571 case 's':
2567 2572 /*
2568 2573 * Save share path into group. Currently limit
2569 2574 * to one share per command.
2570 2575 */
2571 2576 if (sharepath != NULL) {
2572 2577 (void) printf(gettext(
2573 2578 "Adding multiple shares not supported\n"));
2574 2579 return (SA_SYNTAX_ERR);
2575 2580 }
2576 2581 sharepath = optarg;
2577 2582 break;
2578 2583 case 't':
2579 2584 persist = SA_SHARE_TRANSIENT;
2580 2585 break;
2581 2586 case 'h':
2582 2587 /* optopt on valid arg isn't defined */
2583 2588 optopt = c;
2584 2589 /*FALLTHROUGH*/
2585 2590 case '?':
2586 2591 default:
2587 2592 /*
2588 2593 * Since a bad option gets to here, sort it
2589 2594 * out and return a syntax error return value
2590 2595 * if necessary.
2591 2596 */
2592 2597 switch (optopt) {
2593 2598 default:
2594 2599 ret = SA_SYNTAX_ERR;
2595 2600 break;
2596 2601 case 'h':
2597 2602 case '?':
2598 2603 break;
2599 2604 }
2600 2605 (void) printf(gettext("usage: %s\n"),
2601 2606 sa_get_usage(USAGE_ADD_SHARE));
2602 2607 return (ret);
2603 2608 }
2604 2609 }
2605 2610
2606 2611 if (optind >= argc) {
2607 2612 (void) printf(gettext("usage: %s\n"),
2608 2613 sa_get_usage(USAGE_ADD_SHARE));
2609 2614 if (dryrun || sharepath != NULL || description != NULL ||
2610 2615 rsrcname != NULL || verbose || persist) {
2611 2616 (void) printf(gettext("\tgroup must be specified\n"));
2612 2617 ret = SA_NO_SUCH_GROUP;
2613 2618 } else {
2614 2619 ret = SA_OK;
2615 2620 }
2616 2621 } else {
2617 2622 if (sharepath == NULL) {
2618 2623 (void) printf(gettext("usage: %s\n"),
2619 2624 sa_get_usage(USAGE_ADD_SHARE));
2620 2625 (void) printf(gettext(
2621 2626 "\t-s sharepath must be specified\n"));
2622 2627 ret = SA_BAD_PATH;
2623 2628 }
2624 2629 if (ret == SA_OK) {
2625 2630 if (realpath(sharepath, dir) == NULL) {
2626 2631 ret = SA_BAD_PATH;
2627 2632 (void) printf(gettext("Path "
2628 2633 "is not valid: %s\n"),
2629 2634 sharepath);
2630 2635 } else {
2631 2636 sharepath = dir;
2632 2637 }
2633 2638 }
2634 2639 if (ret == SA_OK && rsrcname != NULL) {
2635 2640 /* check for valid syntax */
2636 2641 if (validresource(rsrcname)) {
2637 2642 rsrc = conv_to_utf8(rsrcname);
2638 2643 resource = sa_find_resource(handle, rsrc);
2639 2644 if (resource != NULL) {
2640 2645 /*
2641 2646 * Resource names must be
2642 2647 * unique in the system
2643 2648 */
2644 2649 ret = SA_DUPLICATE_NAME;
2645 2650 (void) printf(gettext("usage: %s\n"),
2646 2651 sa_get_usage(USAGE_ADD_SHARE));
2647 2652 (void) printf(gettext(
2648 2653 "\tresource names must be unique "
2649 2654 "in the system\n"));
2650 2655 }
2651 2656 } else {
2652 2657 (void) printf(gettext("usage: %s\n"),
2653 2658 sa_get_usage(USAGE_ADD_SHARE));
2654 2659 (void) printf(gettext(
2655 2660 "\tresource names use restricted "
2656 2661 "character set\n"));
2657 2662 ret = SA_INVALID_NAME;
2658 2663 }
2659 2664 }
2660 2665
2661 2666 if (ret != SA_OK) {
2662 2667 if (rsrc != NULL && rsrcname != rsrc)
2663 2668 sa_free_attr_string(rsrc);
2664 2669 return (ret);
2665 2670 }
2666 2671
2667 2672 share = sa_find_share(handle, sharepath);
2668 2673 if (share != NULL) {
2669 2674 if (rsrcname == NULL) {
2670 2675 /*
2671 2676 * Can only have a duplicate share if a new
2672 2677 * resource name is being added.
2673 2678 */
2674 2679 ret = SA_DUPLICATE_NAME;
2675 2680 (void) printf(gettext("Share path already "
2676 2681 "shared: %s\n"), sharepath);
2677 2682 }
2678 2683 }
2679 2684 if (ret != SA_OK)
2680 2685 return (ret);
2681 2686
2682 2687 group = sa_get_group(handle, argv[optind]);
2683 2688 if (group != NULL) {
2684 2689 if (sa_require_resource(group) == B_TRUE &&
2685 2690 rsrcname == NULL) {
2686 2691 (void) printf(gettext(
2687 2692 "Resource name is required "
2688 2693 "by at least one enabled protocol "
2689 2694 "in group\n"));
2690 2695 return (SA_RESOURCE_REQUIRED);
2691 2696 }
2692 2697 if (share == NULL && ret == SA_OK) {
2693 2698 if (dryrun)
2694 2699 ret = sa_check_path(group, sharepath,
2695 2700 SA_CHECK_NORMAL);
2696 2701 else
2697 2702 share = sa_add_share(group, sharepath,
2698 2703 persist, &ret);
2699 2704 }
2700 2705 /*
2701 2706 * Make sure this isn't an attempt to put a resourced
2702 2707 * share into a different group than it already is in.
2703 2708 */
2704 2709 if (share != NULL) {
2705 2710 sa_group_t parent;
2706 2711 parent = sa_get_parent_group(share);
2707 2712 if (parent != group) {
2708 2713 ret = SA_DUPLICATE_NAME;
2709 2714 (void) printf(gettext(
2710 2715 "Share path already "
2711 2716 "shared: %s\n"), sharepath);
2712 2717 }
2713 2718 }
2714 2719 if (!dryrun && share == NULL) {
2715 2720 (void) printf(gettext(
2716 2721 "Could not add share: %s\n"),
2717 2722 sa_errorstr(ret));
2718 2723 } else {
2719 2724 auth = check_authorizations(argv[optind],
2720 2725 flags);
2721 2726 if (!dryrun && ret == SA_OK) {
2722 2727 if (rsrcname != NULL) {
2723 2728 resource = sa_add_resource(
2724 2729 share,
2725 2730 rsrc,
2726 2731 SA_SHARE_PERMANENT,
2727 2732 &ret);
2728 2733 }
2729 2734 if (ret == SA_OK &&
2730 2735 description != NULL) {
2731 2736 if (resource != NULL)
2732 2737 ret =
2733 2738 set_resource_desc(
2734 2739 resource,
2735 2740 description);
2736 2741 else
2737 2742 ret =
2738 2743 set_share_desc(
2739 2744 share,
2740 2745 description);
2741 2746 }
2742 2747 if (ret == SA_OK) {
2743 2748 /* now enable the share(s) */
2744 2749 if (resource != NULL) {
2745 2750 ret = enable_share(
2746 2751 handle,
2747 2752 group,
2748 2753 resource,
2749 2754 1);
2750 2755 } else {
2751 2756 ret = enable_share(
2752 2757 handle,
2753 2758 group,
2754 2759 share,
2755 2760 1);
2756 2761 }
2757 2762 ret = sa_update_config(handle);
2758 2763 }
2759 2764 switch (ret) {
2760 2765 case SA_DUPLICATE_NAME:
2761 2766 (void) printf(gettext(
2762 2767 "Resource name in"
2763 2768 "use: %s\n"),
2764 2769 rsrcname);
2765 2770 break;
2766 2771 default:
2767 2772 (void) printf(gettext(
2768 2773 "Could not set "
2769 2774 "attribute: %s\n"),
2770 2775 sa_errorstr(ret));
2771 2776 break;
2772 2777 case SA_OK:
2773 2778 break;
2774 2779 }
2775 2780 } else if (dryrun && ret == SA_OK &&
2776 2781 !auth && verbose) {
2777 2782 (void) printf(gettext(
2778 2783 "Command would fail: %s\n"),
2779 2784 sa_errorstr(SA_NO_PERMISSION));
2780 2785 ret = SA_NO_PERMISSION;
2781 2786 }
2782 2787 }
2783 2788 } else {
2784 2789 switch (ret) {
2785 2790 default:
2786 2791 (void) printf(gettext(
2787 2792 "Group \"%s\" not found\n"), argv[optind]);
2788 2793 ret = SA_NO_SUCH_GROUP;
2789 2794 break;
2790 2795 case SA_BAD_PATH:
2791 2796 case SA_DUPLICATE_NAME:
2792 2797 break;
2793 2798 }
2794 2799 }
2795 2800 }
2796 2801 return (ret);
2797 2802 }
2798 2803
2799 2804 /*
2800 2805 * sa_moveshare(flags, argc, argv)
2801 2806 *
2802 2807 * implements move-share subcommand.
2803 2808 */
2804 2809
2805 2810 int
2806 2811 sa_moveshare(sa_handle_t handle, int flags, int argc, char *argv[])
2807 2812 {
2808 2813 int verbose = 0;
2809 2814 int dryrun = 0;
2810 2815 int c;
2811 2816 int ret = SA_OK;
2812 2817 sa_group_t group;
2813 2818 sa_share_t share;
2814 2819 char *rsrcname = NULL;
2815 2820 char *sharepath = NULL;
2816 2821 int authsrc = 0, authdst = 0;
2817 2822 char dir[MAXPATHLEN];
2818 2823
2819 2824 while ((c = getopt(argc, argv, "?hvnr:s:")) != EOF) {
2820 2825 switch (c) {
2821 2826 case 'n':
2822 2827 dryrun++;
2823 2828 break;
2824 2829 case 'v':
2825 2830 verbose++;
2826 2831 break;
2827 2832 case 'r':
2828 2833 if (rsrcname != NULL) {
2829 2834 (void) printf(gettext(
2830 2835 "Moving multiple resource names not"
2831 2836 " supported\n"));
2832 2837 return (SA_SYNTAX_ERR);
2833 2838 }
2834 2839 rsrcname = optarg;
2835 2840 break;
2836 2841 case 's':
2837 2842 /*
2838 2843 * Remove share path from group. Currently limit
2839 2844 * to one share per command.
2840 2845 */
2841 2846 if (sharepath != NULL) {
2842 2847 (void) printf(gettext("Moving multiple shares"
2843 2848 " not supported\n"));
2844 2849 return (SA_SYNTAX_ERR);
2845 2850 }
2846 2851 sharepath = optarg;
2847 2852 break;
2848 2853 case 'h':
2849 2854 /* optopt on valid arg isn't defined */
2850 2855 optopt = c;
2851 2856 /*FALLTHROUGH*/
2852 2857 case '?':
2853 2858 default:
2854 2859 /*
2855 2860 * Since a bad option gets to here, sort it
2856 2861 * out and return a syntax error return value
2857 2862 * if necessary.
2858 2863 */
2859 2864 switch (optopt) {
2860 2865 default:
2861 2866 ret = SA_SYNTAX_ERR;
2862 2867 break;
2863 2868 case 'h':
2864 2869 case '?':
2865 2870 break;
2866 2871 }
2867 2872 (void) printf(gettext("usage: %s\n"),
2868 2873 sa_get_usage(USAGE_MOVE_SHARE));
2869 2874 return (ret);
2870 2875 }
2871 2876 }
2872 2877
2873 2878 if (optind >= argc || sharepath == NULL) {
2874 2879 (void) printf(gettext("usage: %s\n"),
2875 2880 sa_get_usage(USAGE_MOVE_SHARE));
2876 2881 if (dryrun || verbose || sharepath != NULL) {
2877 2882 (void) printf(gettext("\tgroup must be specified\n"));
2878 2883 ret = SA_NO_SUCH_GROUP;
2879 2884 } else {
2880 2885 if (sharepath == NULL) {
2881 2886 ret = SA_SYNTAX_ERR;
2882 2887 (void) printf(gettext(
2883 2888 "\tsharepath must be specified\n"));
2884 2889 } else {
2885 2890 ret = SA_OK;
2886 2891 }
2887 2892 }
2888 2893 } else {
2889 2894 sa_group_t parent;
2890 2895 char *zfsold;
2891 2896 char *zfsnew;
2892 2897
2893 2898 if (sharepath == NULL) {
2894 2899 (void) printf(gettext(
2895 2900 "sharepath must be specified with the -s "
2896 2901 "option\n"));
2897 2902 return (SA_BAD_PATH);
2898 2903 }
2899 2904 group = sa_get_group(handle, argv[optind]);
2900 2905 if (group == NULL) {
2901 2906 (void) printf(gettext("Group \"%s\" not found\n"),
2902 2907 argv[optind]);
2903 2908 return (SA_NO_SUCH_GROUP);
2904 2909 }
2905 2910 share = sa_find_share(handle, sharepath);
2906 2911 /*
2907 2912 * If a share wasn't found, it may have been a symlink
2908 2913 * or has a trailing '/'. Try again after resolving
2909 2914 * with realpath().
2910 2915 */
2911 2916 if (share == NULL) {
2912 2917 if (realpath(sharepath, dir) == NULL) {
2913 2918 (void) printf(gettext("Path "
2914 2919 "is not valid: %s\n"),
2915 2920 sharepath);
2916 2921 return (SA_BAD_PATH);
2917 2922 }
2918 2923 sharepath = dir;
2919 2924 share = sa_find_share(handle, sharepath);
2920 2925 }
2921 2926 if (share == NULL) {
2922 2927 (void) printf(gettext("Share not found: %s\n"),
2923 2928 sharepath);
2924 2929 return (SA_NO_SUCH_PATH);
2925 2930 }
2926 2931 authdst = check_authorizations(argv[optind], flags);
2927 2932
2928 2933 parent = sa_get_parent_group(share);
2929 2934 if (parent != NULL) {
2930 2935 char *pname;
2931 2936 pname = sa_get_group_attr(parent, "name");
2932 2937 if (pname != NULL) {
2933 2938 authsrc = check_authorizations(pname, flags);
2934 2939 sa_free_attr_string(pname);
2935 2940 }
2936 2941 zfsold = sa_get_group_attr(parent, "zfs");
2937 2942 zfsnew = sa_get_group_attr(group, "zfs");
2938 2943 if ((zfsold != NULL && zfsnew == NULL) ||
2939 2944 (zfsold == NULL && zfsnew != NULL)) {
2940 2945 ret = SA_NOT_ALLOWED;
2941 2946 }
2942 2947 if (zfsold != NULL)
2943 2948 sa_free_attr_string(zfsold);
2944 2949 if (zfsnew != NULL)
2945 2950 sa_free_attr_string(zfsnew);
2946 2951 }
2947 2952
2948 2953 if (ret == SA_OK && parent != group && !dryrun) {
2949 2954 char *oldstate;
2950 2955 /*
2951 2956 * Note that the share may need to be
2952 2957 * "unshared" if the new group is disabled and
2953 2958 * the old was enabled or it may need to be
2954 2959 * share to update if the new group is
2955 2960 * enabled. We disable before the move and
2956 2961 * will have to enable after the move in order
2957 2962 * to cleanup entries for protocols that
2958 2963 * aren't in the new group.
2959 2964 */
2960 2965 oldstate = sa_get_group_attr(parent, "state");
2961 2966 if (oldstate != NULL) {
2962 2967 /* enable_share determines what to do */
2963 2968 if (strcmp(oldstate, "enabled") == 0)
2964 2969 (void) sa_disable_share(share, NULL);
2965 2970 sa_free_attr_string(oldstate);
2966 2971 }
2967 2972 }
2968 2973
2969 2974 if (!dryrun && ret == SA_OK)
2970 2975 ret = sa_move_share(group, share);
2971 2976
2972 2977 /*
2973 2978 * Reenable and update any config information.
2974 2979 */
2975 2980 if (ret == SA_OK && parent != group && !dryrun) {
2976 2981 ret = sa_update_config(handle);
2977 2982
2978 2983 (void) enable_share(handle, group, share, 1);
2979 2984 }
2980 2985
2981 2986 if (ret != SA_OK)
2982 2987 (void) printf(gettext("Could not move share: %s\n"),
2983 2988 sa_errorstr(ret));
2984 2989
2985 2990 if (dryrun && ret == SA_OK && !(authsrc & authdst) &&
2986 2991 verbose) {
2987 2992 (void) printf(gettext("Command would fail: %s\n"),
2988 2993 sa_errorstr(SA_NO_PERMISSION));
2989 2994 }
2990 2995 }
2991 2996 return (ret);
2992 2997 }
2993 2998
2994 2999 /*
2995 3000 * sa_removeshare(flags, argc, argv)
2996 3001 *
2997 3002 * implements remove-share subcommand.
2998 3003 */
2999 3004
3000 3005 int
3001 3006 sa_removeshare(sa_handle_t handle, int flags, int argc, char *argv[])
3002 3007 {
3003 3008 int verbose = 0;
3004 3009 int dryrun = 0;
3005 3010 int force = 0;
3006 3011 int c;
3007 3012 int ret = SA_OK;
3008 3013 sa_group_t group;
3009 3014 sa_resource_t resource = NULL;
3010 3015 sa_share_t share = NULL;
3011 3016 char *rsrcname = NULL;
3012 3017 char *sharepath = NULL;
3013 3018 char dir[MAXPATHLEN];
3014 3019 int auth;
3015 3020
3016 3021 while ((c = getopt(argc, argv, "?hfnr:s:v")) != EOF) {
3017 3022 switch (c) {
3018 3023 case 'n':
3019 3024 dryrun++;
3020 3025 break;
3021 3026 case 'v':
3022 3027 verbose++;
3023 3028 break;
3024 3029 case 'f':
3025 3030 force++;
3026 3031 break;
3027 3032 case 's':
3028 3033 /*
3029 3034 * Remove share path from group. Currently limit
3030 3035 * to one share per command.
3031 3036 */
3032 3037 if (sharepath != NULL) {
3033 3038 (void) printf(gettext(
3034 3039 "Removing multiple shares not "
3035 3040 "supported\n"));
3036 3041 return (SA_SYNTAX_ERR);
3037 3042 }
3038 3043 sharepath = optarg;
3039 3044 break;
3040 3045 case 'r':
3041 3046 /*
3042 3047 * Remove share from group if last resource or remove
3043 3048 * resource from share if multiple resources.
3044 3049 */
3045 3050 if (rsrcname != NULL) {
3046 3051 (void) printf(gettext(
3047 3052 "Removing multiple resource names not "
3048 3053 "supported\n"));
3049 3054 return (SA_SYNTAX_ERR);
3050 3055 }
3051 3056 rsrcname = optarg;
3052 3057 break;
3053 3058 case 'h':
3054 3059 /* optopt on valid arg isn't defined */
3055 3060 optopt = c;
3056 3061 /*FALLTHROUGH*/
3057 3062 case '?':
3058 3063 default:
3059 3064 /*
3060 3065 * Since a bad option gets to here, sort it
3061 3066 * out and return a syntax error return value
3062 3067 * if necessary.
3063 3068 */
3064 3069 switch (optopt) {
3065 3070 default:
3066 3071 ret = SA_SYNTAX_ERR;
3067 3072 break;
3068 3073 case 'h':
3069 3074 case '?':
3070 3075 break;
3071 3076 }
3072 3077 (void) printf(gettext("usage: %s\n"),
3073 3078 sa_get_usage(USAGE_REMOVE_SHARE));
3074 3079 return (ret);
3075 3080 }
3076 3081 }
3077 3082
3078 3083 if (optind >= argc || (rsrcname == NULL && sharepath == NULL)) {
3079 3084 if (sharepath == NULL && rsrcname == NULL) {
3080 3085 (void) printf(gettext("usage: %s\n"),
3081 3086 sa_get_usage(USAGE_REMOVE_SHARE));
3082 3087 (void) printf(gettext("\t-s sharepath or -r resource"
3083 3088 " must be specified\n"));
3084 3089 ret = SA_BAD_PATH;
3085 3090 } else {
3086 3091 ret = SA_OK;
3087 3092 }
3088 3093 }
3089 3094 if (ret != SA_OK) {
3090 3095 return (ret);
3091 3096 }
3092 3097
3093 3098 if (optind < argc) {
3094 3099 if ((optind + 1) < argc) {
3095 3100 (void) printf(gettext("Extraneous group(s) at end of "
3096 3101 "command\n"));
3097 3102 ret = SA_SYNTAX_ERR;
3098 3103 } else {
3099 3104 group = sa_get_group(handle, argv[optind]);
3100 3105 if (group == NULL) {
3101 3106 (void) printf(gettext(
3102 3107 "Group \"%s\" not found\n"), argv[optind]);
3103 3108 ret = SA_NO_SUCH_GROUP;
3104 3109 }
3105 3110 }
3106 3111 } else {
3107 3112 group = NULL;
3108 3113 }
3109 3114
3110 3115 if (rsrcname != NULL) {
3111 3116 resource = sa_find_resource(handle, rsrcname);
3112 3117 if (resource == NULL) {
3113 3118 ret = SA_NO_SUCH_RESOURCE;
3114 3119 (void) printf(gettext(
3115 3120 "Resource name not found for share: %s\n"),
3116 3121 rsrcname);
3117 3122 }
3118 3123 }
3119 3124
3120 3125 /*
3121 3126 * Lookup the path in the internal configuration. Care
3122 3127 * must be taken to handle the case where the
3123 3128 * underlying path has been removed since we need to
3124 3129 * be able to deal with that as well.
3125 3130 */
3126 3131 if (ret == SA_OK) {
3127 3132 if (sharepath != NULL) {
3128 3133 if (group != NULL)
3129 3134 share = sa_get_share(group, sharepath);
3130 3135 else
3131 3136 share = sa_find_share(handle, sharepath);
3132 3137 }
3133 3138
3134 3139 if (resource != NULL) {
3135 3140 sa_share_t rsrcshare;
3136 3141 rsrcshare = sa_get_resource_parent(resource);
3137 3142 if (share == NULL)
3138 3143 share = rsrcshare;
3139 3144 else if (share != rsrcshare) {
3140 3145 ret = SA_NO_SUCH_RESOURCE;
3141 3146 (void) printf(gettext(
3142 3147 "Bad resource name for share: %s\n"),
3143 3148 rsrcname);
3144 3149 share = NULL;
3145 3150 }
3146 3151 }
3147 3152
3148 3153 /*
3149 3154 * If we didn't find the share with the provided path,
3150 3155 * it may be a symlink so attempt to resolve it using
3151 3156 * realpath and try again. Realpath will resolve any
3152 3157 * symlinks and place them in "dir". Note that
3153 3158 * sharepath is only used for the lookup the first
3154 3159 * time and later for error messages. dir will be used
3155 3160 * on the second attempt. Once a share is found, all
3156 3161 * operations are based off of the share variable.
3157 3162 */
3158 3163 if (share == NULL) {
3159 3164 if (realpath(sharepath, dir) == NULL) {
3160 3165 ret = SA_BAD_PATH;
3161 3166 (void) printf(gettext(
3162 3167 "Path is not valid: %s\n"), sharepath);
3163 3168 } else {
3164 3169 if (group != NULL)
3165 3170 share = sa_get_share(group, dir);
3166 3171 else
3167 3172 share = sa_find_share(handle, dir);
3168 3173 }
3169 3174 }
3170 3175 }
3171 3176
3172 3177 /*
3173 3178 * If there hasn't been an error, there was likely a
3174 3179 * path found. If not, give the appropriate error
3175 3180 * message and set the return error. If it was found,
3176 3181 * then disable the share and then remove it from the
3177 3182 * configuration.
3178 3183 */
3179 3184 if (ret != SA_OK) {
3180 3185 return (ret);
3181 3186 }
3182 3187 if (share == NULL) {
3183 3188 if (group != NULL)
3184 3189 (void) printf(gettext("Share not found in group %s:"
3185 3190 " %s\n"), argv[optind], sharepath);
3186 3191 else
3187 3192 (void) printf(gettext("Share not found: %s\n"),
3188 3193 sharepath);
3189 3194 ret = SA_NO_SUCH_PATH;
3190 3195 } else {
3191 3196 if (group == NULL)
3192 3197 group = sa_get_parent_group(share);
3193 3198 if (!dryrun) {
3194 3199 if (ret == SA_OK) {
3195 3200 if (resource != NULL)
3196 3201 ret = sa_disable_resource(resource,
3197 3202 NULL);
3198 3203 else
3199 3204 ret = sa_disable_share(share, NULL);
3200 3205 /*
3201 3206 * We don't care if it fails since it
3202 3207 * could be disabled already. Some
3203 3208 * unexpected errors could occur that
3204 3209 * prevent removal, so also check for
3205 3210 * force being set.
3206 3211 */
3207 3212 if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
3208 3213 ret == SA_NOT_SUPPORTED ||
3209 3214 ret == SA_SYSTEM_ERR || force) &&
3210 3215 resource == NULL)
3211 3216 ret = sa_remove_share(share);
3212 3217
3213 3218 if ((ret == SA_OK || ret == SA_NO_SUCH_PATH ||
3214 3219 ret == SA_NOT_SUPPORTED ||
3215 3220 ret == SA_SYSTEM_ERR || force) &&
3216 3221 resource != NULL) {
3217 3222 ret = sa_remove_resource(resource);
3218 3223 if (ret == SA_OK) {
3219 3224 /*
3220 3225 * If this was the
3221 3226 * last one, remove
3222 3227 * the share as well.
3223 3228 */
3224 3229 resource =
3225 3230 sa_get_share_resource(
3226 3231 share, NULL);
3227 3232 if (resource == NULL)
3228 3233 ret = sa_remove_share(
3229 3234 share);
3230 3235 }
3231 3236 }
3232 3237 if (ret == SA_OK)
3233 3238 ret = sa_update_config(handle);
3234 3239 }
3235 3240 if (ret != SA_OK)
3236 3241 (void) printf(gettext("Could not remove share:"
3237 3242 " %s\n"), sa_errorstr(ret));
3238 3243 } else if (ret == SA_OK) {
3239 3244 char *pname;
3240 3245 pname = sa_get_group_attr(group, "name");
3241 3246 if (pname != NULL) {
3242 3247 auth = check_authorizations(pname, flags);
3243 3248 sa_free_attr_string(pname);
3244 3249 }
3245 3250 if (!auth && verbose) {
3246 3251 (void) printf(gettext(
3247 3252 "Command would fail: %s\n"),
3248 3253 sa_errorstr(SA_NO_PERMISSION));
3249 3254 }
3250 3255 }
3251 3256 }
3252 3257 return (ret);
3253 3258 }
3254 3259
3255 3260 /*
3256 3261 * sa_set_share(flags, argc, argv)
3257 3262 *
3258 3263 * implements set-share subcommand.
3259 3264 */
3260 3265
3261 3266 int
3262 3267 sa_set_share(sa_handle_t handle, int flags, int argc, char *argv[])
3263 3268 {
3264 3269 int dryrun = 0;
3265 3270 int c;
3266 3271 int ret = SA_OK;
3267 3272 sa_group_t group, sharegroup;
3268 3273 sa_share_t share = NULL;
3269 3274 sa_resource_t resource = NULL;
3270 3275 char *sharepath = NULL;
3271 3276 char *description = NULL;
3272 3277 char *rsrcname = NULL;
3273 3278 char *rsrc = NULL;
3274 3279 char *newname = NULL;
3275 3280 char *newrsrc;
3276 3281 char *groupname = NULL;
3277 3282 int auth;
3278 3283 int verbose = 0;
3279 3284
3280 3285 while ((c = getopt(argc, argv, "?hnd:r:s:")) != EOF) {
3281 3286 switch (c) {
3282 3287 case 'n':
3283 3288 dryrun++;
3284 3289 break;
3285 3290 case 'd':
3286 3291 description = optarg;
3287 3292 break;
3288 3293 case 'v':
3289 3294 verbose++;
3290 3295 break;
3291 3296 case 'r':
3292 3297 /*
3293 3298 * Update share by resource name
3294 3299 */
3295 3300 if (rsrcname != NULL) {
3296 3301 (void) printf(gettext(
3297 3302 "Updating multiple resource names not "
3298 3303 "supported\n"));
3299 3304 return (SA_SYNTAX_ERR);
3300 3305 }
3301 3306 rsrcname = optarg;
3302 3307 break;
3303 3308 case 's':
3304 3309 /*
3305 3310 * Save share path into group. Currently limit
3306 3311 * to one share per command.
3307 3312 */
3308 3313 if (sharepath != NULL) {
3309 3314 (void) printf(gettext(
3310 3315 "Updating multiple shares not "
3311 3316 "supported\n"));
3312 3317 return (SA_SYNTAX_ERR);
3313 3318 }
3314 3319 sharepath = optarg;
3315 3320 break;
3316 3321 case 'h':
3317 3322 /* optopt on valid arg isn't defined */
3318 3323 optopt = c;
3319 3324 /*FALLTHROUGH*/
3320 3325 case '?':
3321 3326 default:
3322 3327 /*
3323 3328 * Since a bad option gets to here, sort it
3324 3329 * out and return a syntax error return value
3325 3330 * if necessary.
3326 3331 */
3327 3332 switch (optopt) {
3328 3333 default:
3329 3334 ret = SA_SYNTAX_ERR;
3330 3335 break;
3331 3336 case 'h':
3332 3337 case '?':
3333 3338 break;
3334 3339 }
3335 3340 (void) printf(gettext("usage: %s\n"),
3336 3341 sa_get_usage(USAGE_SET_SHARE));
3337 3342 return (ret);
3338 3343 }
3339 3344 }
3340 3345
3341 3346 if (optind >= argc && sharepath == NULL && rsrcname == NULL) {
3342 3347 if (sharepath == NULL) {
3343 3348 (void) printf(gettext("usage: %s\n"),
3344 3349 sa_get_usage(USAGE_SET_SHARE));
3345 3350 (void) printf(gettext("\tgroup must be specified\n"));
3346 3351 ret = SA_BAD_PATH;
3347 3352 } else {
3348 3353 ret = SA_OK;
3349 3354 }
3350 3355 }
3351 3356 if ((optind + 1) < argc) {
3352 3357 (void) printf(gettext("usage: %s\n"),
3353 3358 sa_get_usage(USAGE_SET_SHARE));
3354 3359 (void) printf(gettext("\tExtraneous group(s) at end\n"));
3355 3360 ret = SA_SYNTAX_ERR;
3356 3361 }
3357 3362
3358 3363 /*
3359 3364 * Must have at least one of sharepath and rsrcrname.
3360 3365 * It is a syntax error to be missing both.
3361 3366 */
3362 3367 if (sharepath == NULL && rsrcname == NULL) {
3363 3368 (void) printf(gettext("usage: %s\n"),
3364 3369 sa_get_usage(USAGE_SET_SHARE));
3365 3370 ret = SA_SYNTAX_ERR;
3366 3371 }
3367 3372
3368 3373 if (ret != SA_OK)
3369 3374 return (ret);
3370 3375
3371 3376 if (optind < argc) {
3372 3377 groupname = argv[optind];
3373 3378 group = sa_get_group(handle, groupname);
3374 3379 } else {
3375 3380 group = NULL;
3376 3381 groupname = NULL;
3377 3382 }
3378 3383 if (rsrcname != NULL) {
3379 3384 /*
3380 3385 * If rsrcname exists, split rename syntax and then
3381 3386 * convert to utf 8 if no errors.
3382 3387 */
3383 3388 newname = strchr(rsrcname, '=');
3384 3389 if (newname != NULL) {
3385 3390 *newname++ = '\0';
3386 3391 }
3387 3392 if (!validresource(rsrcname)) {
3388 3393 ret = SA_INVALID_NAME;
3389 3394 (void) printf(gettext("Invalid resource name: "
3390 3395 "\"%s\"\n"), rsrcname);
3391 3396 } else {
3392 3397 rsrc = conv_to_utf8(rsrcname);
3393 3398 }
3394 3399 if (newname != NULL) {
3395 3400 if (!validresource(newname)) {
3396 3401 ret = SA_INVALID_NAME;
3397 3402 (void) printf(gettext("Invalid resource name: "
3398 3403 "%s\n"), newname);
3399 3404 newname = NULL;
3400 3405 } else {
3401 3406 newrsrc = conv_to_utf8(newname);
3402 3407 }
3403 3408 }
3404 3409 }
3405 3410
3406 3411 if (ret != SA_OK) {
3407 3412 if (rsrcname != NULL && rsrcname != rsrc)
3408 3413 sa_free_attr_string(rsrc);
3409 3414 if (newname != NULL && newname != newrsrc)
3410 3415 sa_free_attr_string(newrsrc);
3411 3416 return (ret);
3412 3417 }
3413 3418
3414 3419 if (sharepath != NULL) {
3415 3420 share = sa_find_share(handle, sharepath);
3416 3421 } else if (rsrcname != NULL) {
3417 3422 resource = sa_find_resource(handle, rsrc);
3418 3423 if (resource != NULL)
3419 3424 share = sa_get_resource_parent(resource);
3420 3425 else
3421 3426 ret = SA_NO_SUCH_RESOURCE;
3422 3427 }
3423 3428 if (share != NULL) {
3424 3429 sharegroup = sa_get_parent_group(share);
3425 3430 if (group != NULL && group != sharegroup) {
3426 3431 (void) printf(gettext("Group \"%s\" does not contain "
3427 3432 "share %s\n"),
3428 3433 argv[optind], sharepath);
3429 3434 ret = SA_BAD_PATH;
3430 3435 } else {
3431 3436 int delgroupname = 0;
3432 3437 if (groupname == NULL) {
3433 3438 groupname = sa_get_group_attr(sharegroup,
3434 3439 "name");
3435 3440 delgroupname = 1;
3436 3441 }
3437 3442 if (groupname != NULL) {
3438 3443 auth = check_authorizations(groupname, flags);
3439 3444 if (delgroupname) {
3440 3445 sa_free_attr_string(groupname);
3441 3446 groupname = NULL;
3442 3447 }
3443 3448 } else {
3444 3449 ret = SA_NO_MEMORY;
3445 3450 }
3446 3451 if (rsrcname != NULL) {
3447 3452 resource = sa_find_resource(handle, rsrc);
3448 3453 if (!dryrun) {
3449 3454 if (newname != NULL &&
3450 3455 resource != NULL)
3451 3456 ret = sa_rename_resource(
3452 3457 resource, newrsrc);
3453 3458 else if (newname != NULL)
3454 3459 ret = SA_NO_SUCH_RESOURCE;
3455 3460 if (newname != NULL &&
3456 3461 newname != newrsrc)
3457 3462 sa_free_attr_string(newrsrc);
3458 3463 }
3459 3464 if (rsrc != rsrcname)
3460 3465 sa_free_attr_string(rsrc);
3461 3466 }
3462 3467
3463 3468 /*
3464 3469 * If the user has set a description, it will be
3465 3470 * on the resource if -r was used otherwise it
3466 3471 * must be on the share.
3467 3472 */
3468 3473 if (!dryrun && ret == SA_OK && description != NULL) {
3469 3474 char *desc;
3470 3475 desc = conv_to_utf8(description);
3471 3476 if (resource != NULL)
3472 3477 ret = sa_set_resource_description(
3473 3478 resource, desc);
3474 3479 else
3475 3480 ret = sa_set_share_description(share,
3476 3481 desc);
3477 3482 if (desc != description)
3478 3483 sa_free_share_description(desc);
3479 3484 }
3480 3485 }
3481 3486 if (!dryrun && ret == SA_OK) {
3482 3487 if (resource != NULL)
3483 3488 (void) sa_enable_resource(resource, NULL);
3484 3489 ret = sa_update_config(handle);
3485 3490 }
3486 3491 switch (ret) {
3487 3492 case SA_DUPLICATE_NAME:
3488 3493 (void) printf(gettext("Resource name in use: %s\n"),
3489 3494 rsrcname);
3490 3495 break;
3491 3496 default:
3492 3497 (void) printf(gettext("Could not set: %s\n"),
3493 3498 sa_errorstr(ret));
3494 3499 break;
3495 3500 case SA_OK:
3496 3501 if (dryrun && !auth && verbose) {
3497 3502 (void) printf(gettext(
3498 3503 "Command would fail: %s\n"),
3499 3504 sa_errorstr(SA_NO_PERMISSION));
3500 3505 }
3501 3506 break;
3502 3507 }
3503 3508 } else {
3504 3509 switch (ret) {
3505 3510 case SA_NO_SUCH_RESOURCE:
3506 3511 (void) printf(gettext("Resource \"%s\" not found\n"),
3507 3512 rsrcname);
3508 3513 break;
3509 3514 default:
3510 3515 if (sharepath != NULL) {
3511 3516 (void) printf(
3512 3517 gettext("Share path \"%s\" not found\n"),
3513 3518 sharepath);
3514 3519 ret = SA_NO_SUCH_PATH;
3515 3520 } else {
3516 3521 (void) printf(gettext("Set failed: %s\n"),
3517 3522 sa_errorstr(ret));
3518 3523 }
3519 3524 }
3520 3525 }
3521 3526
3522 3527 return (ret);
3523 3528 }
3524 3529
3525 3530 /*
3526 3531 * add_security(group, sectype, optlist, proto, *err)
3527 3532 *
3528 3533 * Helper function to add a security option (named optionset) to the
3529 3534 * group.
3530 3535 */
3531 3536
3532 3537 static int
3533 3538 add_security(sa_group_t group, char *sectype,
3534 3539 struct options *optlist, char *proto, int *err)
3535 3540 {
3536 3541 sa_security_t security;
3537 3542 int ret = SA_OK;
3538 3543 int result = 0;
3539 3544 sa_handle_t handle;
3540 3545
3541 3546 sectype = sa_proto_space_alias(proto, sectype);
3542 3547 security = sa_get_security(group, sectype, proto);
3543 3548 if (security == NULL)
3544 3549 security = sa_create_security(group, sectype, proto);
3545 3550
3546 3551 if (sectype != NULL)
3547 3552 sa_free_attr_string(sectype);
3548 3553
3549 3554 if (security == NULL)
3550 3555 goto done;
3551 3556
3552 3557 handle = sa_find_group_handle(group);
3553 3558 if (handle == NULL) {
3554 3559 ret = SA_CONFIG_ERR;
3555 3560 goto done;
3556 3561 }
3557 3562 while (optlist != NULL) {
3558 3563 sa_property_t prop;
3559 3564 prop = sa_get_property(security, optlist->optname);
3560 3565 if (prop == NULL) {
3561 3566 /*
3562 3567 * Add the property, but only if it is
3563 3568 * a non-NULL or non-zero length value
3564 3569 */
3565 3570 if (optlist->optvalue != NULL) {
3566 3571 prop = sa_create_property(optlist->optname,
3567 3572 optlist->optvalue);
3568 3573 if (prop != NULL) {
3569 3574 ret = sa_valid_property(handle,
3570 3575 security, proto, prop);
3571 3576 if (ret != SA_OK) {
3572 3577 (void) sa_remove_property(prop);
3573 3578 (void) printf(gettext(
3574 3579 "Could not add "
3575 3580 "property %s: %s\n"),
3576 3581 optlist->optname,
3577 3582 sa_errorstr(ret));
3578 3583 }
3579 3584 if (ret == SA_OK) {
3580 3585 ret = sa_add_property(security,
3581 3586 prop);
3582 3587 if (ret != SA_OK) {
3583 3588 (void) printf(gettext(
3584 3589 "Could not add "
3585 3590 "property (%s=%s):"
3586 3591 " %s\n"),
3587 3592 optlist->optname,
3588 3593 optlist->optvalue,
3589 3594 sa_errorstr(ret));
3590 3595 } else {
3591 3596 result = 1;
3592 3597 }
3593 3598 }
3594 3599 }
3595 3600 }
3596 3601 } else {
3597 3602 ret = sa_update_property(prop, optlist->optvalue);
3598 3603 result = 1; /* should check if really changed */
3599 3604 }
3600 3605 optlist = optlist->next;
3601 3606 }
3602 3607 /*
3603 3608 * When done, properties may have all been removed but
3604 3609 * we need to keep the security type itself until
3605 3610 * explicitly removed.
3606 3611 */
3607 3612 if (result)
3608 3613 ret = sa_commit_properties(security, 0);
3609 3614 done:
3610 3615 *err = ret;
3611 3616 return (result);
3612 3617 }
3613 3618
3614 3619 /*
3615 3620 * zfscheck(group, share)
3616 3621 *
3617 3622 * For the special case where a share was provided, make sure it is a
3618 3623 * compatible path for a ZFS property change. The only path
3619 3624 * acceptable is the path that defines the zfs sub-group (dataset with
3620 3625 * the sharenfs property set) and not one of the paths that inherited
3621 3626 * the NFS properties. Returns SA_OK if it is usable and
3622 3627 * SA_NOT_ALLOWED if it isn't.
3623 3628 *
3624 3629 * If group is not a ZFS group/subgroup, we assume OK since the check
3625 3630 * on return will catch errors for those cases. What we are looking
3626 3631 * for here is that the group is ZFS and the share is not the defining
3627 3632 * share. All else is SA_OK.
3628 3633 */
3629 3634
3630 3635 static int
3631 3636 zfscheck(sa_group_t group, sa_share_t share)
3632 3637 {
3633 3638 int ret = SA_OK;
3634 3639 char *attr;
3635 3640
3636 3641 if (sa_group_is_zfs(group)) {
3637 3642 /*
3638 3643 * The group is a ZFS group. Does the share represent
3639 3644 * the dataset that defined the group? It is only OK
3640 3645 * if the attribute "subgroup" exists on the share and
3641 3646 * has a value of "true".
3642 3647 */
3643 3648
3644 3649 ret = SA_NOT_ALLOWED;
3645 3650 attr = sa_get_share_attr(share, "subgroup");
3646 3651 if (attr != NULL) {
3647 3652 if (strcmp(attr, "true") == 0)
3648 3653 ret = SA_OK;
3649 3654 sa_free_attr_string(attr);
3650 3655 }
3651 3656 }
3652 3657 return (ret);
3653 3658 }
3654 3659
3655 3660 /*
3656 3661 * basic_set(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
3657 3662 *
3658 3663 * This function implements "set" when a name space (-S) is not
3659 3664 * specified. It is a basic set. Options and other CLI parsing has
3660 3665 * already been done.
3661 3666 *
3662 3667 * "rsrcname" is a "resource name". If it is non-NULL, it must match
3663 3668 * the sharepath if present or group if present, otherwise it is used
3664 3669 * to set options.
3665 3670 *
3666 3671 * Resource names may take options if the protocol supports it. If the
3667 3672 * protocol doesn't support resource level options, rsrcname is just
3668 3673 * an alias for the share.
3669 3674 */
3670 3675
3671 3676 static int
3672 3677 basic_set(sa_handle_t handle, char *groupname, struct options *optlist,
3673 3678 char *protocol, char *sharepath, char *rsrcname, int dryrun)
3674 3679 {
3675 3680 sa_group_t group;
3676 3681 int ret = SA_OK;
3677 3682 int change = 0;
3678 3683 struct list *worklist = NULL;
3679 3684
3680 3685 group = sa_get_group(handle, groupname);
3681 3686 if (group != NULL) {
3682 3687 sa_share_t share = NULL;
3683 3688 sa_resource_t resource = NULL;
3684 3689
3685 3690 /*
3686 3691 * If there is a sharepath, make sure it belongs to
3687 3692 * the group.
3688 3693 */
3689 3694 if (sharepath != NULL) {
3690 3695 share = sa_get_share(group, sharepath);
3691 3696 if (share == NULL) {
3692 3697 (void) printf(gettext(
3693 3698 "Share does not exist in group %s\n"),
3694 3699 groupname, sharepath);
3695 3700 ret = SA_NO_SUCH_PATH;
3696 3701 } else {
3697 3702 /* if ZFS and OK, then only group */
3698 3703 ret = zfscheck(group, share);
3699 3704 if (ret == SA_OK &&
3700 3705 sa_group_is_zfs(group))
3701 3706 share = NULL;
3702 3707 if (ret == SA_NOT_ALLOWED)
3703 3708 (void) printf(gettext(
3704 3709 "Properties on ZFS group shares "
3705 3710 "not supported: %s\n"), sharepath);
3706 3711 }
3707 3712 }
3708 3713
3709 3714 /*
3710 3715 * If a resource name exists, make sure it belongs to
3711 3716 * the share if present else it belongs to the
3712 3717 * group. Also check the protocol to see if it
3713 3718 * supports resource level properties or not. If not,
3714 3719 * use share only.
3715 3720 */
3716 3721 if (rsrcname != NULL) {
3717 3722 if (share != NULL) {
3718 3723 resource = sa_get_share_resource(share,
3719 3724 rsrcname);
3720 3725 if (resource == NULL)
3721 3726 ret = SA_NO_SUCH_RESOURCE;
3722 3727 } else {
3723 3728 resource = sa_get_resource(group, rsrcname);
3724 3729 if (resource != NULL)
3725 3730 share = sa_get_resource_parent(
3726 3731 resource);
3727 3732 else
3728 3733 ret = SA_NO_SUCH_RESOURCE;
3729 3734 }
3730 3735 if (ret == SA_OK && resource != NULL) {
3731 3736 uint64_t features;
3732 3737 /*
3733 3738 * Check to see if the resource can take
3734 3739 * properties. If so, stick the resource into
3735 3740 * "share" so it will all just work.
3736 3741 */
3737 3742 features = sa_proto_get_featureset(protocol);
3738 3743 if (features & SA_FEATURE_RESOURCE)
3739 3744 share = (sa_share_t)resource;
3740 3745 }
3741 3746 }
3742 3747
3743 3748 if (ret == SA_OK) {
3744 3749 /* group must exist */
3745 3750 ret = valid_options(handle, optlist, protocol,
3746 3751 share == NULL ? group : share, NULL);
3747 3752 if (ret == SA_OK && !dryrun) {
3748 3753 if (share != NULL)
3749 3754 change |= add_optionset(share, optlist,
3750 3755 protocol, &ret);
3751 3756 else
3752 3757 change |= add_optionset(group, optlist,
3753 3758 protocol, &ret);
3754 3759 if (ret == SA_OK && change)
3755 3760 worklist = add_list(worklist, group,
3756 3761 share, protocol);
3757 3762 }
3758 3763 }
3759 3764 free_opt(optlist);
3760 3765 } else {
3761 3766 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
3762 3767 ret = SA_NO_SUCH_GROUP;
3763 3768 }
3764 3769 /*
3765 3770 * we have a group and potentially legal additions
3766 3771 */
3767 3772
3768 3773 /*
3769 3774 * Commit to configuration if not a dryrunp and properties
3770 3775 * have changed.
3771 3776 */
3772 3777 if (!dryrun && ret == SA_OK && change && worklist != NULL)
3773 3778 /* properties changed, so update all shares */
3774 3779 (void) enable_all_groups(handle, worklist, 0, 0, protocol,
3775 3780 B_TRUE);
3776 3781
3777 3782 if (worklist != NULL)
3778 3783 free_list(worklist);
3779 3784 return (ret);
3780 3785 }
3781 3786
3782 3787 /*
3783 3788 * space_set(groupname, optlist, protocol, sharepath, dryrun)
3784 3789 *
3785 3790 * This function implements "set" when a name space (-S) is
3786 3791 * specified. It is a namespace set. Options and other CLI parsing has
3787 3792 * already been done.
3788 3793 */
3789 3794
3790 3795 static int
3791 3796 space_set(sa_handle_t handle, char *groupname, struct options *optlist,
3792 3797 char *protocol, char *sharepath, int dryrun, char *sectype)
3793 3798 {
3794 3799 sa_group_t group;
3795 3800 int ret = SA_OK;
3796 3801 int change = 0;
3797 3802 struct list *worklist = NULL;
3798 3803
3799 3804 /*
3800 3805 * make sure protcol and sectype are valid
3801 3806 */
3802 3807
3803 3808 if (sa_proto_valid_space(protocol, sectype) == 0) {
3804 3809 (void) printf(gettext("Option space \"%s\" not valid "
3805 3810 "for protocol.\n"), sectype);
3806 3811 return (SA_INVALID_SECURITY);
3807 3812 }
3808 3813
3809 3814 group = sa_get_group(handle, groupname);
3810 3815 if (group != NULL) {
3811 3816 sa_share_t share = NULL;
3812 3817 if (sharepath != NULL) {
3813 3818 share = sa_get_share(group, sharepath);
3814 3819 if (share == NULL) {
3815 3820 (void) printf(gettext(
3816 3821 "Share does not exist in group %s\n"),
3817 3822 groupname, sharepath);
3818 3823 ret = SA_NO_SUCH_PATH;
3819 3824 } else {
3820 3825 /* if ZFS and OK, then only group */
3821 3826 ret = zfscheck(group, share);
3822 3827 if (ret == SA_OK &&
3823 3828 sa_group_is_zfs(group))
3824 3829 share = NULL;
3825 3830 if (ret == SA_NOT_ALLOWED)
3826 3831 (void) printf(gettext(
3827 3832 "Properties on ZFS group shares "
3828 3833 "not supported: %s\n"), sharepath);
3829 3834 }
3830 3835 }
3831 3836 if (ret == SA_OK) {
3832 3837 /* group must exist */
3833 3838 ret = valid_options(handle, optlist, protocol,
3834 3839 share == NULL ? group : share, sectype);
3835 3840 if (ret == SA_OK && !dryrun) {
3836 3841 if (share != NULL)
3837 3842 change = add_security(share, sectype,
3838 3843 optlist, protocol, &ret);
3839 3844 else
3840 3845 change = add_security(group, sectype,
3841 3846 optlist, protocol, &ret);
3842 3847 if (ret != SA_OK)
3843 3848 (void) printf(gettext(
3844 3849 "Could not set property: %s\n"),
3845 3850 sa_errorstr(ret));
3846 3851 }
3847 3852 if (ret == SA_OK && change)
3848 3853 worklist = add_list(worklist, group, share,
3849 3854 protocol);
3850 3855 }
3851 3856 free_opt(optlist);
3852 3857 } else {
3853 3858 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
3854 3859 ret = SA_NO_SUCH_GROUP;
3855 3860 }
3856 3861
3857 3862 /*
3858 3863 * We have a group and potentially legal additions.
3859 3864 */
3860 3865
3861 3866 /* Commit to configuration if not a dryrun */
3862 3867 if (!dryrun && ret == 0) {
3863 3868 if (change && worklist != NULL) {
3864 3869 /* properties changed, so update all shares */
3865 3870 (void) enable_all_groups(handle, worklist, 0, 0,
3866 3871 protocol, B_TRUE);
3867 3872 }
3868 3873 ret = sa_update_config(handle);
3869 3874 }
3870 3875 if (worklist != NULL)
3871 3876 free_list(worklist);
3872 3877 return (ret);
3873 3878 }
3874 3879
3875 3880 /*
3876 3881 * sa_set(flags, argc, argv)
3877 3882 *
3878 3883 * Implements the set subcommand. It keys off of -S to determine which
3879 3884 * set of operations to actually do.
3880 3885 */
3881 3886
3882 3887 int
3883 3888 sa_set(sa_handle_t handle, int flags, int argc, char *argv[])
3884 3889 {
3885 3890 char *groupname;
3886 3891 int verbose = 0;
3887 3892 int dryrun = 0;
3888 3893 int c;
3889 3894 char *protocol = NULL;
3890 3895 int ret = SA_OK;
3891 3896 struct options *optlist = NULL;
3892 3897 char *rsrcname = NULL;
3893 3898 char *sharepath = NULL;
3894 3899 char *optset = NULL;
3895 3900 int auth;
3896 3901
3897 3902 while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
3898 3903 switch (c) {
3899 3904 case 'v':
3900 3905 verbose++;
3901 3906 break;
3902 3907 case 'n':
3903 3908 dryrun++;
3904 3909 break;
3905 3910 case 'P':
3906 3911 if (protocol != NULL) {
3907 3912 (void) printf(gettext(
3908 3913 "Specifying multiple protocols "
3909 3914 "not supported: %s\n"), protocol);
3910 3915 return (SA_SYNTAX_ERR);
3911 3916 }
3912 3917 protocol = optarg;
3913 3918 if (!sa_valid_protocol(protocol)) {
3914 3919 (void) printf(gettext(
3915 3920 "Invalid protocol specified: %s\n"),
3916 3921 protocol);
3917 3922 return (SA_INVALID_PROTOCOL);
3918 3923 }
3919 3924 break;
3920 3925 case 'p':
3921 3926 ret = add_opt(&optlist, optarg, 0);
3922 3927 switch (ret) {
3923 3928 case OPT_ADD_SYNTAX:
3924 3929 (void) printf(gettext("Property syntax error:"
3925 3930 " %s\n"), optarg);
3926 3931 return (SA_SYNTAX_ERR);
3927 3932 case OPT_ADD_MEMORY:
3928 3933 (void) printf(gettext("No memory to set "
3929 3934 "property: %s\n"), optarg);
3930 3935 return (SA_NO_MEMORY);
3931 3936 default:
3932 3937 break;
3933 3938 }
3934 3939 break;
3935 3940 case 'r':
3936 3941 if (rsrcname != NULL) {
3937 3942 (void) printf(gettext(
3938 3943 "Setting multiple resource names not"
3939 3944 " supported\n"));
3940 3945 return (SA_SYNTAX_ERR);
3941 3946 }
3942 3947 rsrcname = optarg;
3943 3948 break;
3944 3949 case 's':
3945 3950 if (sharepath != NULL) {
3946 3951 (void) printf(gettext(
3947 3952 "Setting multiple shares not supported\n"));
3948 3953 return (SA_SYNTAX_ERR);
3949 3954 }
3950 3955 sharepath = optarg;
3951 3956 break;
3952 3957 case 'S':
3953 3958 if (optset != NULL) {
3954 3959 (void) printf(gettext(
3955 3960 "Specifying multiple property "
3956 3961 "spaces not supported: %s\n"), optset);
3957 3962 return (SA_SYNTAX_ERR);
3958 3963 }
3959 3964 optset = optarg;
3960 3965 break;
3961 3966 case 'h':
3962 3967 /* optopt on valid arg isn't defined */
3963 3968 optopt = c;
3964 3969 /*FALLTHROUGH*/
3965 3970 case '?':
3966 3971 default:
3967 3972 /*
3968 3973 * Since a bad option gets to here, sort it
3969 3974 * out and return a syntax error return value
3970 3975 * if necessary.
3971 3976 */
3972 3977 switch (optopt) {
3973 3978 default:
3974 3979 ret = SA_SYNTAX_ERR;
3975 3980 break;
3976 3981 case 'h':
3977 3982 case '?':
3978 3983 break;
3979 3984 }
3980 3985 (void) printf(gettext("usage: %s\n"),
3981 3986 sa_get_usage(USAGE_SET));
3982 3987 return (ret);
3983 3988 }
3984 3989 }
3985 3990
3986 3991 if (optlist != NULL)
3987 3992 ret = chk_opt(optlist, optset != NULL, protocol);
3988 3993
3989 3994 if (optind >= argc || (optlist == NULL && optset == NULL) ||
3990 3995 protocol == NULL || ret != OPT_ADD_OK) {
3991 3996 char *sep = "\t";
3992 3997
3993 3998 (void) printf(gettext("usage: %s\n"), sa_get_usage(USAGE_SET));
3994 3999 if (optind >= argc) {
3995 4000 (void) printf(gettext("%sgroup must be specified"),
3996 4001 sep);
3997 4002 sep = ", ";
3998 4003 }
3999 4004 if (optlist == NULL) {
4000 4005 (void) printf(gettext("%sat least one property must be"
4001 4006 " specified"), sep);
4002 4007 sep = ", ";
4003 4008 }
4004 4009 if (protocol == NULL) {
4005 4010 (void) printf(gettext("%sprotocol must be specified"),
4006 4011 sep);
4007 4012 sep = ", ";
4008 4013 }
4009 4014 (void) printf("\n");
4010 4015 ret = SA_SYNTAX_ERR;
4011 4016 } else {
4012 4017 /*
4013 4018 * Group already exists so we can proceed after a few
4014 4019 * additional checks related to ZFS handling.
4015 4020 */
4016 4021
4017 4022 groupname = argv[optind];
4018 4023 if (strcmp(groupname, "zfs") == 0) {
4019 4024 (void) printf(gettext("Changing properties for group "
4020 4025 "\"zfs\" not allowed\n"));
4021 4026 return (SA_NOT_ALLOWED);
4022 4027 }
4023 4028
4024 4029 auth = check_authorizations(groupname, flags);
4025 4030 if (optset == NULL)
4026 4031 ret = basic_set(handle, groupname, optlist, protocol,
4027 4032 sharepath, rsrcname, dryrun);
4028 4033 else
4029 4034 ret = space_set(handle, groupname, optlist, protocol,
4030 4035 sharepath, dryrun, optset);
4031 4036 if (dryrun && ret == SA_OK && !auth && verbose) {
4032 4037 (void) printf(gettext("Command would fail: %s\n"),
4033 4038 sa_errorstr(SA_NO_PERMISSION));
4034 4039 }
4035 4040 }
4036 4041 return (ret);
4037 4042 }
4038 4043
4039 4044 /*
4040 4045 * remove_options(group, optlist, proto, *err)
4041 4046 *
4042 4047 * Helper function to actually remove options from a group after all
4043 4048 * preprocessing is done.
4044 4049 */
4045 4050
4046 4051 static int
4047 4052 remove_options(sa_group_t group, struct options *optlist,
4048 4053 char *proto, int *err)
4049 4054 {
4050 4055 struct options *cur;
4051 4056 sa_optionset_t optionset;
4052 4057 sa_property_t prop;
4053 4058 int change = 0;
4054 4059 int ret = SA_OK;
4055 4060
4056 4061 optionset = sa_get_optionset(group, proto);
4057 4062 if (optionset != NULL) {
4058 4063 for (cur = optlist; cur != NULL; cur = cur->next) {
4059 4064 prop = sa_get_property(optionset, cur->optname);
4060 4065 if (prop != NULL) {
4061 4066 ret = sa_remove_property(prop);
4062 4067 if (ret != SA_OK)
4063 4068 break;
4064 4069 change = 1;
4065 4070 }
4066 4071 }
4067 4072 }
4068 4073 if (ret == SA_OK && change)
4069 4074 ret = sa_commit_properties(optionset, 0);
4070 4075
4071 4076 if (err != NULL)
4072 4077 *err = ret;
4073 4078 return (change);
4074 4079 }
4075 4080
4076 4081 /*
4077 4082 * valid_unset(group, optlist, proto)
4078 4083 *
4079 4084 * Sanity check the optlist to make sure they can be removed. Issue an
4080 4085 * error if a property doesn't exist.
4081 4086 */
4082 4087
4083 4088 static int
4084 4089 valid_unset(sa_group_t group, struct options *optlist, char *proto)
4085 4090 {
4086 4091 struct options *cur;
4087 4092 sa_optionset_t optionset;
4088 4093 sa_property_t prop;
4089 4094 int ret = SA_OK;
4090 4095
4091 4096 optionset = sa_get_optionset(group, proto);
4092 4097 if (optionset != NULL) {
4093 4098 for (cur = optlist; cur != NULL; cur = cur->next) {
4094 4099 prop = sa_get_property(optionset, cur->optname);
4095 4100 if (prop == NULL) {
4096 4101 (void) printf(gettext(
4097 4102 "Could not unset property %s: not set\n"),
4098 4103 cur->optname);
4099 4104 ret = SA_NO_SUCH_PROP;
4100 4105 }
4101 4106 }
4102 4107 }
4103 4108 return (ret);
4104 4109 }
4105 4110
4106 4111 /*
4107 4112 * valid_unset_security(group, optlist, proto)
4108 4113 *
4109 4114 * Sanity check the optlist to make sure they can be removed. Issue an
4110 4115 * error if a property doesn't exist.
4111 4116 */
4112 4117
4113 4118 static int
4114 4119 valid_unset_security(sa_group_t group, struct options *optlist, char *proto,
4115 4120 char *sectype)
4116 4121 {
4117 4122 struct options *cur;
4118 4123 sa_security_t security;
4119 4124 sa_property_t prop;
4120 4125 int ret = SA_OK;
4121 4126 char *sec;
4122 4127
4123 4128 sec = sa_proto_space_alias(proto, sectype);
4124 4129 security = sa_get_security(group, sec, proto);
4125 4130 if (security != NULL) {
4126 4131 for (cur = optlist; cur != NULL; cur = cur->next) {
4127 4132 prop = sa_get_property(security, cur->optname);
4128 4133 if (prop == NULL) {
4129 4134 (void) printf(gettext(
4130 4135 "Could not unset property %s: not set\n"),
4131 4136 cur->optname);
4132 4137 ret = SA_NO_SUCH_PROP;
4133 4138 }
4134 4139 }
4135 4140 } else {
4136 4141 (void) printf(gettext(
4137 4142 "Could not unset %s: space not defined\n"), sectype);
4138 4143 ret = SA_NO_SUCH_SECURITY;
4139 4144 }
4140 4145 if (sec != NULL)
4141 4146 sa_free_attr_string(sec);
4142 4147 return (ret);
4143 4148 }
4144 4149
4145 4150 /*
4146 4151 * remove_security(group, optlist, proto)
4147 4152 *
4148 4153 * Remove the properties since they were checked as valid.
4149 4154 */
4150 4155
4151 4156 static int
4152 4157 remove_security(sa_group_t group, char *sectype,
4153 4158 struct options *optlist, char *proto, int *err)
4154 4159 {
4155 4160 sa_security_t security;
4156 4161 int ret = SA_OK;
4157 4162 int change = 0;
4158 4163
4159 4164 sectype = sa_proto_space_alias(proto, sectype);
4160 4165 security = sa_get_security(group, sectype, proto);
4161 4166 if (sectype != NULL)
4162 4167 sa_free_attr_string(sectype);
4163 4168
4164 4169 if (security != NULL) {
4165 4170 while (optlist != NULL) {
4166 4171 sa_property_t prop;
4167 4172 prop = sa_get_property(security, optlist->optname);
4168 4173 if (prop != NULL) {
4169 4174 ret = sa_remove_property(prop);
4170 4175 if (ret != SA_OK)
4171 4176 break;
4172 4177 change = 1;
4173 4178 }
4174 4179 optlist = optlist->next;
4175 4180 }
4176 4181 /*
4177 4182 * when done, properties may have all been removed but
4178 4183 * we need to keep the security type itself until
4179 4184 * explicitly removed.
4180 4185 */
4181 4186 if (ret == SA_OK && change)
4182 4187 ret = sa_commit_properties(security, 0);
4183 4188 } else {
4184 4189 ret = SA_NO_SUCH_PROP;
4185 4190 }
4186 4191 if (err != NULL)
4187 4192 *err = ret;
4188 4193 return (change);
4189 4194 }
4190 4195
4191 4196 /*
4192 4197 * basic_unset(groupname, optlist, protocol, sharepath, rsrcname, dryrun)
4193 4198 *
4194 4199 * Unset non-named optionset properties.
4195 4200 */
4196 4201
4197 4202 static int
4198 4203 basic_unset(sa_handle_t handle, char *groupname, struct options *optlist,
4199 4204 char *protocol, char *sharepath, char *rsrcname, int dryrun)
4200 4205 {
4201 4206 sa_group_t group;
4202 4207 int ret = SA_OK;
4203 4208 int change = 0;
4204 4209 struct list *worklist = NULL;
4205 4210 sa_share_t share = NULL;
4206 4211 sa_resource_t resource = NULL;
4207 4212
4208 4213 group = sa_get_group(handle, groupname);
4209 4214 if (group == NULL)
4210 4215 return (ret);
4211 4216
4212 4217 /*
4213 4218 * If there is a sharepath, make sure it belongs to
4214 4219 * the group.
4215 4220 */
4216 4221 if (sharepath != NULL) {
4217 4222 share = sa_get_share(group, sharepath);
4218 4223 if (share == NULL) {
4219 4224 (void) printf(gettext(
4220 4225 "Share does not exist in group %s\n"),
4221 4226 groupname, sharepath);
4222 4227 ret = SA_NO_SUCH_PATH;
4223 4228 }
4224 4229 }
4225 4230 /*
4226 4231 * If a resource name exists, make sure it belongs to
4227 4232 * the share if present else it belongs to the
4228 4233 * group. Also check the protocol to see if it
4229 4234 * supports resource level properties or not. If not,
4230 4235 * use share only.
4231 4236 */
4232 4237 if (rsrcname != NULL) {
4233 4238 if (share != NULL) {
4234 4239 resource = sa_get_share_resource(share, rsrcname);
4235 4240 if (resource == NULL)
4236 4241 ret = SA_NO_SUCH_RESOURCE;
4237 4242 } else {
4238 4243 resource = sa_get_resource(group, rsrcname);
4239 4244 if (resource != NULL) {
4240 4245 share = sa_get_resource_parent(resource);
4241 4246 } else {
4242 4247 ret = SA_NO_SUCH_RESOURCE;
4243 4248 }
4244 4249 }
4245 4250 if (ret == SA_OK && resource != NULL) {
4246 4251 uint64_t features;
4247 4252 /*
4248 4253 * Check to see if the resource can take
4249 4254 * properties. If so, stick the resource into
4250 4255 * "share" so it will all just work.
4251 4256 */
4252 4257 features = sa_proto_get_featureset(protocol);
4253 4258 if (features & SA_FEATURE_RESOURCE)
4254 4259 share = (sa_share_t)resource;
4255 4260 }
4256 4261 }
4257 4262
4258 4263 if (ret == SA_OK) {
4259 4264 /* group must exist */
4260 4265 ret = valid_unset(share != NULL ? share : group,
4261 4266 optlist, protocol);
4262 4267 if (ret == SA_OK && !dryrun) {
4263 4268 if (share != NULL) {
4264 4269 sa_optionset_t optionset;
4265 4270 sa_property_t prop;
4266 4271 change |= remove_options(share, optlist,
4267 4272 protocol, &ret);
4268 4273 /*
4269 4274 * If a share optionset is
4270 4275 * empty, remove it.
4271 4276 */
4272 4277 optionset = sa_get_optionset((sa_share_t)share,
4273 4278 protocol);
4274 4279 if (optionset != NULL) {
4275 4280 prop = sa_get_property(optionset, NULL);
4276 4281 if (prop == NULL)
4277 4282 (void) sa_destroy_optionset(
4278 4283 optionset);
4279 4284 }
4280 4285 } else {
4281 4286 change |= remove_options(group,
4282 4287 optlist, protocol, &ret);
4283 4288 }
4284 4289 if (ret == SA_OK && change)
4285 4290 worklist = add_list(worklist, group, share,
4286 4291 protocol);
4287 4292 if (ret != SA_OK)
4288 4293 (void) printf(gettext(
4289 4294 "Could not remove properties: "
4290 4295 "%s\n"), sa_errorstr(ret));
4291 4296 }
4292 4297 } else {
4293 4298 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
4294 4299 ret = SA_NO_SUCH_GROUP;
4295 4300 }
4296 4301 free_opt(optlist);
4297 4302
4298 4303 /*
4299 4304 * We have a group and potentially legal additions
4300 4305 *
4301 4306 * Commit to configuration if not a dryrun
4302 4307 */
4303 4308 if (!dryrun && ret == SA_OK) {
4304 4309 if (change && worklist != NULL) {
4305 4310 /* properties changed, so update all shares */
4306 4311 (void) enable_all_groups(handle, worklist, 0, 0,
4307 4312 protocol, B_TRUE);
4308 4313 }
4309 4314 }
4310 4315 if (worklist != NULL)
4311 4316 free_list(worklist);
4312 4317 return (ret);
4313 4318 }
4314 4319
4315 4320 /*
4316 4321 * space_unset(groupname, optlist, protocol, sharepath, dryrun)
4317 4322 *
4318 4323 * Unset named optionset properties.
4319 4324 */
4320 4325 static int
4321 4326 space_unset(sa_handle_t handle, char *groupname, struct options *optlist,
4322 4327 char *protocol, char *sharepath, int dryrun, char *sectype)
4323 4328 {
4324 4329 sa_group_t group;
4325 4330 int ret = SA_OK;
4326 4331 int change = 0;
4327 4332 struct list *worklist = NULL;
4328 4333 sa_share_t share = NULL;
4329 4334
4330 4335 group = sa_get_group(handle, groupname);
4331 4336 if (group == NULL) {
4332 4337 (void) printf(gettext("Group \"%s\" not found\n"), groupname);
4333 4338 return (SA_NO_SUCH_GROUP);
4334 4339 }
4335 4340 if (sharepath != NULL) {
4336 4341 share = sa_get_share(group, sharepath);
4337 4342 if (share == NULL) {
4338 4343 (void) printf(gettext(
4339 4344 "Share does not exist in group %s\n"),
4340 4345 groupname, sharepath);
4341 4346 return (SA_NO_SUCH_PATH);
4342 4347 }
4343 4348 }
4344 4349 ret = valid_unset_security(share != NULL ? share : group,
4345 4350 optlist, protocol, sectype);
4346 4351
4347 4352 if (ret == SA_OK && !dryrun) {
4348 4353 if (optlist != NULL) {
4349 4354 if (share != NULL) {
4350 4355 sa_security_t optionset;
4351 4356 sa_property_t prop;
4352 4357 change = remove_security(share,
4353 4358 sectype, optlist, protocol, &ret);
4354 4359
4355 4360 /* If a share security is empty, remove it */
4356 4361 optionset = sa_get_security((sa_group_t)share,
4357 4362 sectype, protocol);
4358 4363 if (optionset != NULL) {
4359 4364 prop = sa_get_property(optionset,
4360 4365 NULL);
4361 4366 if (prop == NULL)
4362 4367 ret = sa_destroy_security(
4363 4368 optionset);
4364 4369 }
4365 4370 } else {
4366 4371 change = remove_security(group, sectype,
4367 4372 optlist, protocol, &ret);
4368 4373 }
4369 4374 } else {
4370 4375 sa_security_t security;
4371 4376 char *sec;
4372 4377 sec = sa_proto_space_alias(protocol, sectype);
4373 4378 security = sa_get_security(group, sec, protocol);
4374 4379 if (sec != NULL)
4375 4380 sa_free_attr_string(sec);
4376 4381 if (security != NULL) {
4377 4382 ret = sa_destroy_security(security);
4378 4383 if (ret == SA_OK)
4379 4384 change = 1;
4380 4385 } else {
4381 4386 ret = SA_NO_SUCH_PROP;
4382 4387 }
4383 4388 }
4384 4389 if (ret != SA_OK)
4385 4390 (void) printf(gettext("Could not unset property: %s\n"),
4386 4391 sa_errorstr(ret));
4387 4392 }
4388 4393
4389 4394 if (ret == SA_OK && change)
4390 4395 worklist = add_list(worklist, group, 0, protocol);
4391 4396
4392 4397 free_opt(optlist);
4393 4398 /*
4394 4399 * We have a group and potentially legal additions
4395 4400 */
4396 4401
4397 4402 /* Commit to configuration if not a dryrun */
4398 4403 if (!dryrun && ret == 0) {
4399 4404 /* properties changed, so update all shares */
4400 4405 if (change && worklist != NULL)
4401 4406 (void) enable_all_groups(handle, worklist, 0, 0,
4402 4407 protocol, B_TRUE);
4403 4408 ret = sa_update_config(handle);
4404 4409 }
4405 4410 if (worklist != NULL)
4406 4411 free_list(worklist);
4407 4412 return (ret);
4408 4413 }
4409 4414
4410 4415 /*
4411 4416 * sa_unset(flags, argc, argv)
4412 4417 *
4413 4418 * Implements the unset subcommand. Parsing done here and then basic
4414 4419 * or space versions of the real code are called.
4415 4420 */
4416 4421
4417 4422 int
4418 4423 sa_unset(sa_handle_t handle, int flags, int argc, char *argv[])
4419 4424 {
4420 4425 char *groupname;
4421 4426 int verbose = 0;
4422 4427 int dryrun = 0;
4423 4428 int c;
4424 4429 char *protocol = NULL;
4425 4430 int ret = SA_OK;
4426 4431 struct options *optlist = NULL;
4427 4432 char *rsrcname = NULL;
4428 4433 char *sharepath = NULL;
4429 4434 char *optset = NULL;
4430 4435 int auth;
4431 4436
4432 4437 while ((c = getopt(argc, argv, "?hvnP:p:r:s:S:")) != EOF) {
4433 4438 switch (c) {
4434 4439 case 'v':
4435 4440 verbose++;
4436 4441 break;
4437 4442 case 'n':
4438 4443 dryrun++;
4439 4444 break;
4440 4445 case 'P':
4441 4446 if (protocol != NULL) {
4442 4447 (void) printf(gettext(
4443 4448 "Specifying multiple protocols "
4444 4449 "not supported: %s\n"), protocol);
4445 4450 return (SA_SYNTAX_ERR);
4446 4451 }
4447 4452 protocol = optarg;
4448 4453 if (!sa_valid_protocol(protocol)) {
4449 4454 (void) printf(gettext(
4450 4455 "Invalid protocol specified: %s\n"),
4451 4456 protocol);
4452 4457 return (SA_INVALID_PROTOCOL);
4453 4458 }
4454 4459 break;
4455 4460 case 'p':
4456 4461 ret = add_opt(&optlist, optarg, 1);
4457 4462 switch (ret) {
4458 4463 case OPT_ADD_SYNTAX:
4459 4464 (void) printf(gettext("Property syntax error "
4460 4465 "for property %s\n"), optarg);
4461 4466 return (SA_SYNTAX_ERR);
4462 4467
4463 4468 case OPT_ADD_PROPERTY:
4464 4469 (void) printf(gettext("Properties need to be "
4465 4470 "set with set command: %s\n"), optarg);
4466 4471 return (SA_SYNTAX_ERR);
4467 4472
4468 4473 default:
4469 4474 break;
4470 4475 }
4471 4476 break;
4472 4477 case 'r':
4473 4478 /*
4474 4479 * Unset properties on resource if applicable or on
4475 4480 * share if resource for this protocol doesn't use
4476 4481 * resources.
4477 4482 */
4478 4483 if (rsrcname != NULL) {
4479 4484 (void) printf(gettext(
4480 4485 "Unsetting multiple resource "
4481 4486 "names not supported\n"));
4482 4487 return (SA_SYNTAX_ERR);
4483 4488 }
4484 4489 rsrcname = optarg;
4485 4490 break;
4486 4491 case 's':
4487 4492 if (sharepath != NULL) {
4488 4493 (void) printf(gettext(
4489 4494 "Adding multiple shares not supported\n"));
4490 4495 return (SA_SYNTAX_ERR);
4491 4496 }
4492 4497 sharepath = optarg;
4493 4498 break;
4494 4499 case 'S':
4495 4500 if (optset != NULL) {
4496 4501 (void) printf(gettext(
4497 4502 "Specifying multiple property "
4498 4503 "spaces not supported: %s\n"), optset);
4499 4504 return (SA_SYNTAX_ERR);
4500 4505 }
4501 4506 optset = optarg;
4502 4507 break;
4503 4508 case 'h':
4504 4509 /* optopt on valid arg isn't defined */
4505 4510 optopt = c;
4506 4511 /*FALLTHROUGH*/
4507 4512 case '?':
4508 4513 default:
4509 4514 /*
4510 4515 * Since a bad option gets to here, sort it
4511 4516 * out and return a syntax error return value
4512 4517 * if necessary.
4513 4518 */
4514 4519 switch (optopt) {
4515 4520 default:
4516 4521 ret = SA_SYNTAX_ERR;
4517 4522 break;
4518 4523 case 'h':
4519 4524 case '?':
4520 4525 break;
4521 4526 }
4522 4527 (void) printf(gettext("usage: %s\n"),
4523 4528 sa_get_usage(USAGE_UNSET));
4524 4529 return (ret);
4525 4530 }
4526 4531 }
4527 4532
4528 4533 if (optlist != NULL)
4529 4534 ret = chk_opt(optlist, optset != NULL, protocol);
4530 4535
4531 4536 if (optind >= argc || (optlist == NULL && optset == NULL) ||
4532 4537 protocol == NULL) {
4533 4538 char *sep = "\t";
4534 4539 (void) printf(gettext("usage: %s\n"),
4535 4540 sa_get_usage(USAGE_UNSET));
4536 4541 if (optind >= argc) {
4537 4542 (void) printf(gettext("%sgroup must be specified"),
4538 4543 sep);
4539 4544 sep = ", ";
4540 4545 }
4541 4546 if (optlist == NULL) {
4542 4547 (void) printf(gettext("%sat least one property must "
4543 4548 "be specified"), sep);
4544 4549 sep = ", ";
4545 4550 }
4546 4551 if (protocol == NULL) {
4547 4552 (void) printf(gettext("%sprotocol must be specified"),
4548 4553 sep);
4549 4554 sep = ", ";
4550 4555 }
4551 4556 (void) printf("\n");
4552 4557 ret = SA_SYNTAX_ERR;
4553 4558 } else {
4554 4559
4555 4560 /*
4556 4561 * If a group already exists, we can only add a new
4557 4562 * protocol to it and not create a new one or add the
4558 4563 * same protocol again.
4559 4564 */
4560 4565
4561 4566 groupname = argv[optind];
4562 4567 auth = check_authorizations(groupname, flags);
4563 4568 if (optset == NULL)
4564 4569 ret = basic_unset(handle, groupname, optlist, protocol,
4565 4570 sharepath, rsrcname, dryrun);
4566 4571 else
4567 4572 ret = space_unset(handle, groupname, optlist, protocol,
4568 4573 sharepath, dryrun, optset);
4569 4574
4570 4575 if (dryrun && ret == SA_OK && !auth && verbose)
4571 4576 (void) printf(gettext("Command would fail: %s\n"),
4572 4577 sa_errorstr(SA_NO_PERMISSION));
4573 4578 }
4574 4579 return (ret);
4575 4580 }
4576 4581
4577 4582 /*
4578 4583 * sa_enable_group(flags, argc, argv)
4579 4584 *
4580 4585 * Implements the enable subcommand
4581 4586 */
4582 4587
4583 4588 int
4584 4589 sa_enable_group(sa_handle_t handle, int flags, int argc, char *argv[])
4585 4590 {
4586 4591 int verbose = 0;
4587 4592 int dryrun = 0;
4588 4593 int all = 0;
4589 4594 int c;
4590 4595 int ret = SA_OK;
4591 4596 char *protocol = NULL;
4592 4597 char *state;
4593 4598 struct list *worklist = NULL;
4594 4599 int auth = 1;
4595 4600 sa_group_t group;
4596 4601
4597 4602 while ((c = getopt(argc, argv, "?havnP:")) != EOF) {
4598 4603 switch (c) {
4599 4604 case 'a':
4600 4605 all = 1;
4601 4606 break;
4602 4607 case 'n':
4603 4608 dryrun++;
4604 4609 break;
4605 4610 case 'P':
4606 4611 if (protocol != NULL) {
4607 4612 (void) printf(gettext(
4608 4613 "Specifying multiple protocols "
4609 4614 "not supported: %s\n"), protocol);
4610 4615 return (SA_SYNTAX_ERR);
4611 4616 }
4612 4617 protocol = optarg;
4613 4618 if (!sa_valid_protocol(protocol)) {
4614 4619 (void) printf(gettext(
4615 4620 "Invalid protocol specified: %s\n"),
4616 4621 protocol);
4617 4622 return (SA_INVALID_PROTOCOL);
4618 4623 }
4619 4624 break;
4620 4625 case 'v':
4621 4626 verbose++;
4622 4627 break;
4623 4628 case 'h':
4624 4629 /* optopt on valid arg isn't defined */
4625 4630 optopt = c;
4626 4631 /*FALLTHROUGH*/
4627 4632 case '?':
4628 4633 default:
4629 4634 /*
4630 4635 * Since a bad option gets to here, sort it
4631 4636 * out and return a syntax error return value
4632 4637 * if necessary.
4633 4638 */
4634 4639 switch (optopt) {
4635 4640 default:
4636 4641 ret = SA_SYNTAX_ERR;
4637 4642 break;
4638 4643 case 'h':
4639 4644 case '?':
4640 4645 (void) printf(gettext("usage: %s\n"),
4641 4646 sa_get_usage(USAGE_ENABLE));
4642 4647 return (ret);
4643 4648 }
4644 4649 }
4645 4650 }
4646 4651
4647 4652 if (optind == argc && !all) {
4648 4653 (void) printf(gettext("usage: %s\n"),
4649 4654 sa_get_usage(USAGE_ENABLE));
4650 4655 (void) printf(gettext("\tmust specify group\n"));
4651 4656 return (SA_NO_SUCH_PATH);
4652 4657 }
4653 4658 if (!all) {
4654 4659 while (optind < argc) {
4655 4660 group = sa_get_group(handle, argv[optind]);
4656 4661 if (group != NULL) {
4657 4662 auth &= check_authorizations(argv[optind],
4658 4663 flags);
4659 4664 state = sa_get_group_attr(group, "state");
4660 4665 if (state != NULL &&
4661 4666 strcmp(state, "enabled") == 0) {
4662 4667 /* already enabled */
4663 4668 if (verbose)
4664 4669 (void) printf(gettext(
4665 4670 "Group \"%s\" is already "
4666 4671 "enabled\n"),
4667 4672 argv[optind]);
4668 4673 ret = SA_BUSY; /* already enabled */
4669 4674 } else {
4670 4675 worklist = add_list(worklist, group,
4671 4676 0, protocol);
4672 4677 if (verbose)
4673 4678 (void) printf(gettext(
4674 4679 "Enabling group \"%s\"\n"),
4675 4680 argv[optind]);
4676 4681 }
4677 4682 if (state != NULL)
4678 4683 sa_free_attr_string(state);
4679 4684 } else {
4680 4685 ret = SA_NO_SUCH_GROUP;
4681 4686 }
4682 4687 optind++;
4683 4688 }
4684 4689 } else {
4685 4690 for (group = sa_get_group(handle, NULL);
4686 4691 group != NULL;
4687 4692 group = sa_get_next_group(group)) {
4688 4693 worklist = add_list(worklist, group, 0, protocol);
4689 4694 }
4690 4695 }
4691 4696 if (!dryrun && ret == SA_OK)
4692 4697 ret = enable_all_groups(handle, worklist, 1, 0, NULL, B_FALSE);
4693 4698
4694 4699 if (ret != SA_OK && ret != SA_BUSY)
4695 4700 (void) printf(gettext("Could not enable group: %s\n"),
4696 4701 sa_errorstr(ret));
4697 4702 if (ret == SA_BUSY)
4698 4703 ret = SA_OK;
4699 4704
4700 4705 if (worklist != NULL)
4701 4706 free_list(worklist);
4702 4707 if (dryrun && ret == SA_OK && !auth && verbose) {
4703 4708 (void) printf(gettext("Command would fail: %s\n"),
4704 4709 sa_errorstr(SA_NO_PERMISSION));
4705 4710 }
4706 4711 return (ret);
4707 4712 }
4708 4713
4709 4714 /*
4710 4715 * disable_group(group, proto)
4711 4716 *
4712 4717 * Disable all the shares in the specified group.. This is a helper
4713 4718 * for disable_all_groups in order to simplify regular and subgroup
4714 4719 * (zfs) disabling. Group has already been checked for non-NULL.
4715 4720 */
4716 4721
4717 4722 static int
4718 4723 disable_group(sa_group_t group, char *proto)
4719 4724 {
4720 4725 sa_share_t share;
4721 4726 int ret = SA_OK;
4722 4727
4723 4728 /*
4724 4729 * If the protocol isn't enabled, skip it and treat as
4725 4730 * successful.
4726 4731 */
4727 4732 if (!has_protocol(group, proto))
4728 4733 return (ret);
4729 4734
4730 4735 for (share = sa_get_share(group, NULL);
4731 4736 share != NULL && ret == SA_OK;
4732 4737 share = sa_get_next_share(share)) {
4733 4738 ret = sa_disable_share(share, proto);
4734 4739 if (ret == SA_NO_SUCH_PATH) {
4735 4740 /*
4736 4741 * this is OK since the path is gone. we can't
4737 4742 * re-share it anyway so no error.
4738 4743 */
4739 4744 ret = SA_OK;
4740 4745 }
4741 4746 }
4742 4747 return (ret);
4743 4748 }
4744 4749
4745 4750 /*
4746 4751 * disable_all_groups(work, setstate)
4747 4752 *
4748 4753 * helper function that disables the shares in the list of groups
4749 4754 * provided. It optionally marks the group as disabled. Used by both
4750 4755 * enable and start subcommands.
4751 4756 */
4752 4757
4753 4758 static int
4754 4759 disable_all_groups(sa_handle_t handle, struct list *work, int setstate)
4755 4760 {
4756 4761 int ret = SA_OK;
4757 4762 sa_group_t subgroup, group;
4758 4763
4759 4764 while (work != NULL && ret == SA_OK) {
4760 4765 group = (sa_group_t)work->item;
4761 4766 if (setstate)
4762 4767 ret = sa_set_group_attr(group, "state", "disabled");
4763 4768 if (ret == SA_OK) {
4764 4769 char *name;
4765 4770 name = sa_get_group_attr(group, "name");
4766 4771 if (name != NULL && strcmp(name, "zfs") == 0) {
4767 4772 /* need to get the sub-groups for stopping */
4768 4773 for (subgroup = sa_get_sub_group(group);
4769 4774 subgroup != NULL;
4770 4775 subgroup = sa_get_next_group(subgroup)) {
4771 4776 ret = disable_group(subgroup,
4772 4777 work->proto);
4773 4778 }
4774 4779 } else {
4775 4780 ret = disable_group(group, work->proto);
4776 4781 }
4777 4782 if (name != NULL)
4778 4783 sa_free_attr_string(name);
4779 4784 /*
4780 4785 * We don't want to "disable" since it won't come
4781 4786 * up after a reboot. The SMF framework should do
4782 4787 * the right thing. On enable we do want to do
4783 4788 * something.
4784 4789 */
4785 4790 }
4786 4791 work = work->next;
4787 4792 }
4788 4793 if (ret == SA_OK)
4789 4794 ret = sa_update_config(handle);
4790 4795 return (ret);
4791 4796 }
4792 4797
4793 4798 /*
4794 4799 * sa_disable_group(flags, argc, argv)
4795 4800 *
4796 4801 * Implements the disable subcommand
4797 4802 */
4798 4803
4799 4804 int
4800 4805 sa_disable_group(sa_handle_t handle, int flags, int argc, char *argv[])
4801 4806 {
4802 4807 int verbose = 0;
4803 4808 int dryrun = 0;
4804 4809 int all = 0;
4805 4810 int c;
4806 4811 int ret = SA_OK;
4807 4812 char *protocol = NULL;
4808 4813 char *state;
4809 4814 struct list *worklist = NULL;
4810 4815 sa_group_t group;
4811 4816 int auth = 1;
4812 4817
4813 4818 while ((c = getopt(argc, argv, "?havn")) != EOF) {
4814 4819 switch (c) {
4815 4820 case 'a':
4816 4821 all = 1;
4817 4822 break;
4818 4823 case 'n':
4819 4824 dryrun++;
4820 4825 break;
4821 4826 case 'P':
4822 4827 if (protocol != NULL) {
4823 4828 (void) printf(gettext(
4824 4829 "Specifying multiple protocols "
4825 4830 "not supported: %s\n"), protocol);
4826 4831 return (SA_SYNTAX_ERR);
4827 4832 }
4828 4833 protocol = optarg;
4829 4834 if (!sa_valid_protocol(protocol)) {
4830 4835 (void) printf(gettext(
4831 4836 "Invalid protocol specified: %s\n"),
4832 4837 protocol);
4833 4838 return (SA_INVALID_PROTOCOL);
4834 4839 }
4835 4840 break;
4836 4841 case 'v':
4837 4842 verbose++;
4838 4843 break;
4839 4844 case 'h':
4840 4845 /* optopt on valid arg isn't defined */
4841 4846 optopt = c;
4842 4847 /*FALLTHROUGH*/
4843 4848 case '?':
4844 4849 default:
4845 4850 /*
4846 4851 * Since a bad option gets to here, sort it
4847 4852 * out and return a syntax error return value
4848 4853 * if necessary.
4849 4854 */
4850 4855 switch (optopt) {
4851 4856 default:
4852 4857 ret = SA_SYNTAX_ERR;
4853 4858 break;
4854 4859 case 'h':
4855 4860 case '?':
4856 4861 break;
4857 4862 }
4858 4863 (void) printf(gettext("usage: %s\n"),
4859 4864 sa_get_usage(USAGE_DISABLE));
4860 4865 return (ret);
4861 4866 }
4862 4867 }
4863 4868
4864 4869 if (optind == argc && !all) {
4865 4870 (void) printf(gettext("usage: %s\n"),
4866 4871 sa_get_usage(USAGE_DISABLE));
4867 4872 (void) printf(gettext("\tmust specify group\n"));
4868 4873 return (SA_NO_SUCH_PATH);
4869 4874 }
4870 4875 if (!all) {
4871 4876 while (optind < argc) {
4872 4877 group = sa_get_group(handle, argv[optind]);
4873 4878 if (group != NULL) {
4874 4879 auth &= check_authorizations(argv[optind],
4875 4880 flags);
4876 4881 state = sa_get_group_attr(group, "state");
4877 4882 if (state == NULL ||
4878 4883 strcmp(state, "disabled") == 0) {
4879 4884 /* already disabled */
4880 4885 if (verbose)
4881 4886 (void) printf(gettext(
4882 4887 "Group \"%s\" is "
4883 4888 "already disabled\n"),
4884 4889 argv[optind]);
4885 4890 ret = SA_BUSY; /* already disabled */
4886 4891 } else {
4887 4892 worklist = add_list(worklist, group, 0,
4888 4893 protocol);
4889 4894 if (verbose)
4890 4895 (void) printf(gettext(
4891 4896 "Disabling group "
4892 4897 "\"%s\"\n"), argv[optind]);
4893 4898 }
4894 4899 if (state != NULL)
4895 4900 sa_free_attr_string(state);
4896 4901 } else {
4897 4902 ret = SA_NO_SUCH_GROUP;
4898 4903 }
4899 4904 optind++;
4900 4905 }
4901 4906 } else {
4902 4907 for (group = sa_get_group(handle, NULL);
4903 4908 group != NULL;
4904 4909 group = sa_get_next_group(group))
4905 4910 worklist = add_list(worklist, group, 0, protocol);
4906 4911 }
4907 4912
4908 4913 if (ret == SA_OK && !dryrun)
4909 4914 ret = disable_all_groups(handle, worklist, 1);
4910 4915 if (ret != SA_OK && ret != SA_BUSY)
4911 4916 (void) printf(gettext("Could not disable group: %s\n"),
4912 4917 sa_errorstr(ret));
4913 4918 if (ret == SA_BUSY)
4914 4919 ret = SA_OK;
4915 4920 if (worklist != NULL)
4916 4921 free_list(worklist);
4917 4922 if (dryrun && ret == SA_OK && !auth && verbose)
4918 4923 (void) printf(gettext("Command would fail: %s\n"),
4919 4924 sa_errorstr(SA_NO_PERMISSION));
4920 4925 return (ret);
4921 4926 }
4922 4927
4923 4928 /*
4924 4929 * sa_start_group(flags, argc, argv)
4925 4930 *
4926 4931 * Implements the start command.
4927 4932 * This is similar to enable except it doesn't change the state
4928 4933 * of the group(s) and only enables shares if the group is already
4929 4934 * enabled.
4930 4935 */
4931 4936
4932 4937 int
4933 4938 sa_start_group(sa_handle_t handle, int flags, int argc, char *argv[])
4934 4939 {
4935 4940 int verbose = 0;
4936 4941 int all = 0;
4937 4942 int c;
4938 4943 int ret = SMF_EXIT_OK;
4939 4944 char *protocol = NULL;
4940 4945 char *state;
4941 4946 struct list *worklist = NULL;
4942 4947 sa_group_t group;
4943 4948 #ifdef lint
4944 4949 flags = flags;
4945 4950 #endif
4946 4951
4947 4952 while ((c = getopt(argc, argv, "?havP:")) != EOF) {
4948 4953 switch (c) {
4949 4954 case 'a':
4950 4955 all = 1;
4951 4956 break;
4952 4957 case 'P':
4953 4958 if (protocol != NULL) {
4954 4959 (void) printf(gettext(
4955 4960 "Specifying multiple protocols "
4956 4961 "not supported: %s\n"), protocol);
4957 4962 return (SA_SYNTAX_ERR);
4958 4963 }
4959 4964 protocol = optarg;
4960 4965 if (!sa_valid_protocol(protocol)) {
4961 4966 (void) printf(gettext(
4962 4967 "Invalid protocol specified: %s\n"),
4963 4968 protocol);
4964 4969 return (SA_INVALID_PROTOCOL);
4965 4970 }
4966 4971 break;
4967 4972 case 'v':
4968 4973 verbose++;
4969 4974 break;
4970 4975 case 'h':
4971 4976 /* optopt on valid arg isn't defined */
4972 4977 optopt = c;
4973 4978 /*FALLTHROUGH*/
4974 4979 case '?':
4975 4980 default:
4976 4981 /*
4977 4982 * Since a bad option gets to here, sort it
4978 4983 * out and return a syntax error return value
4979 4984 * if necessary.
4980 4985 */
4981 4986 ret = SA_OK;
4982 4987 switch (optopt) {
4983 4988 default:
4984 4989 ret = SA_SYNTAX_ERR;
4985 4990 break;
4986 4991 case 'h':
4987 4992 case '?':
4988 4993 break;
4989 4994 }
4990 4995 (void) printf(gettext("usage: %s\n"),
4991 4996 sa_get_usage(USAGE_START));
4992 4997 return (ret);
4993 4998 }
4994 4999 }
4995 5000
4996 5001 if (optind == argc && !all) {
4997 5002 (void) printf(gettext("usage: %s\n"),
4998 5003 sa_get_usage(USAGE_START));
4999 5004 return (SMF_EXIT_ERR_FATAL);
5000 5005 }
5001 5006
5002 5007 if (!all) {
5003 5008 while (optind < argc) {
5004 5009 group = sa_get_group(handle, argv[optind]);
5005 5010 if (group != NULL) {
5006 5011 state = sa_get_group_attr(group, "state");
5007 5012 if (state == NULL ||
5008 5013 strcmp(state, "enabled") == 0) {
5009 5014 worklist = add_list(worklist, group, 0,
5010 5015 protocol);
5011 5016 if (verbose)
5012 5017 (void) printf(gettext(
5013 5018 "Starting group \"%s\"\n"),
5014 5019 argv[optind]);
5015 5020 } else {
5016 5021 /*
5017 5022 * Determine if there are any
5018 5023 * protocols. If there aren't any,
5019 5024 * then there isn't anything to do in
5020 5025 * any case so no error.
5021 5026 */
5022 5027 if (sa_get_optionset(group,
5023 5028 protocol) != NULL) {
5024 5029 ret = SMF_EXIT_OK;
5025 5030 }
5026 5031 }
5027 5032 if (state != NULL)
5028 5033 sa_free_attr_string(state);
5029 5034 }
5030 5035 optind++;
5031 5036 }
5032 5037 } else {
5033 5038 for (group = sa_get_group(handle, NULL);
5034 5039 group != NULL;
5035 5040 group = sa_get_next_group(group)) {
5036 5041 state = sa_get_group_attr(group, "state");
5037 5042 if (state == NULL || strcmp(state, "enabled") == 0)
5038 5043 worklist = add_list(worklist, group, 0,
5039 5044 protocol);
5040 5045 if (state != NULL)
5041 5046 sa_free_attr_string(state);
5042 5047 }
5043 5048 }
5044 5049
5045 5050 (void) enable_all_groups(handle, worklist, 0, 1, protocol, B_FALSE);
5046 5051
5047 5052 if (worklist != NULL)
5048 5053 free_list(worklist);
5049 5054 return (ret);
5050 5055 }
5051 5056
5052 5057 /*
5053 5058 * sa_stop_group(flags, argc, argv)
5054 5059 *
5055 5060 * Implements the stop command.
5056 5061 * This is similar to disable except it doesn't change the state
5057 5062 * of the group(s) and only disables shares if the group is already
5058 5063 * enabled.
5059 5064 */
5060 5065 int
5061 5066 sa_stop_group(sa_handle_t handle, int flags, int argc, char *argv[])
5062 5067 {
5063 5068 int verbose = 0;
5064 5069 int all = 0;
5065 5070 int c;
5066 5071 int ret = SMF_EXIT_OK;
5067 5072 char *protocol = NULL;
5068 5073 char *state;
5069 5074 struct list *worklist = NULL;
5070 5075 sa_group_t group;
5071 5076 #ifdef lint
5072 5077 flags = flags;
5073 5078 #endif
5074 5079
5075 5080 while ((c = getopt(argc, argv, "?havP:")) != EOF) {
5076 5081 switch (c) {
5077 5082 case 'a':
5078 5083 all = 1;
5079 5084 break;
5080 5085 case 'P':
5081 5086 if (protocol != NULL) {
5082 5087 (void) printf(gettext(
5083 5088 "Specifying multiple protocols "
5084 5089 "not supported: %s\n"), protocol);
5085 5090 return (SA_SYNTAX_ERR);
5086 5091 }
5087 5092 protocol = optarg;
5088 5093 if (!sa_valid_protocol(protocol)) {
5089 5094 (void) printf(gettext(
5090 5095 "Invalid protocol specified: %s\n"),
5091 5096 protocol);
5092 5097 return (SA_INVALID_PROTOCOL);
5093 5098 }
5094 5099 break;
5095 5100 case 'v':
5096 5101 verbose++;
5097 5102 break;
5098 5103 case 'h':
5099 5104 /* optopt on valid arg isn't defined */
5100 5105 optopt = c;
5101 5106 /*FALLTHROUGH*/
5102 5107 case '?':
5103 5108 default:
5104 5109 /*
5105 5110 * Since a bad option gets to here, sort it
5106 5111 * out and return a syntax error return value
5107 5112 * if necessary.
5108 5113 */
5109 5114 ret = SA_OK;
5110 5115 switch (optopt) {
5111 5116 default:
5112 5117 ret = SA_SYNTAX_ERR;
5113 5118 break;
5114 5119 case 'h':
5115 5120 case '?':
5116 5121 break;
5117 5122 }
5118 5123 (void) printf(gettext("usage: %s\n"),
5119 5124 sa_get_usage(USAGE_STOP));
5120 5125 return (ret);
5121 5126 }
5122 5127 }
5123 5128
5124 5129 if (optind == argc && !all) {
5125 5130 (void) printf(gettext("usage: %s\n"),
5126 5131 sa_get_usage(USAGE_STOP));
5127 5132 return (SMF_EXIT_ERR_FATAL);
5128 5133 } else if (!all) {
5129 5134 while (optind < argc) {
5130 5135 group = sa_get_group(handle, argv[optind]);
5131 5136 if (group != NULL) {
5132 5137 state = sa_get_group_attr(group, "state");
5133 5138 if (state == NULL ||
5134 5139 strcmp(state, "enabled") == 0) {
5135 5140 worklist = add_list(worklist, group, 0,
5136 5141 protocol);
5137 5142 if (verbose)
5138 5143 (void) printf(gettext(
5139 5144 "Stopping group \"%s\"\n"),
5140 5145 argv[optind]);
5141 5146 } else {
5142 5147 ret = SMF_EXIT_OK;
5143 5148 }
5144 5149 if (state != NULL)
5145 5150 sa_free_attr_string(state);
5146 5151 }
5147 5152 optind++;
5148 5153 }
5149 5154 } else {
5150 5155 for (group = sa_get_group(handle, NULL);
5151 5156 group != NULL;
5152 5157 group = sa_get_next_group(group)) {
5153 5158 state = sa_get_group_attr(group, "state");
5154 5159 if (state == NULL || strcmp(state, "enabled") == 0)
5155 5160 worklist = add_list(worklist, group, 0,
5156 5161 protocol);
5157 5162 if (state != NULL)
5158 5163 sa_free_attr_string(state);
5159 5164 }
5160 5165 }
5161 5166 (void) disable_all_groups(handle, worklist, 0);
5162 5167 ret = sa_update_config(handle);
5163 5168
5164 5169 if (worklist != NULL)
5165 5170 free_list(worklist);
5166 5171 return (ret);
5167 5172 }
5168 5173
5169 5174 /*
5170 5175 * remove_all_options(share, proto)
5171 5176 *
5172 5177 * Removes all options on a share.
5173 5178 */
5174 5179
5175 5180 static void
5176 5181 remove_all_options(sa_share_t share, char *proto)
5177 5182 {
5178 5183 sa_optionset_t optionset;
5179 5184 sa_security_t security;
5180 5185 sa_security_t prevsec = NULL;
5181 5186
5182 5187 optionset = sa_get_optionset(share, proto);
5183 5188 if (optionset != NULL)
5184 5189 (void) sa_destroy_optionset(optionset);
5185 5190 for (security = sa_get_security(share, NULL, NULL);
5186 5191 security != NULL;
5187 5192 security = sa_get_next_security(security)) {
5188 5193 char *type;
5189 5194 /*
5190 5195 * We walk through the list. prevsec keeps the
5191 5196 * previous security so we can delete it without
5192 5197 * destroying the list.
5193 5198 */
5194 5199 if (prevsec != NULL) {
5195 5200 /* remove the previously seen security */
5196 5201 (void) sa_destroy_security(prevsec);
5197 5202 /* set to NULL so we don't try multiple times */
5198 5203 prevsec = NULL;
5199 5204 }
5200 5205 type = sa_get_security_attr(security, "type");
5201 5206 if (type != NULL) {
5202 5207 /*
5203 5208 * if the security matches the specified protocol, we
5204 5209 * want to remove it. prevsec holds it until either
5205 5210 * the next pass or we fall out of the loop.
5206 5211 */
5207 5212 if (strcmp(type, proto) == 0)
5208 5213 prevsec = security;
5209 5214 sa_free_attr_string(type);
5210 5215 }
5211 5216 }
5212 5217 /* in case there is one left */
5213 5218 if (prevsec != NULL)
5214 5219 (void) sa_destroy_security(prevsec);
5215 5220 }
5216 5221
5217 5222
5218 5223 /*
5219 5224 * for legacy support, we need to handle the old syntax. This is what
5220 5225 * we get if sharemgr is called with the name "share" rather than
5221 5226 * sharemgr.
5222 5227 */
5223 5228
5224 5229 static int
5225 5230 format_legacy_path(char *buff, int buffsize, char *proto, char *cmd)
5226 5231 {
5227 5232 int err;
5228 5233
5229 5234 err = snprintf(buff, buffsize, "/usr/lib/fs/%s/%s", proto, cmd);
5230 5235 if (err > buffsize)
5231 5236 return (-1);
5232 5237 return (0);
5233 5238 }
5234 5239
5235 5240
5236 5241 /*
5237 5242 * check_legacy_cmd(proto, cmd)
5238 5243 *
5239 5244 * Check to see if the cmd exists in /usr/lib/fs/<proto>/<cmd> and is
5240 5245 * executable.
5241 5246 */
5242 5247
5243 5248 static int
5244 5249 check_legacy_cmd(char *path)
5245 5250 {
5246 5251 struct stat st;
5247 5252 int ret = 0;
5248 5253
5249 5254 if (stat(path, &st) == 0) {
5250 5255 if (S_ISREG(st.st_mode) &&
5251 5256 st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
5252 5257 ret = 1;
5253 5258 }
5254 5259 return (ret);
5255 5260 }
5256 5261
5257 5262 /*
5258 5263 * run_legacy_command(proto, cmd, argv)
5259 5264 *
5260 5265 * We know the command exists, so attempt to execute it with all the
5261 5266 * arguments. This implements full legacy share support for those
5262 5267 * protocols that don't have plugin providers.
5263 5268 */
5264 5269
5265 5270 static int
5266 5271 run_legacy_command(char *path, char *argv[])
5267 5272 {
5268 5273 int ret;
5269 5274
5270 5275 ret = execv(path, argv);
5271 5276 if (ret < 0) {
5272 5277 switch (errno) {
5273 5278 case EACCES:
5274 5279 ret = SA_NO_PERMISSION;
5275 5280 break;
5276 5281 default:
5277 5282 ret = SA_SYSTEM_ERR;
5278 5283 break;
5279 5284 }
5280 5285 }
5281 5286 return (ret);
5282 5287 }
5283 5288
5284 5289 /*
5285 5290 * out_share(out, group, proto)
5286 5291 *
5287 5292 * Display the share information in the format that the "share"
5288 5293 * command has traditionally used.
5289 5294 */
5290 5295
5291 5296 static void
5292 5297 out_share(FILE *out, sa_group_t group, char *proto)
5293 5298 {
5294 5299 sa_share_t share;
5295 5300 char resfmt[128];
5296 5301 char *defprop;
5297 5302
5298 5303 /*
5299 5304 * The original share command defaulted to displaying NFS
5300 5305 * shares or allowed a protocol to be specified. We want to
5301 5306 * skip those shares that are not the specified protocol.
5302 5307 */
5303 5308 if (proto != NULL && sa_get_optionset(group, proto) == NULL)
5304 5309 return;
5305 5310
5306 5311 if (proto == NULL)
5307 5312 proto = "nfs";
5308 5313
5309 5314 /*
5310 5315 * get the default property string. NFS uses "rw" but
5311 5316 * everything else will use "".
5312 5317 */
5313 5318 if (proto != NULL && strcmp(proto, "nfs") != 0)
5314 5319 defprop = "\"\"";
5315 5320 else
5316 5321 defprop = "rw";
5317 5322
5318 5323 for (share = sa_get_share(group, NULL);
5319 5324 share != NULL;
5320 5325 share = sa_get_next_share(share)) {
5321 5326 char *path;
5322 5327 char *type;
5323 5328 char *resource;
5324 5329 char *description;
5325 5330 char *groupname;
5326 5331 char *sharedstate;
5327 5332 int shared = 1;
5328 5333 char *soptions;
5329 5334 char shareopts[MAXNAMLEN];
5330 5335
5331 5336 sharedstate = sa_get_share_attr(share, "shared");
5332 5337 path = sa_get_share_attr(share, "path");
5333 5338 type = sa_get_share_attr(share, "type");
5334 5339 resource = get_resource(share);
5335 5340 groupname = sa_get_group_attr(group, "name");
5336 5341
5337 5342 if (groupname != NULL && strcmp(groupname, "default") == 0) {
5338 5343 sa_free_attr_string(groupname);
5339 5344 groupname = NULL;
5340 5345 }
5341 5346 description = sa_get_share_description(share);
5342 5347
5343 5348 /*
5344 5349 * Want the sharetab version if it exists, defaulting
5345 5350 * to NFS if no protocol specified.
5346 5351 */
5347 5352 (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", proto);
5348 5353 soptions = sa_get_share_attr(share, shareopts);
5349 5354
5350 5355 if (sharedstate == NULL)
5351 5356 shared = 0;
5352 5357
5353 5358 if (soptions == NULL)
5354 5359 soptions = sa_proto_legacy_format(proto, share, 1);
5355 5360
5356 5361 if (shared) {
5357 5362 /* only active shares go here */
5358 5363 (void) snprintf(resfmt, sizeof (resfmt), "%s%s%s",
5359 5364 resource != NULL ? resource : "-",
5360 5365 groupname != NULL ? "@" : "",
5361 5366 groupname != NULL ? groupname : "");
5362 5367 (void) fprintf(out, "%-14.14s %s %s \"%s\" \n",
5363 5368 resfmt, (path != NULL) ? path : "",
5364 5369 (soptions != NULL && strlen(soptions) > 0) ?
5365 5370 soptions : defprop,
5366 5371 (description != NULL) ? description : "");
5367 5372 }
5368 5373
5369 5374 if (path != NULL)
5370 5375 sa_free_attr_string(path);
5371 5376 if (type != NULL)
5372 5377 sa_free_attr_string(type);
5373 5378 if (resource != NULL)
5374 5379 sa_free_attr_string(resource);
5375 5380 if (groupname != NULL)
5376 5381 sa_free_attr_string(groupname);
5377 5382 if (description != NULL)
5378 5383 sa_free_share_description(description);
5379 5384 if (sharedstate != NULL)
5380 5385 sa_free_attr_string(sharedstate);
5381 5386 if (soptions != NULL)
5382 5387 sa_format_free(soptions);
5383 5388 }
5384 5389 }
5385 5390
5386 5391 /*
5387 5392 * output_legacy_file(out, proto)
5388 5393 *
5389 5394 * Walk all of the groups for the specified protocol and call
5390 5395 * out_share() to format and write in the format displayed by the
5391 5396 * "share" command with no arguments.
5392 5397 */
5393 5398
5394 5399 static void
5395 5400 output_legacy_file(FILE *out, char *proto, sa_handle_t handle)
5396 5401 {
5397 5402 sa_group_t group;
5398 5403
5399 5404 for (group = sa_get_group(handle, NULL);
5400 5405 group != NULL;
5401 5406 group = sa_get_next_group(group)) {
5402 5407 char *zfs;
5403 5408
5404 5409 /*
5405 5410 * Go through all the groups and ZFS
5406 5411 * sub-groups. out_share() will format the shares in
5407 5412 * the group appropriately.
5408 5413 */
5409 5414
5410 5415 zfs = sa_get_group_attr(group, "zfs");
5411 5416 if (zfs != NULL) {
5412 5417 sa_group_t zgroup;
5413 5418 sa_free_attr_string(zfs);
5414 5419 for (zgroup = sa_get_sub_group(group);
5415 5420 zgroup != NULL;
5416 5421 zgroup = sa_get_next_group(zgroup)) {
5417 5422
5418 5423 /* got a group, so display it */
5419 5424 out_share(out, zgroup, proto);
5420 5425 }
5421 5426 } else {
5422 5427 out_share(out, group, proto);
5423 5428 }
5424 5429 }
5425 5430 }
5426 5431
5427 5432 int
5428 5433 sa_legacy_share(sa_handle_t handle, int flags, int argc, char *argv[])
5429 5434 {
5430 5435 char *protocol = "nfs";
5431 5436 char *options = NULL;
5432 5437 char *description = NULL;
5433 5438 char *groupname = NULL;
5434 5439 char *sharepath = NULL;
5435 5440 char *resource = NULL;
5436 5441 char *groupstatus = NULL;
5437 5442 int persist = SA_SHARE_TRANSIENT;
5438 5443 int argsused = 0;
5439 5444 int c;
5440 5445 int ret = SA_OK;
5441 5446 int zfs = 0;
5442 5447 int true_legacy = 0;
5443 5448 int curtype = SA_SHARE_TRANSIENT;
5444 5449 char cmd[MAXPATHLEN];
5445 5450 sa_group_t group = NULL;
5446 5451 sa_resource_t rsrc = NULL;
5447 5452 sa_share_t share;
5448 5453 char dir[MAXPATHLEN];
5449 5454 uint64_t features;
5450 5455 #ifdef lint
5451 5456 flags = flags;
5452 5457 #endif
5453 5458
5454 5459 while ((c = getopt(argc, argv, "?hF:d:o:p")) != EOF) {
5455 5460 switch (c) {
5456 5461 case 'd':
5457 5462 description = optarg;
5458 5463 argsused++;
5459 5464 break;
5460 5465 case 'F':
5461 5466 protocol = optarg;
5462 5467 if (!sa_valid_protocol(protocol)) {
5463 5468 if (format_legacy_path(cmd, MAXPATHLEN,
5464 5469 protocol, "share") == 0 &&
5465 5470 check_legacy_cmd(cmd)) {
5466 5471 true_legacy++;
5467 5472 } else {
5468 5473 (void) fprintf(stderr, gettext(
5469 5474 "Invalid protocol specified: "
5470 5475 "%s\n"), protocol);
5471 5476 return (SA_INVALID_PROTOCOL);
5472 5477 }
5473 5478 }
5474 5479 break;
5475 5480 case 'o':
5476 5481 options = optarg;
5477 5482 argsused++;
5478 5483 break;
5479 5484 case 'p':
5480 5485 persist = SA_SHARE_PERMANENT;
5481 5486 argsused++;
5482 5487 break;
5483 5488 case 'h':
5484 5489 /* optopt on valid arg isn't defined */
5485 5490 optopt = c;
5486 5491 /*FALLTHROUGH*/
5487 5492 case '?':
5488 5493 default:
5489 5494 /*
5490 5495 * Since a bad option gets to here, sort it
5491 5496 * out and return a syntax error return value
5492 5497 * if necessary.
5493 5498 */
5494 5499 switch (optopt) {
5495 5500 default:
5496 5501 ret = SA_LEGACY_ERR;
5497 5502 break;
5498 5503 case 'h':
5499 5504 case '?':
5500 5505 break;
5501 5506 }
5502 5507 (void) fprintf(stderr, gettext("usage: %s\n"),
5503 5508 sa_get_usage(USAGE_SHARE));
5504 5509 return (ret);
5505 5510 }
5506 5511 }
5507 5512
5508 5513 /* Have the info so construct what is needed */
5509 5514 if (!argsused && optind == argc) {
5510 5515 /* display current info in share format */
5511 5516 (void) output_legacy_file(stdout, protocol, handle);
5512 5517 return (ret);
5513 5518 }
5514 5519
5515 5520 /* We are modifying the configuration */
5516 5521 if (optind == argc) {
5517 5522 (void) fprintf(stderr, gettext("usage: %s\n"),
5518 5523 sa_get_usage(USAGE_SHARE));
5519 5524 return (SA_LEGACY_ERR);
5520 5525 }
5521 5526 if (true_legacy) {
5522 5527 /* If still using legacy share/unshare, exec it */
5523 5528 ret = run_legacy_command(cmd, argv);
5524 5529 return (ret);
5525 5530 }
5526 5531
5527 5532 sharepath = argv[optind++];
5528 5533 if (optind < argc) {
5529 5534 resource = argv[optind];
5530 5535 groupname = strchr(resource, '@');
5531 5536 if (groupname != NULL)
5532 5537 *groupname++ = '\0';
5533 5538 }
5534 5539 if (realpath(sharepath, dir) == NULL)
5535 5540 ret = SA_BAD_PATH;
5536 5541 else
5537 5542 sharepath = dir;
5538 5543 if (ret == SA_OK)
5539 5544 share = sa_find_share(handle, sharepath);
5540 5545 else
5541 5546 share = NULL;
5542 5547
5543 5548 features = sa_proto_get_featureset(protocol);
5544 5549
5545 5550 if (groupname != NULL) {
5546 5551 ret = SA_NOT_ALLOWED;
5547 5552 } else if (ret == SA_OK) {
5548 5553 char *legacygroup;
5549 5554 /*
5550 5555 * The legacy group is always present and zfs groups
5551 5556 * come and go. zfs shares may be in sub-groups and
5552 5557 * the zfs share will already be in that group so it
5553 5558 * isn't an error. If the protocol is "smb", the group
5554 5559 * "smb" is used when "default" would otherwise be
5555 5560 * used. "default" is NFS only and "smb" is SMB only.
5556 5561 */
5557 5562 if (strcmp(protocol, "smb") == 0)
5558 5563 legacygroup = "smb";
5559 5564 else
5560 5565 legacygroup = "default";
5561 5566
5562 5567 /*
5563 5568 * If the share exists (not NULL), then make sure it
5564 5569 * is one we want to handle by getting the parent
5565 5570 * group.
5566 5571 */
5567 5572 if (share != NULL) {
5568 5573 group = sa_get_parent_group(share);
5569 5574 } else {
5570 5575 group = sa_get_group(handle, legacygroup);
5571 5576 if (group == NULL && strcmp(legacygroup, "smb") == 0) {
5572 5577 /*
5573 5578 * This group may not exist, so create
5574 5579 * as necessary. It only contains the
5575 5580 * "smb" protocol.
5576 5581 */
5577 5582 group = sa_create_group(handle, legacygroup,
5578 5583 &ret);
5579 5584 if (group != NULL)
5580 5585 (void) sa_create_optionset(group,
5581 5586 protocol);
5582 5587 }
5583 5588 }
5584 5589
5585 5590 if (group == NULL) {
5586 5591 ret = SA_SYSTEM_ERR;
5587 5592 goto err;
5588 5593 }
5589 5594
5590 5595 groupstatus = group_status(group);
5591 5596 if (share == NULL) {
5592 5597 share = sa_add_share(group, sharepath,
5593 5598 persist, &ret);
5594 5599 if (share == NULL &&
5595 5600 ret == SA_DUPLICATE_NAME) {
5596 5601 /*
5597 5602 * Could be a ZFS path being started
5598 5603 */
5599 5604 if (sa_zfs_is_shared(handle,
5600 5605 sharepath)) {
5601 5606 ret = SA_OK;
5602 5607 group = sa_get_group(handle,
5603 5608 "zfs");
5604 5609 if (group == NULL) {
5605 5610 /*
5606 5611 * This shouldn't
5607 5612 * happen.
5608 5613 */
5609 5614 ret = SA_CONFIG_ERR;
5610 5615 } else {
5611 5616 share = sa_add_share(
5612 5617 group, sharepath,
5613 5618 persist, &ret);
5614 5619 }
5615 5620 }
5616 5621 }
5617 5622 } else {
5618 5623 char *type;
5619 5624 /*
5620 5625 * May want to change persist state, but the
5621 5626 * important thing is to change options. We
5622 5627 * need to change them regardless of the
5623 5628 * source.
5624 5629 */
5625 5630
5626 5631 if (sa_zfs_is_shared(handle, sharepath)) {
5627 5632 zfs = 1;
5628 5633 }
5629 5634 remove_all_options(share, protocol);
5630 5635 type = sa_get_share_attr(share, "type");
5631 5636 if (type != NULL &&
5632 5637 strcmp(type, "transient") != 0) {
5633 5638 curtype = SA_SHARE_PERMANENT;
5634 5639 }
5635 5640 if (type != NULL)
5636 5641 sa_free_attr_string(type);
5637 5642 if (curtype != persist) {
5638 5643 (void) sa_set_share_attr(share, "type",
5639 5644 persist == SA_SHARE_PERMANENT ?
5640 5645 "persist" : "transient");
5641 5646 }
5642 5647 }
5643 5648
5644 5649 /*
5645 5650 * If there is a resource name, we may
5646 5651 * actually care about it if this is share for
5647 5652 * a protocol that uses resource level sharing
5648 5653 * (SMB). We need to find the resource and, if
5649 5654 * it exists, make sure it belongs to the
5650 5655 * current share. If it doesn't exist, attempt
5651 5656 * to create it.
5652 5657 */
5653 5658
5654 5659 if (ret == SA_OK && resource != NULL) {
5655 5660 rsrc = sa_find_resource(handle, resource);
5656 5661 if (rsrc != NULL) {
5657 5662 if (share != sa_get_resource_parent(rsrc))
5658 5663 ret = SA_DUPLICATE_NAME;
5659 5664 } else {
5660 5665 rsrc = sa_add_resource(share, resource,
5661 5666 persist, &ret);
5662 5667 }
5663 5668 if (features & SA_FEATURE_RESOURCE)
5664 5669 share = rsrc;
5665 5670 }
5666 5671
5667 5672 /* Have a group to hold this share path */
5668 5673 if (ret == SA_OK && options != NULL &&
5669 5674 strlen(options) > 0) {
5670 5675 ret = sa_parse_legacy_options(share,
5671 5676 options,
5672 5677 protocol);
5673 5678 }
5674 5679 if (!zfs) {
5675 5680 /*
5676 5681 * ZFS shares never have a description
5677 5682 * and we can't store the values so
5678 5683 * don't try.
5679 5684 */
5680 5685 if (ret == SA_OK && description != NULL)
5681 5686 ret = sa_set_share_description(share,
5682 5687 description);
5683 5688 }
5684 5689 if (ret == SA_OK &&
5685 5690 strcmp(groupstatus, "enabled") == 0) {
5686 5691 if (rsrc != share)
5687 5692 ret = sa_enable_share(share, protocol);
5688 5693 else
5689 5694 ret = sa_enable_resource(rsrc,
5690 5695 protocol);
5691 5696 if (ret == SA_OK &&
5692 5697 persist == SA_SHARE_PERMANENT) {
5693 5698 (void) sa_update_legacy(share,
5694 5699 protocol);
5695 5700 }
5696 5701 if (ret == SA_OK)
5697 5702 ret = sa_update_config(handle);
5698 5703 }
5699 5704 }
5700 5705 err:
5701 5706 if (ret != SA_OK) {
5702 5707 (void) fprintf(stderr, gettext("Could not share: %s: %s\n"),
5703 5708 sharepath, sa_errorstr(ret));
5704 5709 ret = SA_LEGACY_ERR;
5705 5710 }
5706 5711 return (ret);
5707 5712 }
5708 5713
5709 5714 /*
5710 5715 * sa_legacy_unshare(flags, argc, argv)
5711 5716 *
5712 5717 * Implements the original unshare command.
5713 5718 */
5714 5719 int
5715 5720 sa_legacy_unshare(sa_handle_t handle, int flags, int argc, char *argv[])
5716 5721 {
5717 5722 char *protocol = "nfs"; /* for now */
5718 5723 char *options = NULL;
5719 5724 char *sharepath = NULL;
5720 5725 int persist = SA_SHARE_TRANSIENT;
5721 5726 int argsused = 0;
5722 5727 int c;
5723 5728 int ret = SA_OK;
5724 5729 int true_legacy = 0;
5725 5730 uint64_t features = 0;
5726 5731 sa_resource_t resource = NULL;
5727 5732 char cmd[MAXPATHLEN];
5728 5733 #ifdef lint
5729 5734 flags = flags;
5730 5735 options = options;
5731 5736 #endif
5732 5737
5733 5738 while ((c = getopt(argc, argv, "?hF:o:p")) != EOF) {
5734 5739 switch (c) {
5735 5740 case 'F':
5736 5741 protocol = optarg;
5737 5742 if (!sa_valid_protocol(protocol)) {
5738 5743 if (format_legacy_path(cmd, MAXPATHLEN,
5739 5744 protocol, "unshare") == 0 &&
5740 5745 check_legacy_cmd(cmd)) {
5741 5746 true_legacy++;
5742 5747 } else {
5743 5748 (void) printf(gettext(
5744 5749 "Invalid file system name\n"));
5745 5750 return (SA_INVALID_PROTOCOL);
5746 5751 }
5747 5752 }
5748 5753 break;
5749 5754 case 'o':
5750 5755 options = optarg;
5751 5756 argsused++;
5752 5757 break;
5753 5758 case 'p':
5754 5759 persist = SA_SHARE_PERMANENT;
5755 5760 argsused++;
5756 5761 break;
5757 5762 case 'h':
5758 5763 /* optopt on valid arg isn't defined */
5759 5764 optopt = c;
5760 5765 /*FALLTHROUGH*/
5761 5766 case '?':
5762 5767 default:
5763 5768 /*
5764 5769 * Since a bad option gets to here, sort it
5765 5770 * out and return a syntax error return value
5766 5771 * if necessary.
5767 5772 */
5768 5773 switch (optopt) {
5769 5774 default:
5770 5775 ret = SA_LEGACY_ERR;
5771 5776 break;
5772 5777 case 'h':
5773 5778 case '?':
5774 5779 break;
5775 5780 }
5776 5781 (void) printf(gettext("usage: %s\n"),
5777 5782 sa_get_usage(USAGE_UNSHARE));
5778 5783 return (ret);
5779 5784 }
5780 5785 }
5781 5786
5782 5787 /* Have the info so construct what is needed */
5783 5788 if (optind == argc || (optind + 1) < argc || options != NULL) {
5784 5789 ret = SA_SYNTAX_ERR;
5785 5790 } else {
5786 5791 sa_share_t share;
5787 5792 char dir[MAXPATHLEN];
5788 5793 if (true_legacy) {
5789 5794 /* if still using legacy share/unshare, exec it */
5790 5795 ret = run_legacy_command(cmd, argv);
5791 5796 return (ret);
5792 5797 }
5793 5798 /*
5794 5799 * Find the path in the internal configuration. If it
5795 5800 * isn't found, attempt to resolve the path via
5796 5801 * realpath() and try again.
5797 5802 */
5798 5803 sharepath = argv[optind++];
5799 5804 share = sa_find_share(handle, sharepath);
5800 5805 if (share == NULL) {
5801 5806 if (realpath(sharepath, dir) == NULL) {
5802 5807 ret = SA_NO_SUCH_PATH;
5803 5808 } else {
5804 5809 share = sa_find_share(handle, dir);
5805 5810 }
5806 5811 }
5807 5812 if (share == NULL) {
5808 5813 /* Could be a resource name so check that next */
5809 5814 features = sa_proto_get_featureset(protocol);
5810 5815 resource = sa_find_resource(handle, sharepath);
5811 5816 if (resource != NULL) {
5812 5817 share = sa_get_resource_parent(resource);
5813 5818 if (features & SA_FEATURE_RESOURCE)
5814 5819 (void) sa_disable_resource(resource,
5815 5820 protocol);
5816 5821 if (persist == SA_SHARE_PERMANENT) {
5817 5822 ret = sa_remove_resource(resource);
5818 5823 if (ret == SA_OK)
5819 5824 ret = sa_update_config(handle);
5820 5825 }
5821 5826 /*
5822 5827 * If we still have a resource on the
5823 5828 * share, we don't disable the share
5824 5829 * itself. IF there aren't anymore, we
5825 5830 * need to remove the share. The
5826 5831 * removal will be done in the next
5827 5832 * section if appropriate.
5828 5833 */
5829 5834 resource = sa_get_share_resource(share, NULL);
5830 5835 if (resource != NULL)
5831 5836 share = NULL;
5832 5837 } else if (ret == SA_OK) {
5833 5838 /* Didn't find path and no resource */
5834 5839 ret = SA_BAD_PATH;
5835 5840 }
5836 5841 }
5837 5842 if (share != NULL && resource == NULL) {
5838 5843 ret = sa_disable_share(share, protocol);
5839 5844 /*
5840 5845 * Errors are ok and removal should still occur. The
5841 5846 * legacy unshare is more forgiving of errors than the
5842 5847 * remove-share subcommand which may need the force
5843 5848 * flag set for some error conditions. That is, the
5844 5849 * "unshare" command will always unshare if it can
5845 5850 * while "remove-share" might require the force option.
5846 5851 */
5847 5852 if (persist == SA_SHARE_PERMANENT) {
5848 5853 ret = sa_remove_share(share);
5849 5854 if (ret == SA_OK)
5850 5855 ret = sa_update_config(handle);
5851 5856 }
5852 5857 } else if (ret == SA_OK && share == NULL && resource == NULL) {
5853 5858 /*
5854 5859 * If both share and resource are NULL, then
5855 5860 * share not found. If one or the other was
5856 5861 * found or there was an earlier error, we
5857 5862 * assume it was handled earlier.
5858 5863 */
5859 5864 ret = SA_NOT_SHARED;
5860 5865 }
5861 5866 }
5862 5867 switch (ret) {
5863 5868 default:
5864 5869 (void) printf("%s: %s\n", sharepath, sa_errorstr(ret));
5865 5870 ret = SA_LEGACY_ERR;
5866 5871 break;
5867 5872 case SA_SYNTAX_ERR:
5868 5873 (void) printf(gettext("usage: %s\n"),
5869 5874 sa_get_usage(USAGE_UNSHARE));
5870 5875 break;
5871 5876 case SA_OK:
5872 5877 break;
5873 5878 }
5874 5879 return (ret);
5875 5880 }
5876 5881
5877 5882 /*
5878 5883 * Common commands that implement the sub-commands used by all
5879 5884 * protocols. The entries are found via the lookup command
5880 5885 */
5881 5886
5882 5887 static sa_command_t commands[] = {
5883 5888 {"add-share", 0, sa_addshare, USAGE_ADD_SHARE, SVC_SET},
5884 5889 {"create", 0, sa_create, USAGE_CREATE, SVC_SET|SVC_ACTION},
5885 5890 {"delete", 0, sa_delete, USAGE_DELETE, SVC_SET|SVC_ACTION},
5886 5891 {"disable", 0, sa_disable_group, USAGE_DISABLE, SVC_SET|SVC_ACTION},
5887 5892 {"enable", 0, sa_enable_group, USAGE_ENABLE, SVC_SET|SVC_ACTION},
5888 5893 {"list", 0, sa_list, USAGE_LIST},
5889 5894 {"move-share", 0, sa_moveshare, USAGE_MOVE_SHARE, SVC_SET},
5890 5895 {"remove-share", 0, sa_removeshare, USAGE_REMOVE_SHARE, SVC_SET},
5891 5896 {"set", 0, sa_set, USAGE_SET, SVC_SET},
5892 5897 {"set-share", 0, sa_set_share, USAGE_SET_SHARE, SVC_SET},
5893 5898 {"show", 0, sa_show, USAGE_SHOW},
5894 5899 {"share", 0, sa_legacy_share, USAGE_SHARE, SVC_SET|SVC_ACTION},
5895 5900 {"start", CMD_NODISPLAY, sa_start_group, USAGE_START,
5896 5901 SVC_SET|SVC_ACTION},
5897 5902 {"stop", CMD_NODISPLAY, sa_stop_group, USAGE_STOP, SVC_SET|SVC_ACTION},
5898 5903 {"unset", 0, sa_unset, USAGE_UNSET, SVC_SET},
5899 5904 {"unshare", 0, sa_legacy_unshare, USAGE_UNSHARE, SVC_SET|SVC_ACTION},
5900 5905 {NULL, 0, NULL, NULL}
5901 5906 };
5902 5907
5903 5908 static char *
5904 5909 sa_get_usage(sa_usage_t index)
5905 5910 {
5906 5911 char *ret = NULL;
5907 5912 switch (index) {
5908 5913 case USAGE_ADD_SHARE:
5909 5914 ret = gettext("add-share [-nth] [-r resource-name] "
5910 5915 "[-d \"description text\"] -s sharepath group");
5911 5916 break;
5912 5917 case USAGE_CREATE:
5913 5918 ret = gettext(
5914 5919 "create [-nvh] [-P proto [-p property=value]] group");
5915 5920 break;
5916 5921 case USAGE_DELETE:
5917 5922 ret = gettext("delete [-nvh] [-P proto] [-f] group");
5918 5923 break;
5919 5924 case USAGE_DISABLE:
5920 5925 ret = gettext("disable [-nvh] {-a | group ...}");
5921 5926 break;
5922 5927 case USAGE_ENABLE:
5923 5928 ret = gettext("enable [-nvh] {-a | group ...}");
5924 5929 break;
5925 5930 case USAGE_LIST:
5926 5931 ret = gettext("list [-vh] [-P proto]");
5927 5932 break;
5928 5933 case USAGE_MOVE_SHARE:
5929 5934 ret = gettext(
5930 5935 "move-share [-nvh] -s sharepath destination-group");
5931 5936 break;
5932 5937 case USAGE_REMOVE_SHARE:
5933 5938 ret = gettext(
5934 5939 "remove-share [-fnvh] {-s sharepath | -r resource} "
5935 5940 "group");
5936 5941 break;
5937 5942 case USAGE_SET:
5938 5943 ret = gettext("set [-nvh] -P proto [-S optspace] "
5939 5944 "[-p property=value]* [-s sharepath] [-r resource]] "
5940 5945 "group");
5941 5946 break;
5942 5947 case USAGE_SET_SECURITY:
5943 5948 ret = gettext("set-security [-nvh] -P proto -S security-type "
5944 5949 "[-p property=value]* group");
5945 5950 break;
5946 5951 case USAGE_SET_SHARE:
5947 5952 ret = gettext("set-share [-nh] [-r resource] "
5948 5953 "[-d \"description text\"] -s sharepath group");
5949 5954 break;
5950 5955 case USAGE_SHOW:
5951 5956 ret = gettext("show [-pvxh] [-P proto] [group ...]");
5952 5957 break;
5953 5958 case USAGE_SHARE:
5954 5959 ret = gettext("share [-F fstype] [-p] [-o optionlist]"
5955 5960 "[-d description] [pathname [resourcename]]");
5956 5961 break;
5957 5962 case USAGE_START:
5958 5963 ret = gettext("start [-vh] [-P proto] {-a | group ...}");
5959 5964 break;
5960 5965 case USAGE_STOP:
5961 5966 ret = gettext("stop [-vh] [-P proto] {-a | group ...}");
5962 5967 break;
5963 5968 case USAGE_UNSET:
5964 5969 ret = gettext("unset [-nvh] -P proto [-S optspace] "
5965 5970 "[-p property]* group");
5966 5971 break;
5967 5972 case USAGE_UNSET_SECURITY:
5968 5973 ret = gettext("unset-security [-nvh] -P proto "
5969 5974 "-S security-type [-p property]* group");
5970 5975 break;
5971 5976 case USAGE_UNSHARE:
5972 5977 ret = gettext(
5973 5978 "unshare [-F fstype] [-p] [-o optionlist] sharepath");
5974 5979 break;
5975 5980 }
5976 5981 return (ret);
5977 5982 }
5978 5983
5979 5984 /*
5980 5985 * sa_lookup(cmd, proto)
5981 5986 *
5982 5987 * Lookup the sub-command. proto isn't currently used, but it may
5983 5988 * eventually provide a way to provide protocol specific sub-commands.
5984 5989 */
5985 5990 sa_command_t *
5986 5991 sa_lookup(char *cmd, char *proto)
5987 5992 {
5988 5993 int i;
5989 5994 size_t len;
5990 5995 #ifdef lint
5991 5996 proto = proto;
5992 5997 #endif
5993 5998
5994 5999 len = strlen(cmd);
5995 6000 for (i = 0; commands[i].cmdname != NULL; i++) {
5996 6001 if (strncmp(cmd, commands[i].cmdname, len) == 0)
5997 6002 return (&commands[i]);
5998 6003 }
5999 6004 return (NULL);
6000 6005 }
6001 6006
6002 6007 void
6003 6008 sub_command_help(char *proto)
6004 6009 {
6005 6010 int i;
6006 6011 #ifdef lint
6007 6012 proto = proto;
6008 6013 #endif
6009 6014
6010 6015 (void) printf(gettext("\tsub-commands:\n"));
6011 6016 for (i = 0; commands[i].cmdname != NULL; i++) {
6012 6017 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
6013 6018 (void) printf("\t%s\n",
6014 6019 sa_get_usage((sa_usage_t)commands[i].cmdidx));
6015 6020 }
6016 6021 }
|
↓ open down ↓ |
3813 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX