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