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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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 **);
44 static void sub_command_help(char *proto);
45 
46 static void
47 global_help()
48 {
49 	(void) printf(gettext("usage: sharectl <command> [options]\n"));
50 	sub_command_help(NULL);
51 }
52 
53 int
54 main(int argc, char *argv[])
55 {
56 	int c;
57 	int help = 0;
58 	int rval;
59 	char *command;
60 
61 	/*
62 	 * make sure locale and gettext domain is setup
63 	 */
64 	(void) setlocale(LC_ALL, "");
65 	(void) textdomain(TEXT_DOMAIN);
66 
67 	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);
91 
92 	sa_fini();
93 	return (rval);
94 }
95 
96 char *
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 	}
112 	return (ret);
113 }
114 
115 static int
116 sc_get(int flags, int argc, char *argv[])
117 {
118 	char *proto = NULL;
119 	struct options *optlist = NULL;
120 	int ret = SA_OK;
121 	int c;
122 #ifdef lint
123 	flags = flags;
124 #endif
125 
126 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
127 	    switch (c) {
128 	    case 'p':
129 		ret = add_opt(&optlist, optarg, 1);
130 		if (ret != SA_OK) {
131 		    (void) printf(gettext("Problem with property: %s\n"),
132 						optarg);
133 		    return (SA_NO_MEMORY);
134 		}
135 		break;
136 	    default:
137 		(void) printf(gettext("usage: %s\n"),
138 				sc_get_usage(USAGE_CTL_GET));
139 		return (SA_SYNTAX_ERR);
140 	    case '?':
141 	    case 'h':
142 		(void) printf(gettext("usage: %s\n"),
143 				sc_get_usage(USAGE_CTL_GET));
144 		return (SA_OK);
145 		break;
146 	    }
147 	}
148 
149 	if (optind >= argc) {
150 	    (void) printf(gettext("usage: %s\n"), sc_get_usage(USAGE_CTL_GET));
151 	    (void) printf(gettext("\tprotocol must be specified.\n"));
152 	    return (SA_INVALID_PROTOCOL);
153 	}
154 
155 	proto = argv[optind];
156 	if (sa_valid_protocol(proto)) {
157 	    sa_protocol_properties_t propset;
158 	    propset = sa_proto_get_properties(proto);
159 	    if (propset != NULL) {
160 		sa_property_t prop;
161 		char *value;
162 		char *name;
163 		if (optlist == NULL) {
164 		    /* display all known properties for this protocol */
165 		    for (prop = sa_get_protocol_property(propset, NULL);
166 			prop != NULL;
167 			prop = sa_get_next_protocol_property(prop)) {
168 
169 			/* get and display the property and value */
170 			name = sa_get_property_attr(prop, "type");
171 			if (name != NULL) {
172 			    value = sa_get_property_attr(prop, "value");
173 			    (void) printf(gettext("%s=%s\n"), name,
174 						value != NULL ? value : "");
175 			}
176 			if (value != NULL)
177 			    sa_free_attr_string(value);
178 			if (name != NULL)
179 			    sa_free_attr_string(name);
180 		    }
181 		} else {
182 		    struct options *opt;
183 		    /* list the specified option(s) */
184 		    for (opt = optlist; opt != NULL; opt = opt->next) {
185 			prop = sa_get_protocol_property(propset, opt->optname);
186 			if (prop != NULL) {
187 			    value = sa_get_property_attr(prop, "value");
188 			    (void) printf(gettext("%s=%s\n"), opt->optname,
189 					value != NULL ? value : "");
190 			    sa_free_attr_string(value);
191 			} else {
192 			    (void) printf(gettext("%s: not defined\n"),
193 						opt->optname);
194 			}
195 		    }
196 		}
197 	    }
198 	} else {
199 	    (void) printf(gettext("Invalid protocol specified: %s\n"), proto);
200 	    ret = SA_INVALID_PROTOCOL;
201 	}
202 	return (ret);
203 }
204 
205 static int
206 sc_set(int flags, int argc, char *argv[])
207 {
208 	char *proto = NULL;
209 	struct options *optlist = NULL;
210 	int ret = SA_OK;
211 	int c;
212 #ifdef lint
213 	flags = flags;
214 #endif
215 
216 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
217 	    switch (c) {
218 	    case 'p':
219 		ret = add_opt(&optlist, optarg, 0);
220 		if (ret != SA_OK) {
221 		    (void) printf(gettext("Problem with property: %s\n"),
222 					optarg);
223 		    return (SA_NO_MEMORY);
224 		}
225 		break;
226 	    default:
227 		(void) printf(gettext("usage: %s\n"),
228 				sc_get_usage(USAGE_CTL_SET));
229 		return (SA_SYNTAX_ERR);
230 	    case '?':
231 	    case 'h':
232 		(void) printf(gettext("usage: %s\n"),
233 				sc_get_usage(USAGE_CTL_SET));
234 		return (SA_OK);
235 		break;
236 	    }
237 	}
238 
239 	if (optind >= argc) {
240 	    (void) printf(gettext("usage: %s\n"),
241 				sc_get_usage(USAGE_CTL_SET));
242 	    (void) printf(gettext("\tprotocol must be specified.\n"));
243 	    return (SA_INVALID_PROTOCOL);
244 	}
245 
246 	proto = argv[optind];
247 	if (sa_valid_protocol(proto)) {
248 	    sa_protocol_properties_t propset;
249 	    propset = sa_proto_get_properties(proto);
250 	    if (propset != NULL) {
251 		sa_property_t prop;
252 
253 		if (optlist == NULL) {
254 		    (void) printf(gettext("usage: %s\n"),
255 				sc_get_usage(USAGE_CTL_SET));
256 		    (void) printf(gettext("\tat least one property and value "
257 				    "must be specified\n"));
258 		} else {
259 		    struct options *opt;
260 		    /* list the specified option(s) */
261 		    for (opt = optlist; opt != NULL; opt = opt->next) {
262 			prop = sa_get_protocol_property(propset, opt->optname);
263 			if (prop != NULL) {
264 			    ret = sa_set_protocol_property(prop, opt->optvalue);
265 			    if (ret != SA_OK) {
266 				(void) printf(gettext("Could not set property"
267 						" %s: %s\n"),
268 					opt->optname, sa_errorstr(ret));
269 			    }
270 			} else {
271 			    (void) printf(gettext("%s: not defined\n"),
272 						opt->optname);
273 			}
274 		    }
275 		}
276 	    }
277 	} else {
278 	    (void) printf(gettext("Invalid protocol specified: %s\n"), proto);
279 	    ret = SA_INVALID_PROTOCOL;
280 	}
281 	return (ret);
282 }
283 
284 static void
285 show_status(char *proto)
286 {
287 	char *status;
288 	status = sa_get_protocol_status(proto);
289 	(void) printf("%s\t%s\n", proto, status ? gettext(status) : "-");
290 	if (status != NULL)
291 	    free(status);
292 }
293 
294 static int
295 valid_proto(char **protos, int num, char *proto)
296 {
297 	int i;
298 	for (i = 0; i < num; i++)
299 	    if (strcmp(protos[i], proto) == 0)
300 		return (1);
301 	return (0);
302 }
303 
304 static int
305 sc_status(int flags, int argc, char *argv[])
306 {
307 	char **protos;
308 	int ret = SA_OK;
309 	int c;
310 	int i;
311 	int num_proto;
312 	int verbose = 0;
313 #ifdef lint
314 	flags = flags;
315 #endif
316 
317 	while ((c = getopt(argc, argv, "?hv")) != EOF) {
318 	    switch (c) {
319 	    case 'v':
320 		verbose++;
321 		break;
322 	    case '?':
323 	    case 'h':
324 		(void) printf(gettext("usage: %s\n"),
325 				sc_get_usage(USAGE_CTL_SET));
326 		return (SA_OK);
327 	    default:
328 		(void) printf(gettext("usage: %s\n"),
329 				sc_get_usage(USAGE_CTL_SET));
330 		return (SA_SYNTAX_ERR);
331 	    }
332 	}
333 
334 	num_proto = sa_get_protocols(&protos);
335 	if (optind == argc) {
336 	    /* status for all protocols */
337 	    for (i = 0; i < num_proto; i++) {
338 		show_status(protos[i]);
339 	    }
340 	} else {
341 	    for (i = optind; i < argc; i++) {
342 		if (valid_proto(protos, num_proto, argv[i])) {
343 		    show_status(argv[i]);
344 		} else {
345 		    (void) printf(gettext("Invalid protocol: %s\n"), argv[i]);
346 		    ret = SA_INVALID_PROTOCOL;
347 		}
348 	    }
349 	}
350 	if (protos != NULL)
351 	    free(protos);
352 	return (ret);
353 }
354 
355 static sa_command_t commands[] = {
356 	{"get", 0, sc_get, USAGE_CTL_GET},
357 	{"set", 0, sc_set, USAGE_CTL_SET},
358 	{"status", 0, sc_status, USAGE_CTL_STATUS},
359 	{NULL, 0, NULL, 0},
360 };
361 
362 void
363 sub_command_help(char *proto)
364 {
365 	int i;
366 #ifdef lint
367 	proto = proto;
368 #endif
369 
370 	(void) printf("\tsub-commands:\n");
371 	for (i = 0; commands[i].cmdname != NULL; i++) {
372 		if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
373 			(void) printf("\t%s\n",
374 				sc_get_usage((sc_usage_t)commands[i].cmdidx));
375 	}
376 }
377 
378 sa_command_t *
379 sa_lookup(char *cmd)
380 {
381 	int i;
382 	size_t len;
383 
384 	len = strlen(cmd);
385 	for (i = 0; commands[i].cmdname != NULL; i++) {
386 		if (strncmp(cmd, commands[i].cmdname, len) == 0)
387 			return (&commands[i]);
388 	}
389 	return (NULL);
390 }
391 
392 static int
393 run_command(char *command, int argc, char *argv[])
394 {
395 	sa_command_t *cmdvec;
396 	int ret;
397 
398 	/*
399 	 * To get here, we know there should be a command due to the
400 	 * preprocessing done earlier.  Need to find the protocol
401 	 * that is being affected. If no protocol, then it is ALL
402 	 * protocols.
403 	 *
404 	 * ??? do we really need the protocol at this level? it may be
405 	 * sufficient to let the commands look it up if needed since
406 	 * not all commands do proto specific things
407 	 *
408 	 * Known sub-commands are handled at this level. An unknown
409 	 * command will be passed down to the shared object that
410 	 * actually implements it. We can do this since the semantics
411 	 * of the common sub-commands is well defined.
412 	 */
413 
414 	cmdvec = sa_lookup(command);
415 	if (cmdvec == NULL) {
416 		(void) printf(gettext("command %s not found\n"), command);
417 		exit(1);
418 	}
419 	/*
420 	 * need to check priviledges and restrict what can be done
421 	 * based on least priviledge and sub-command.
422 	 */
423 	ret = cmdvec->cmdfunc(NULL, argc, argv);
424 	return (ret);
425 }
426