1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 * Copyright 2016 Nexenta Systems, Inc.
27 */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <getopt.h>
35 #include <libgen.h>
36
37 #include "libshare.h"
38 #include <sharemgr.h>
39
40 #include <libintl.h>
41 #include <locale.h>
42
43 static int run_command(char *, int, char **, sa_handle_t);
44 static void sub_command_help(char *proto);
45
46 static void
global_help()47 global_help()
48 {
49 (void) printf(gettext("usage: sharectl <subcommand> [<options>]\n"));
50 sub_command_help(NULL);
51 }
52
53 int
main(int argc,char * argv[])54 main(int argc, char *argv[])
55 {
56 int c;
57 int help = 0;
58 int rval;
59 char *command;
60 sa_handle_t handle;
61
62 /*
63 * make sure locale and gettext domain is setup
64 */
65 (void) setlocale(LC_ALL, "");
66 (void) textdomain(TEXT_DOMAIN);
67
68 handle = sa_init(SA_INIT_CONTROL_API);
69
70 while ((c = getopt(argc, argv, "h?")) != EOF) {
71 switch (c) {
72 case '?':
73 case 'h':
74 help = 1;
75 break;
76 default:
77 (void) printf(gettext("Invalid option: %c\n"), c);
78 }
79 }
80 if (optind == argc || help) {
81 /* no subcommand */
82 global_help();
83 exit(0);
84 }
85 optind = 1;
86
87 /*
88 * now have enough to parse rest of command line
89 */
90 command = argv[optind];
91 rval = run_command(command, argc - optind, argv + optind, handle);
92
93 sa_fini(handle);
94 return (rval);
95 }
96
97 char *
sc_get_usage(sc_usage_t index)98 sc_get_usage(sc_usage_t index)
99 {
100 char *ret = NULL;
101
102 switch (index) {
103 case USAGE_CTL_DELSECT:
104 ret = gettext("delsect\t<section> <proto>");
105 break;
106 case USAGE_CTL_GET:
107 ret = gettext("get\t[-p <property>]... <proto>");
108 break;
109 case USAGE_CTL_SET:
110 ret = gettext("set\t{-p <property>=<value>}... <proto>");
111 break;
112 case USAGE_CTL_STATUS:
113 ret = gettext("status\t[<proto>]...");
114 break;
115 }
116 return (ret);
117 }
118
119 /*ARGSUSED*/
120 static int
sc_get(sa_handle_t handle,int flags,int argc,char * argv[])121 sc_get(sa_handle_t handle, int flags, int argc, char *argv[])
122 {
123 char *proto = NULL;
124 struct options *optlist = NULL;
125 int ret = SA_OK;
126 int c;
127 sa_protocol_properties_t propset, propsect;
128 sa_property_t prop;
129 char *section, *value, *name;
130 int first = 1;
131
132 while ((c = getopt(argc, argv, "?hp:")) != EOF) {
133 switch (c) {
134 case 'p':
135 ret = add_opt(&optlist, optarg, 1);
136 if (ret != SA_OK) {
137 (void) printf(gettext(
138 "Problem with property: %s\n"), optarg);
139 return (SA_NO_MEMORY);
140 }
141 break;
142 default:
143 (void) printf(gettext("usage: %s\n"),
144 sc_get_usage(USAGE_CTL_GET));
145 return (SA_SYNTAX_ERR);
146 case '?':
147 case 'h':
148 (void) printf(gettext("usage: %s\n"),
149 sc_get_usage(USAGE_CTL_GET));
150 return (SA_OK);
151 }
152 }
153
154 if (optind >= argc) {
155 (void) printf(gettext("usage: %s\n"),
156 sc_get_usage(USAGE_CTL_GET));
157 (void) printf(gettext("\tprotocol must be specified.\n"));
158 return (SA_INVALID_PROTOCOL);
159 }
160
161 proto = argv[optind];
162 if (!sa_valid_protocol(proto)) {
163 (void) printf(gettext("Invalid protocol specified: %s\n"),
164 proto);
165 return (SA_INVALID_PROTOCOL);
166 }
167 propset = sa_proto_get_properties(proto);
168 if (propset == NULL)
169 return (ret);
170
171 if (optlist == NULL) {
172 /* Display all known properties for this protocol */
173 for (propsect = sa_get_protocol_section(propset, NULL);
174 propsect != NULL;
175 propsect = sa_get_next_protocol_section(propsect, NULL)) {
176 section = sa_get_property_attr(propsect,
177 "name");
178 /*
179 * If properties are organized into sections, as
180 * in the SMB client, print the section name.
181 */
182 if (sa_proto_get_featureset(proto) &
183 SA_FEATURE_HAS_SECTIONS) {
184 if (!first)
185 (void) printf("\n");
186 first = 0;
187 (void) printf("[%s]\n",
188 section != NULL ? section : "");
189 }
190 if (section != NULL)
191 sa_free_attr_string(section);
192
193 /* Display properties for this section */
194 for (prop = sa_get_protocol_property(propsect, NULL);
195 prop != NULL;
196 prop = sa_get_next_protocol_property(prop, NULL)) {
197
198 /* get and display the property and value */
199 name = sa_get_property_attr(prop, "type");
200 value = NULL;
201 if (name != NULL) {
202 value = sa_get_property_attr(prop,
203 "value");
204 (void) printf(gettext("%s=%s\n"), name,
205 value != NULL ? value : "");
206 }
207 if (value != NULL)
208 sa_free_attr_string(value);
209 if (name != NULL)
210 sa_free_attr_string(name);
211 }
212 }
213 } else {
214 struct options *opt;
215
216 /* list the specified option(s) */
217 for (opt = optlist; opt != NULL; opt = opt->next) {
218 int printed = 0;
219
220 for (propsect = sa_get_protocol_section(propset, NULL);
221 propsect != NULL;
222 propsect = sa_get_next_protocol_section(propsect,
223 NULL)) {
224
225 section = sa_get_property_attr(propsect,
226 "name");
227 for (prop = sa_get_protocol_property(propsect,
228 opt->optname);
229 prop != NULL;
230 prop = sa_get_next_protocol_property(
231 propsect, opt->optname)) {
232 value = sa_get_property_attr(prop,
233 "value");
234 if (sa_proto_get_featureset(proto) &
235 SA_FEATURE_HAS_SECTIONS) {
236 (void) printf(
237 gettext("[%s] %s=%s\n"),
238 section != NULL ?
239 section : "", opt->optname,
240 value != NULL ? value : "");
241 } else {
242 (void) printf(
243 gettext("%s=%s\n"),
244 opt->optname,
245 value != NULL ? value : "");
246 }
247 if (value != NULL)
248 sa_free_attr_string(value);
249 printed = 1;
250 }
251 if (section != NULL)
252 sa_free_attr_string(section);
253 }
254 if (!printed) {
255 (void) printf(gettext("%s: not defined\n"),
256 opt->optname);
257 ret = SA_NO_SUCH_PROP;
258 }
259 }
260 }
261 return (ret);
262 }
263
264 /*ARGSUSED*/
265 static int
sc_set(sa_handle_t handle,int flags,int argc,char * argv[])266 sc_set(sa_handle_t handle, int flags, int argc, char *argv[])
267 {
268 char *proto = NULL;
269 struct options *optlist = NULL;
270 sa_protocol_properties_t propsect;
271 int ret = SA_OK;
272 int c;
273 int err;
274 sa_protocol_properties_t propset;
275 sa_property_t prop;
276
277 while ((c = getopt(argc, argv, "?hp:")) != EOF) {
278 switch (c) {
279 case 'p':
280 ret = add_opt(&optlist, optarg, 0);
281 if (ret != SA_OK) {
282 (void) printf(gettext(
283 "Problem with property: %s\n"), optarg);
284 return (SA_NO_MEMORY);
285 }
286 break;
287 default:
288 (void) printf(gettext("usage: %s\n"),
289 sc_get_usage(USAGE_CTL_SET));
290 return (SA_SYNTAX_ERR);
291 case '?':
292 case 'h':
293 (void) printf(gettext("usage: %s\n"),
294 sc_get_usage(USAGE_CTL_SET));
295 return (SA_OK);
296 }
297 }
298
299 if (optind >= argc) {
300 (void) printf(gettext("usage: %s\n"),
301 sc_get_usage(USAGE_CTL_SET));
302 (void) printf(gettext("\tprotocol must be specified.\n"));
303 return (SA_INVALID_PROTOCOL);
304 }
305
306 proto = argv[optind];
307 if (!sa_valid_protocol(proto)) {
308 (void) printf(gettext("Invalid protocol specified: %s\n"),
309 proto);
310 return (SA_INVALID_PROTOCOL);
311 }
312 propset = sa_proto_get_properties(proto);
313 if (propset == NULL)
314 return (ret);
315
316 if (optlist == NULL) {
317 (void) printf(gettext("usage: %s\n"),
318 sc_get_usage(USAGE_CTL_SET));
319 (void) printf(gettext(
320 "\tat least one property and value "
321 "must be specified\n"));
322 } else {
323 struct options *opt;
324 char *section = NULL;
325 /* fetch and change the specified option(s) */
326 for (opt = optlist; opt != NULL; opt = opt->next) {
327 if (strncmp("section", opt->optname, 7) == 0) {
328 if (section != NULL)
329 free(section);
330 section = strdup(opt->optvalue);
331 continue;
332 }
333 if (sa_proto_get_featureset(proto) &
334 SA_FEATURE_HAS_SECTIONS) {
335 propsect = sa_get_protocol_section(propset,
336 section);
337 prop = sa_get_protocol_property(propsect,
338 opt->optname);
339 } else {
340 prop = sa_get_protocol_property(propset,
341 opt->optname);
342 }
343 if (prop == NULL && sa_proto_get_featureset(proto) &
344 SA_FEATURE_ADD_PROPERTIES) {
345 sa_property_t sect;
346 sect = sa_create_section(section, NULL);
347 sa_set_section_attr(sect, "type", proto);
348 (void) sa_add_protocol_property(propset, sect);
349 prop = sa_create_property(
350 opt->optname, opt->optvalue);
351 (void) sa_add_protocol_property(sect, prop);
352 }
353 if (prop != NULL) {
354 /*
355 * "err" is used in order to prevent
356 * setting ret to SA_OK if there has
357 * been a real error. We want to be
358 * able to return an error status on
359 * exit in that case. Error messages
360 * are printed for each error, so we
361 * only care on exit that there was an
362 * error and not the specific error
363 * value.
364 */
365 err = sa_set_protocol_property(prop, section,
366 opt->optvalue);
367 if (err != SA_OK) {
368 (void) printf(gettext(
369 "Could not set property"
370 " %s: %s\n"),
371 opt->optname, sa_errorstr(err));
372 ret = err;
373 }
374 } else {
375 (void) printf(gettext("%s: not defined\n"),
376 opt->optname);
377 ret = SA_NO_SUCH_PROP;
378 }
379 }
380 }
381 return (ret);
382 }
383
384 static void
show_status(char * proto)385 show_status(char *proto)
386 {
387 char *status;
388 uint64_t features;
389
390 status = sa_get_protocol_status(proto);
391 features = sa_proto_get_featureset(proto);
392 (void) printf("%s\t%s", proto, status ? gettext(status) : "-");
393 if (status != NULL)
394 free(status);
395 /*
396 * Need to flag a client only protocol so test suites can
397 * remove it from consideration.
398 */
399 if (!(features & SA_FEATURE_SERVER))
400 (void) printf(" client");
401 (void) printf("\n");
402 }
403
404 static int
valid_proto(char ** protos,int num,char * proto)405 valid_proto(char **protos, int num, char *proto)
406 {
407 int i;
408 for (i = 0; i < num; i++)
409 if (strcmp(protos[i], proto) == 0)
410 return (1);
411 return (0);
412 }
413
414 /*ARGSUSED*/
415 static int
sc_status(sa_handle_t handle,int flags,int argc,char * argv[])416 sc_status(sa_handle_t handle, int flags, int argc, char *argv[])
417 {
418 char **protos;
419 int ret = SA_OK;
420 int c;
421 int i;
422 int num_proto;
423 int verbose = 0;
424
425 while ((c = getopt(argc, argv, "?hv")) != EOF) {
426 switch (c) {
427 case 'v':
428 verbose++;
429 break;
430 case '?':
431 case 'h':
432 (void) printf(gettext("usage: %s\n"),
433 sc_get_usage(USAGE_CTL_STATUS));
434 return (SA_OK);
435 default:
436 (void) printf(gettext("usage: %s\n"),
437 sc_get_usage(USAGE_CTL_STATUS));
438 return (SA_SYNTAX_ERR);
439 }
440 }
441
442 num_proto = sa_get_protocols(&protos);
443 if (optind == argc) {
444 /* status for all protocols */
445 for (i = 0; i < num_proto; i++) {
446 show_status(protos[i]);
447 }
448 } else {
449 for (i = optind; i < argc; i++) {
450 if (valid_proto(protos, num_proto, argv[i])) {
451 show_status(argv[i]);
452 } else {
453 (void) printf(gettext("Invalid protocol: %s\n"),
454 argv[i]);
455 ret = SA_INVALID_PROTOCOL;
456 }
457 }
458 }
459 if (protos != NULL)
460 free(protos);
461 return (ret);
462 }
463
464 /*ARGSUSED*/
465 static int
sc_delsect(sa_handle_t handle,int flags,int argc,char * argv[])466 sc_delsect(sa_handle_t handle, int flags, int argc, char *argv[])
467 {
468 char *proto = NULL;
469 char *section = NULL;
470 sa_protocol_properties_t propset;
471 sa_protocol_properties_t propsect;
472 int ret = SA_OK;
473 int c;
474
475 while ((c = getopt(argc, argv, "?h")) != EOF) {
476 switch (c) {
477 default:
478 ret = SA_SYNTAX_ERR;
479 /*FALLTHROUGH*/
480 case '?':
481 case 'h':
482 (void) printf(gettext("usage: %s\n"),
483 sc_get_usage(USAGE_CTL_DELSECT));
484 return (ret);
485 }
486 /*NOTREACHED*/
487 }
488
489 section = argv[optind++];
490
491 if (optind >= argc) {
492 (void) printf(gettext("usage: %s\n"),
493 sc_get_usage(USAGE_CTL_DELSECT));
494 (void) printf(gettext(
495 "\tsection and protocol must be specified.\n"));
496 return (SA_INVALID_PROTOCOL);
497 }
498
499 proto = argv[optind];
500 if (!sa_valid_protocol(proto)) {
501 (void) printf(gettext("Invalid protocol specified: %s\n"),
502 proto);
503 return (SA_INVALID_PROTOCOL);
504 }
505
506 if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) {
507 (void) printf(gettext("Protocol %s does not have sections\n"),
508 proto);
509 return (SA_NOT_SUPPORTED);
510 }
511
512 propset = sa_proto_get_properties(proto);
513 if (propset == NULL) {
514 (void) printf(gettext("Cannot get properties for %s\n"),
515 proto);
516 return (SA_NO_PROPERTIES);
517 }
518
519 propsect = sa_get_protocol_section(propset, section);
520 if (propsect == NULL) {
521 (void) printf(gettext("Cannot find section %s for proto %s\n"),
522 section, proto);
523 return (SA_NO_SUCH_SECTION);
524 }
525
526 ret = sa_proto_delete_section(proto, section);
527
528 return (ret);
529 }
530
531 static sa_command_t commands[] = {
532 {"delsect", 0, sc_delsect, USAGE_CTL_DELSECT},
533 {"get", 0, sc_get, USAGE_CTL_GET},
534 {"set", 0, sc_set, USAGE_CTL_SET},
535 {"status", 0, sc_status, USAGE_CTL_STATUS},
536 {NULL, 0, NULL, 0},
537 };
538
539 /*ARGSUSED*/
540 void
sub_command_help(char * proto)541 sub_command_help(char *proto)
542 {
543 int i;
544
545 for (i = 0; commands[i].cmdname != NULL; i++) {
546 if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
547 (void) printf("\t%s\n",
548 sc_get_usage((sc_usage_t)commands[i].cmdidx));
549 }
550 }
551
552 sa_command_t *
sa_lookup(char * cmd)553 sa_lookup(char *cmd)
554 {
555 int i;
556 size_t len;
557
558 len = strlen(cmd);
559 for (i = 0; commands[i].cmdname != NULL; i++) {
560 if (strncmp(cmd, commands[i].cmdname, len) == 0)
561 return (&commands[i]);
562 }
563 return (NULL);
564 }
565
566 static int
run_command(char * command,int argc,char * argv[],sa_handle_t handle)567 run_command(char *command, int argc, char *argv[], sa_handle_t handle)
568 {
569 sa_command_t *cmdvec;
570 int ret;
571
572 /*
573 * To get here, we know there should be a command due to the
574 * preprocessing done earlier. Need to find the protocol
575 * that is being affected. If no protocol, then it is ALL
576 * protocols.
577 *
578 * ??? do we really need the protocol at this level? it may be
579 * sufficient to let the commands look it up if needed since
580 * not all commands do proto specific things
581 *
582 * Known sub-commands are handled at this level. An unknown
583 * command will be passed down to the shared object that
584 * actually implements it. We can do this since the semantics
585 * of the common sub-commands is well defined.
586 */
587
588 cmdvec = sa_lookup(command);
589 if (cmdvec == NULL) {
590 (void) printf(gettext("command %s not found\n"), command);
591 exit(1);
592 }
593 /*
594 * need to check priviledges and restrict what can be done
595 * based on least priviledge and sub-command.
596 */
597 ret = cmdvec->cmdfunc(handle, 0, argc, argv);
598 return (ret);
599 }
600