dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / logadm / opts.c
blob6de73a599a9d10d07fba19f64ff7d29fbbefbd68
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
27 * logadm/opts.c -- options handling routines
30 #include <stdio.h>
31 #include <libintl.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <strings.h>
35 #include <time.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <errno.h>
39 #include "err.h"
40 #include "lut.h"
41 #include "fn.h"
42 #include "opts.h"
44 /* forward declarations for private functions */
45 static struct optinfo *opt_info(int c);
46 static void opts_setcmdarg(struct opts *opts, const char *cmdarg);
48 /* info created by opts_parse(), private to this module */
49 struct opts {
50 struct lut *op_raw; /* the raw text for the options */
51 struct lut *op_ints; /* the int values for the options */
52 struct fn_list *op_cmdargs; /* the op_cmdargs */
55 static off_t opts_parse_ctime(const char *o, const char *optarg);
56 static off_t opts_parse_bytes(const char *o, const char *optarg);
57 static off_t opts_parse_atopi(const char *o, const char *optarg);
58 static off_t opts_parse_seconds(const char *o, const char *optarg);
60 static struct lut *Info; /* table driving parsing */
62 /* table that drives argument parsing */
63 struct optinfo Opttable[] = {
64 { "e", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
65 { "F", OPTTYPE_STRING, NULL, OPTF_CLI },
66 { "f", OPTTYPE_STRING, NULL, OPTF_CLI },
67 { "h", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
68 { "l", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF },
69 { "N", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF },
70 { "n", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
71 { "r", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
72 { "V", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
73 { "v", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
74 { "w", OPTTYPE_STRING, NULL, OPTF_CLI },
75 { "p", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF },
76 { "P", OPTTYPE_INT, opts_parse_ctime, OPTF_CLI|OPTF_CONF },
77 { "s", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF },
78 { "a", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
79 { "b", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
80 { "c", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF },
81 { "g", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
82 { "m", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF },
83 { "M", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
84 { "o", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
85 { "R", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
86 { "t", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
87 { "z", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF },
88 { "A", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF },
89 { "C", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF },
90 { "E", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
91 { "S", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF },
92 { "T", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
95 int Opttable_cnt = sizeof (Opttable) / sizeof (struct optinfo);
98 * opts_init -- set current options parsing table
100 void
101 opts_init(struct optinfo *table, int numentries)
103 while (numentries-- > 0) {
104 Info = lut_add(Info, table->oi_o, table);
105 table++;
110 * opt_info -- fetch the optinfo struct for the given option
112 static struct optinfo *
113 opt_info(int c)
115 char lhs[2];
116 lhs[0] = c;
117 lhs[1] = '\0';
118 return ((struct optinfo *)lut_lookup(Info, lhs));
122 * opts_parse -- parse an argv-style list of options
124 * prints a message to stderr and calls err(EF_FILE|EF_JMP, ...) on error
126 struct opts *
127 opts_parse(struct opts *opts, char **argv, int flags)
129 int dashdash = 0;
130 char *ptr;
132 if (opts == NULL) {
133 opts = MALLOC(sizeof (*opts));
134 opts->op_raw = opts->op_ints = NULL;
135 opts->op_cmdargs = fn_list_new(NULL);
138 /* no words to process, just return empty opts struct */
139 if (argv == NULL)
140 return (opts);
142 /* foreach word... */
143 for (; (ptr = *argv) != NULL; argv++) {
144 if (dashdash || *ptr != '-') {
145 /* found a cmdarg */
146 opts_setcmdarg(opts, ptr);
147 continue;
149 if (*++ptr == '\0')
150 err(EF_FILE|EF_JMP, "Illegal option: dash by itself");
151 if (*ptr == '-') {
152 /* (here's where support for --longname would go) */
153 if (*(ptr + 1) != '\0')
154 err(EF_FILE|EF_JMP, "Illegal option: -%s", ptr);
155 dashdash++;
156 continue;
158 for (; *ptr; ptr++) {
159 struct optinfo *info = opt_info(*ptr);
161 /* see if option was in our parsing table */
162 if (info == NULL)
163 err(EF_FILE|EF_JMP, "Illegal option: %c", *ptr);
165 /* see if context allows this option */
166 if ((flags & OPTF_CLI) &&
167 (info->oi_flags & OPTF_CLI) == 0)
168 err(EF_FILE|EF_JMP,
169 "Option '%c' not allowed on "
170 "command line", *ptr);
172 if ((flags & OPTF_CONF) &&
173 (info->oi_flags & OPTF_CONF) == 0)
174 err(EF_FILE|EF_JMP,
175 "Option '%c' not allowed in "
176 "configuration file", *ptr);
178 /* for boolean options, we have all the info we need */
179 if (info->oi_t == OPTTYPE_BOOLEAN) {
180 (void) opts_set(opts, info->oi_o, "");
181 continue;
184 /* option expects argument */
185 if (*++ptr == '\0' &&
186 ((ptr = *++argv) == NULL || *ptr == '-'))
187 err(EF_FILE|EF_JMP,
188 "Option '%c' requires an argument",
189 info->oi_o[0]);
190 opts_set(opts, info->oi_o, ptr);
191 break;
195 return (opts);
199 * opts_free -- free a struct opts previously allocated by opts_parse()
201 void
202 opts_free(struct opts *opts)
204 if (opts) {
205 lut_free(opts->op_raw, NULL);
206 lut_free(opts->op_ints, NULL);
207 fn_list_free(opts->op_cmdargs);
208 FREE(opts);
213 * opts_set -- set an option
215 void
216 opts_set(struct opts *opts, const char *o, const char *optarg)
218 off_t *rval;
219 struct optinfo *info = opt_info(*o);
221 rval = MALLOC(sizeof (off_t));
222 opts->op_raw = lut_add(opts->op_raw, o, (void *)optarg);
224 if (info->oi_parser) {
225 *rval = (*info->oi_parser)(o, optarg);
226 opts->op_ints = lut_add(opts->op_ints, o, (void *)rval);
231 * opts_setcmdarg -- add a cmdarg to the list of op_cmdargs
233 static void
234 opts_setcmdarg(struct opts *opts, const char *cmdarg)
236 fn_list_adds(opts->op_cmdargs, cmdarg);
240 * opts_count -- return count of the options in *options that are set
243 opts_count(struct opts *opts, const char *options)
245 int count = 0;
247 for (; *options; options++) {
248 char lhs[2];
249 lhs[0] = *options;
250 lhs[1] = '\0';
251 if (lut_lookup(opts->op_raw, lhs))
252 count++;
254 return (count);
258 * opts_optarg -- return the optarg for the given option, NULL if not set
260 const char *
261 opts_optarg(struct opts *opts, const char *o)
263 return ((char *)lut_lookup(opts->op_raw, o));
267 * opts_optarg_int -- return the int value for the given option
269 off_t
270 opts_optarg_int(struct opts *opts, const char *o)
272 off_t *ret;
274 ret = (off_t *)lut_lookup(opts->op_ints, o);
275 if (ret != NULL)
276 return (*ret);
277 return (0);
281 * opts_cmdargs -- return list of op_cmdargs
283 struct fn_list *
284 opts_cmdargs(struct opts *opts)
286 return (opts->op_cmdargs);
289 static void
290 merger(const char *lhs, void *rhs, void *arg)
292 struct lut **destlutp = (struct lut **)arg;
294 *destlutp = lut_add(*destlutp, lhs, rhs);
298 * opts_merge -- merge two option lists together
300 struct opts *
301 opts_merge(struct opts *back, struct opts *front)
303 struct opts *ret = MALLOC(sizeof (struct opts));
305 ret->op_raw = lut_dup(back->op_raw);
306 lut_walk(front->op_raw, merger, &(ret->op_raw));
308 ret->op_ints = lut_dup(back->op_ints);
309 lut_walk(front->op_ints, merger, &(ret->op_ints));
311 ret->op_cmdargs = fn_list_dup(back->op_cmdargs);
313 return (ret);
317 * opts_parse_ctime -- parse a ctime format optarg
319 static off_t
320 opts_parse_ctime(const char *o, const char *optarg)
322 struct tm tm;
323 off_t ret;
325 if (strptime(optarg, "%a %b %e %T %Z %Y", &tm) == NULL &&
326 strptime(optarg, "%c", &tm) == NULL)
327 err(EF_FILE|EF_JMP,
328 "Option '%c' requires ctime-style time", *o);
329 errno = 0;
330 if ((ret = (off_t)mktime(&tm)) == -1 && errno)
331 err(EF_FILE|EF_SYS|EF_JMP, "Option '%c' Illegal time", *o);
333 return (ret);
337 * opts_parse_atopi -- parse a positive integer format optarg
339 static off_t
340 opts_parse_atopi(const char *o, const char *optarg)
342 off_t ret = atoll(optarg);
344 while (isdigit(*optarg))
345 optarg++;
347 if (*optarg)
348 err(EF_FILE|EF_JMP,
349 "Option '%c' requires non-negative number", *o);
351 return (ret);
355 * opts_parse_atopi -- parse a size format optarg into bytes
357 static off_t
358 opts_parse_bytes(const char *o, const char *optarg)
360 off_t ret = atoll(optarg);
361 while (isdigit(*optarg))
362 optarg++;
364 switch (*optarg) {
365 case 'g':
366 case 'G':
367 ret *= 1024;
368 /*FALLTHROUGH*/
369 case 'm':
370 case 'M':
371 ret *= 1024;
372 /*FALLTHROUGH*/
373 case 'k':
374 case 'K':
375 ret *= 1024;
376 /*FALLTHROUGH*/
377 case 'b':
378 case 'B':
379 if (optarg[1] == '\0')
380 return (ret);
383 err(EF_FILE|EF_JMP,
384 "Option '%c' requires number with suffix from [bkmg]", *o);
385 /*NOTREACHED*/
386 return (0);
390 * opts_parse_seconds -- parse a time format optarg into seconds
392 static off_t
393 opts_parse_seconds(const char *o, const char *optarg)
395 off_t ret;
397 if (strcasecmp(optarg, "now") == 0)
398 return (OPTP_NOW);
400 if (strcasecmp(optarg, "never") == 0)
401 return (OPTP_NEVER);
403 ret = atoll(optarg);
404 while (isdigit(*optarg))
405 optarg++;
407 if (optarg[1] == '\0')
408 switch (*optarg) {
409 case 'h':
410 case 'H':
411 ret *= 60 * 60;
412 return (ret);
413 case 'd':
414 case 'D':
415 ret *= 60 * 60 * 24;
416 return (ret);
417 case 'w':
418 case 'W':
419 ret *= 60 * 60 * 24 * 7;
420 return (ret);
421 case 'm':
422 case 'M':
423 ret *= 60 * 60 * 24 * 30;
424 return (ret);
425 case 'y':
426 case 'Y':
427 ret *= 60 * 60 * 24 * 365;
428 return (ret);
431 err(EF_FILE|EF_JMP,
432 "Option '%c' requires number with suffix from [hdwmy]", *o);
433 /*NOTREACHED*/
434 return (0);
437 /* info passed between opts_print() and printer() */
438 struct printerinfo {
439 FILE *stream;
440 int isswitch;
441 char *exclude;
444 /* helper function for opts_print() */
445 static void
446 printer(const char *lhs, void *rhs, void *arg)
448 struct printerinfo *pip = (struct printerinfo *)arg;
449 char *s = (char *)rhs;
451 if (pip->isswitch) {
452 char *ep = pip->exclude;
453 while (ep && *ep)
454 if (*ep++ == *lhs)
455 return;
458 (void) fprintf(pip->stream, " %s%s", (pip->isswitch) ? "-" : "", lhs);
459 if (s && *s) {
460 (void) fprintf(pip->stream, " ");
461 opts_printword(s, pip->stream);
466 * opts_printword -- print a word, quoting as necessary
468 void
469 opts_printword(const char *word, FILE *stream)
471 char *q = "";
473 if (word != NULL) {
474 if (strchr(word, ' ') || strchr(word, '\t') ||
475 strchr(word, '$') || strchr(word, '[') ||
476 strchr(word, '?') || strchr(word, '{') ||
477 strchr(word, '`') || strchr(word, ';')) {
478 if (strchr(word, '\'') == NULL)
479 q = "'";
480 else if (strchr(word, '"') == NULL)
481 q = "\"";
482 else
483 err(EF_FILE|EF_JMP,
484 "Can't protect quotes in <%s>", word);
485 (void) fprintf(stream, "%s%s%s", q, word, q);
486 } else
487 (void) fprintf(stream, "%s", word);
492 * opts_print -- print options to stream, leaving out those in "exclude"
494 void
495 opts_print(struct opts *opts, FILE *stream, char *exclude)
497 struct printerinfo pi;
498 struct fn *fnp;
500 pi.stream = stream;
501 pi.isswitch = 1;
502 pi.exclude = exclude;
504 lut_walk(opts->op_raw, printer, &pi);
506 fn_list_rewind(opts->op_cmdargs);
507 while ((fnp = fn_list_next(opts->op_cmdargs)) != NULL) {
508 (void) fprintf(stream, " ");
509 opts_printword(fn_s(fnp), stream);
513 #ifdef TESTMODULE
515 /* table that drives argument parsing */
516 static struct optinfo Testopttable[] = {
517 { "a", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
518 { "b", OPTTYPE_STRING, NULL, OPTF_CLI },
519 { "c", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF },
520 { "d", OPTTYPE_INT, opts_parse_ctime, OPTF_CLI|OPTF_CONF },
521 { "e", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF },
522 { "f", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF },
526 * test main for opts module, usage: a.out options...
529 main(int argc, char *argv[])
531 struct opts *opts;
533 err_init(argv[0]);
534 setbuf(stdout, NULL);
536 opts_init(Testopttable,
537 sizeof (Testopttable) / sizeof (struct optinfo));
539 argv++;
541 if (SETJMP)
542 err(0, "opts parsing failed");
543 else
544 opts = opts_parse(NULL, argv, OPTF_CLI);
546 printf("options:");
547 opts_print(opts, stdout, NULL);
548 printf("\n");
550 err_done(0);
551 /* NOTREACHED */
552 return (0);
555 #endif /* TESTMODULE */