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