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