xref: /illumos-gate/usr/src/cmd/dfs.cmds/sharectl/sharectl.c (revision 150d2c5288c645a1c1a7d2bee61199a3729406c7)
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 2007 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 			    ret = SA_NO_SUCH_PROP;
195 			}
196 		    }
197 		}
198 	    }
199 	} else {
200 	    (void) printf(gettext("Invalid protocol specified: %s\n"), proto);
201 	    ret = SA_INVALID_PROTOCOL;
202 	}
203 	return (ret);
204 }
205 
206 static int
207 sc_set(int flags, int argc, char *argv[])
208 {
209 	char *proto = NULL;
210 	struct options *optlist = NULL;
211 	int ret = SA_OK;
212 	int c;
213 #ifdef lint
214 	flags = flags;
215 #endif
216 
217 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
218 	    switch (c) {
219 	    case 'p':
220 		ret = add_opt(&optlist, optarg, 0);
221 		if (ret != SA_OK) {
222 		    (void) printf(gettext("Problem with property: %s\n"),
223 					optarg);
224 		    return (SA_NO_MEMORY);
225 		}
226 		break;
227 	    default:
228 		(void) printf(gettext("usage: %s\n"),
229 				sc_get_usage(USAGE_CTL_SET));
230 		return (SA_SYNTAX_ERR);
231 	    case '?':
232 	    case 'h':
233 		(void) printf(gettext("usage: %s\n"),
234 				sc_get_usage(USAGE_CTL_SET));
235 		return (SA_OK);
236 		break;
237 	    }
238 	}
239 
240 	if (optind >= argc) {
241 	    (void) printf(gettext("usage: %s\n"),
242 				sc_get_usage(USAGE_CTL_SET));
243 	    (void) printf(gettext("\tprotocol must be specified.\n"));
244 	    return (SA_INVALID_PROTOCOL);
245 	}
246 
247 	proto = argv[optind];
248 	if (sa_valid_protocol(proto)) {
249 	    sa_protocol_properties_t propset;
250 	    propset = sa_proto_get_properties(proto);
251 	    if (propset != NULL) {
252 		sa_property_t prop;
253 		int err;
254 
255 		if (optlist == NULL) {
256 		    (void) printf(gettext("usage: %s\n"),
257 				sc_get_usage(USAGE_CTL_SET));
258 		    (void) printf(gettext("\tat least one property and value "
259 				    "must be specified\n"));
260 		} else {
261 		    struct options *opt;
262 		    /* list the specified option(s) */
263 		    for (opt = optlist; opt != NULL; opt = opt->next) {
264 			prop = sa_get_protocol_property(propset, opt->optname);
265 			if (prop != NULL) {
266 				/*
267 				 * "err" is used in order to prevent
268 				 * setting ret to SA_OK if there has
269 				 * been a real error. We want to be
270 				 * able to return an error status on
271 				 * exit in that case. Error messages
272 				 * are printed for each error, so we
273 				 * only care on exit that there was an
274 				 * error and not the specific error
275 				 * value.
276 				 */
277 			    err = sa_set_protocol_property(prop, opt->optvalue);
278 			    if (err != SA_OK) {
279 				(void) printf(gettext("Could not set property"
280 							" %s: %s\n"),
281 					opt->optname, sa_errorstr(err));
282 				ret = err;
283 			    }
284 			} else {
285 			    (void) printf(gettext("%s: not defined\n"),
286 						opt->optname);
287 			    ret = SA_NO_SUCH_PROP;
288 			}
289 		    }
290 		}
291 	    }
292 	} else {
293 	    (void) printf(gettext("Invalid protocol specified: %s\n"), proto);
294 	    ret = SA_INVALID_PROTOCOL;
295 	}
296 	return (ret);
297 }
298 
299 static void
300 show_status(char *proto)
301 {
302 	char *status;
303 	status = sa_get_protocol_status(proto);
304 	(void) printf("%s\t%s\n", proto, status ? gettext(status) : "-");
305 	if (status != NULL)
306 	    free(status);
307 }
308 
309 static int
310 valid_proto(char **protos, int num, char *proto)
311 {
312 	int i;
313 	for (i = 0; i < num; i++)
314 	    if (strcmp(protos[i], proto) == 0)
315 		return (1);
316 	return (0);
317 }
318 
319 static int
320 sc_status(int flags, int argc, char *argv[])
321 {
322 	char **protos;
323 	int ret = SA_OK;
324 	int c;
325 	int i;
326 	int num_proto;
327 	int verbose = 0;
328 #ifdef lint
329 	flags = flags;
330 #endif
331 
332 	while ((c = getopt(argc, argv, "?hv")) != EOF) {
333 	    switch (c) {
334 	    case 'v':
335 		verbose++;
336 		break;
337 	    case '?':
338 	    case 'h':
339 		(void) printf(gettext("usage: %s\n"),
340 				sc_get_usage(USAGE_CTL_STATUS));
341 		return (SA_OK);
342 	    default:
343 		(void) printf(gettext("usage: %s\n"),
344 				sc_get_usage(USAGE_CTL_STATUS));
345 		return (SA_SYNTAX_ERR);
346 	    }
347 	}
348 
349 	num_proto = sa_get_protocols(&protos);
350 	if (optind == argc) {
351 	    /* status for all protocols */
352 	    for (i = 0; i < num_proto; i++) {
353 		show_status(protos[i]);
354 	    }
355 	} else {
356 	    for (i = optind; i < argc; i++) {
357 		if (valid_proto(protos, num_proto, argv[i])) {
358 		    show_status(argv[i]);
359 		} else {
360 		    (void) printf(gettext("Invalid protocol: %s\n"), argv[i]);
361 		    ret = SA_INVALID_PROTOCOL;
362 		}
363 	    }
364 	}
365 	if (protos != NULL)
366 	    free(protos);
367 	return (ret);
368 }
369 
370 static sa_command_t commands[] = {
371 	{"get", 0, sc_get, USAGE_CTL_GET},
372 	{"set", 0, sc_set, USAGE_CTL_SET},
373 	{"status", 0, sc_status, USAGE_CTL_STATUS},
374 	{NULL, 0, NULL, 0},
375 };
376 
377 void
378 sub_command_help(char *proto)
379 {
380 	int i;
381 #ifdef lint
382 	proto = proto;
383 #endif
384 
385 	(void) printf("\tsub-commands:\n");
386 	for (i = 0; commands[i].cmdname != NULL; i++) {
387 		if (!(commands[i].flags & (CMD_ALIAS|CMD_NODISPLAY)))
388 			(void) printf("\t%s\n",
389 				sc_get_usage((sc_usage_t)commands[i].cmdidx));
390 	}
391 }
392 
393 sa_command_t *
394 sa_lookup(char *cmd)
395 {
396 	int i;
397 	size_t len;
398 
399 	len = strlen(cmd);
400 	for (i = 0; commands[i].cmdname != NULL; i++) {
401 		if (strncmp(cmd, commands[i].cmdname, len) == 0)
402 			return (&commands[i]);
403 	}
404 	return (NULL);
405 }
406 
407 static int
408 run_command(char *command, int argc, char *argv[])
409 {
410 	sa_command_t *cmdvec;
411 	int ret;
412 
413 	/*
414 	 * To get here, we know there should be a command due to the
415 	 * preprocessing done earlier.  Need to find the protocol
416 	 * that is being affected. If no protocol, then it is ALL
417 	 * protocols.
418 	 *
419 	 * ??? do we really need the protocol at this level? it may be
420 	 * sufficient to let the commands look it up if needed since
421 	 * not all commands do proto specific things
422 	 *
423 	 * Known sub-commands are handled at this level. An unknown
424 	 * command will be passed down to the shared object that
425 	 * actually implements it. We can do this since the semantics
426 	 * of the common sub-commands is well defined.
427 	 */
428 
429 	cmdvec = sa_lookup(command);
430 	if (cmdvec == NULL) {
431 		(void) printf(gettext("command %s not found\n"), command);
432 		exit(1);
433 	}
434 	/*
435 	 * need to check priviledges and restrict what can be done
436 	 * based on least priviledge and sub-command.
437 	 */
438 	ret = cmdvec->cmdfunc(NULL, argc, argv);
439 	return (ret);
440 }
441