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 */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <unistd.h>
32 #include <getopt.h>
33 #include <libgen.h>
34
35 #include "libshare.h"
36 #include <sharemgr.h>
37
38 #include <libintl.h>
39 #include <locale.h>
40
41 static int run_command(char *, int, char **, sa_handle_t);
42 static void sub_command_help(char *proto);
43
44 static void
global_help()45 global_help()
46 {
47 (void) printf(gettext("usage: sharectl <command> [options]\n"));
48 sub_command_help(NULL);
49 }
50
51 int
main(int argc,char * argv[])52 main(int argc, char *argv[])
53 {
54 int c;
55 int help = 0;
56 int rval;
57 char *command;
58 sa_handle_t handle;
59
60 /*
61 * make sure locale and gettext domain is setup
62 */
63 (void) setlocale(LC_ALL, "");
64 (void) textdomain(TEXT_DOMAIN);
65
66 handle = sa_init(SA_INIT_CONTROL_API);
67
68 while ((c = getopt(argc, argv, "h?")) != EOF) {
69 switch (c) {
70 case '?':
71 case 'h':
72 help = 1;
73 break;
74 default:
75 (void) printf(gettext("Invalid option: %c\n"), c);
76 }
77 }
78 if (optind == argc || help) {
79 /* no subcommand */
80 global_help();
81 exit(0);
82 }
83 optind = 1;
84
85 /*
86 * now have enough to parse rest of command line
87 */
88 command = argv[optind];
89 rval = run_command(command, argc - optind, argv + optind, handle);
90
91 sa_fini(handle);
92 return (rval);
93 }
94
95 char *
sc_get_usage(sc_usage_t index)96 sc_get_usage(sc_usage_t index)
97 {
98 char *ret = NULL;
99
100 switch (index) {
101 case USAGE_CTL_GET:
102 ret = gettext("get [-h | -p property ...] proto");
103 break;
104 case USAGE_CTL_SET:
105 ret = gettext("set [-h] -p property=value ... proto");
106 break;
107 case USAGE_CTL_STATUS:
108 ret = gettext("status [-h | proto ...]");
109 break;
110 case USAGE_CTL_DELSECT:
111 ret = gettext("delsect [-h] section proto");
112 break;
113 }
114 return (ret);
115 }
116
117 /*ARGSUSED*/
118 static int
sc_get(sa_handle_t handle,int flags,int argc,char * argv[])119 sc_get(sa_handle_t handle, int flags, int argc, char *argv[])
120 {
121 char *proto = NULL;
122 struct options *optlist = NULL;
123 int ret = SA_OK;
124 int c;
125 sa_protocol_properties_t propset, propsect;
126 sa_property_t prop;
127 char *section, *value, *name;
128 int first = 1;
129
130 while ((c = getopt(argc, argv, "?hp:")) != EOF) {
131 switch (c) {
132 case 'p':
133 ret = add_opt(&optlist, optarg, 1);
134 if (ret != SA_OK) {
135 (void) printf(gettext(
136 "Problem with property: %s\n"), optarg);
137 return (SA_NO_MEMORY);
138 }
139 break;
140 default:
141 (void) printf(gettext("usage: %s\n"),
142 sc_get_usage(USAGE_CTL_GET));
143 return (SA_SYNTAX_ERR);
144 case '?':
145 case 'h':
146 (void) printf(gettext("usage: %s\n"),
147 sc_get_usage(USAGE_CTL_GET));
148 return (SA_OK);
149 break;
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 break;
295 }
296 }
297
298 if (optind >= argc) {
299 (void) printf(gettext("usage: %s\n"),
300 sc_get_usage(USAGE_CTL_SET));
301 (void) printf(gettext("\tprotocol must be specified.\n"));
302 return (SA_INVALID_PROTOCOL);
303 }
304
305 proto = argv[optind];
306 if (!sa_valid_protocol(proto)) {
307 (void) printf(gettext("Invalid protocol specified: %s\n"),
308 proto);
309 return (SA_INVALID_PROTOCOL);
310 }
311 propset = sa_proto_get_properties(proto);
312 if (propset == NULL)
313 return (ret);
314
315 if (optlist == NULL) {
316 (void) printf(gettext("usage: %s\n"),
317 sc_get_usage(USAGE_CTL_SET));
318 (void) printf(gettext(
319 "\tat least one property and value "
320 "must be specified\n"));
321 } else {
322 struct options *opt;
323 char *section = NULL;
324 /* fetch and change the specified option(s) */
325 for (opt = optlist; opt != NULL; opt = opt->next) {
326 if (strncmp("section", opt->optname, 7) == 0) {
327 if (section != NULL)
328 free(section);
329 section = strdup(opt->optvalue);
330 continue;
331 }
332 if (sa_proto_get_featureset(proto) &
333 SA_FEATURE_HAS_SECTIONS) {
334 propsect = sa_get_protocol_section(propset,
335 section);
336 prop = sa_get_protocol_property(propsect,
337 opt->optname);
338 } else {
339 prop = sa_get_protocol_property(propset,
340 opt->optname);
341 }
342 if (prop == NULL && sa_proto_get_featureset(proto) &
343 SA_FEATURE_ADD_PROPERTIES) {
344 sa_property_t sect;
345 sect = sa_create_section(section, NULL);
346 sa_set_section_attr(sect, "type", proto);
347 (void) sa_add_protocol_property(propset, sect);
348 prop = sa_create_property(
349 opt->optname, opt->optvalue);
350 (void) sa_add_protocol_property(sect, prop);
351 }
352 if (prop != NULL) {
353 /*
354 * "err" is used in order to prevent
355 * setting ret to SA_OK if there has
356 * been a real error. We want to be
357 * able to return an error status on
358 * exit in that case. Error messages
359 * are printed for each error, so we
360 * only care on exit that there was an
361 * error and not the specific error
362 * value.
363 */
364 err = sa_set_protocol_property(prop, section,
365 opt->optvalue);
366 if (err != SA_OK) {
367 (void) printf(gettext(
368 "Could not set property"
369 " %s: %s\n"),
370 opt->optname, sa_errorstr(err));
371 ret = err;
372 }
373 } else {
374 (void) printf(gettext("%s: not defined\n"),
375 opt->optname);
376 ret = SA_NO_SUCH_PROP;
377 }
378 }
379 }
380 return (ret);
381 }
382
383 static void
show_status(char * proto)384 show_status(char *proto)
385 {
386 char *status;
387 uint64_t features;
388
389 status = sa_get_protocol_status(proto);
390 features = sa_proto_get_featureset(proto);
391 (void) printf("%s\t%s", proto, status ? gettext(status) : "-");
392 if (status != NULL)
393 free(status);
394 /*
395 * Need to flag a client only protocol so test suites can
396 * remove it from consideration.
397 */
398 if (!(features & SA_FEATURE_SERVER))
399 (void) printf(" client");
400 (void) printf("\n");
401 }
402
403 static int
valid_proto(char ** protos,int num,char * proto)404 valid_proto(char **protos, int num, char *proto)
405 {
406 int i;
407 for (i = 0; i < num; i++)
408 if (strcmp(protos[i], proto) == 0)
409 return (1);
410 return (0);
411 }
412
413 /*ARGSUSED*/
414 static int
sc_status(sa_handle_t handle,int flags,int argc,char * argv[])415 sc_status(sa_handle_t handle, int flags, int argc, char *argv[])
416 {
417 char **protos;
418 int ret = SA_OK;
419 int c;
420 int i;
421 int num_proto;
422 int verbose = 0;
423
424 while ((c = getopt(argc, argv, "?hv")) != EOF) {
425 switch (c) {
426 case 'v':
427 verbose++;
428 break;
429 case '?':
430 case 'h':
431 (void) printf(gettext("usage: %s\n"),
432 sc_get_usage(USAGE_CTL_STATUS));
433 return (SA_OK);
434 default:
435 (void) printf(gettext("usage: %s\n"),
436 sc_get_usage(USAGE_CTL_STATUS));
437 return (SA_SYNTAX_ERR);
438 }
439 }
440
441 num_proto = sa_get_protocols(&protos);
442 if (optind == argc) {
443 /* status for all protocols */
444 for (i = 0; i < num_proto; i++) {
445 show_status(protos[i]);
446 }
447 } else {
448 for (i = optind; i < argc; i++) {
449 if (valid_proto(protos, num_proto, argv[i])) {
450 show_status(argv[i]);
451 } else {
452 (void) printf(gettext("Invalid protocol: %s\n"),
453 argv[i]);
454 ret = SA_INVALID_PROTOCOL;
455 }
456 }
457 }
458 if (protos != NULL)
459 free(protos);
460 return (ret);
461 }
462
463 /*ARGSUSED*/
464 static int
sc_delsect(sa_handle_t handle,int flags,int argc,char * argv[])465 sc_delsect(sa_handle_t handle, int flags, int argc, char *argv[])
466 {
467 char *proto = NULL;
468 char *section = NULL;
469 sa_protocol_properties_t propset;
470 sa_protocol_properties_t propsect;
471 int ret = SA_OK;
472 int c;
473
474 while ((c = getopt(argc, argv, "?h")) != EOF) {
475 switch (c) {
476 default:
477 ret = SA_SYNTAX_ERR;
478 /*FALLTHROUGH*/
479 case '?':
480 case 'h':
481 (void) printf(gettext("usage: %s\n"),
482 sc_get_usage(USAGE_CTL_DELSECT));
483 return (ret);
484 }
485 /*NOTREACHED*/
486 }
487
488 section = argv[optind++];
489
490 if (optind >= argc) {
491 (void) printf(gettext("usage: %s\n"),
492 sc_get_usage(USAGE_CTL_DELSECT));
493 (void) printf(gettext(
494 "\tsection and protocol must be specified.\n"));
495 return (SA_INVALID_PROTOCOL);
496 }
497
498 proto = argv[optind];
499 if (!sa_valid_protocol(proto)) {
500 (void) printf(gettext("Invalid protocol specified: %s\n"),
501 proto);
502 return (SA_INVALID_PROTOCOL);
503 }
504
505 if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) {
506 (void) printf(gettext("Protocol %s does not have sections\n"),
507 section, proto);
508 return (SA_NOT_SUPPORTED);
509 }
510
511 propset = sa_proto_get_properties(proto);
512 if (propset == NULL) {
513 (void) printf(gettext("Cannot get properties for %s\n"),
514 proto);
515 return (SA_NO_PROPERTIES);
516 }
517
518 propsect = sa_get_protocol_section(propset, section);
519 if (propsect == NULL) {
520 (void) printf(gettext("Cannot find section %s for proto %s\n"),
521 section, proto);
522 return (SA_NO_SUCH_SECTION);
523 }
524
525 ret = sa_proto_delete_section(proto, section);
526
527 return (ret);
528 }
529
530 static sa_command_t commands[] = {
531 {"get", 0, sc_get, USAGE_CTL_GET},
532 {"set", 0, sc_set, USAGE_CTL_SET},
533 {"status", 0, sc_status, USAGE_CTL_STATUS},
534 {"delsect", 0, sc_delsect, USAGE_CTL_DELSECT},
535 {NULL, 0, NULL, 0},
536 };
537
538 /*ARGSUSED*/
539 void
sub_command_help(char * proto)540 sub_command_help(char *proto)
541 {
542 int i;
543
544 (void) printf("\tsub-commands:\n");
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, NULL, argc, argv);
598 return (ret);
599 }
600