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]
23 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
27 * logadm/opts.c -- options handling routines
36 #include <sys/types.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 */
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
101 opts_init(struct optinfo
*table
, int numentries
)
103 while (numentries
-- > 0) {
104 Info
= lut_add(Info
, table
->oi_o
, table
);
110 * opt_info -- fetch the optinfo struct for the given option
112 static struct optinfo
*
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
127 opts_parse(struct opts
*opts
, char **argv
, int flags
)
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 */
142 /* foreach word... */
143 for (; (ptr
= *argv
) != NULL
; argv
++) {
144 if (dashdash
|| *ptr
!= '-') {
146 opts_setcmdarg(opts
, ptr
);
150 err(EF_FILE
|EF_JMP
, "Illegal option: dash by itself");
152 /* (here's where support for --longname would go) */
153 if (*(ptr
+ 1) != '\0')
154 err(EF_FILE
|EF_JMP
, "Illegal option: -%s", ptr
);
158 for (; *ptr
; ptr
++) {
159 struct optinfo
*info
= opt_info(*ptr
);
161 /* see if option was in our parsing table */
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)
169 "Option '%c' not allowed on "
170 "command line", *ptr
);
172 if ((flags
& OPTF_CONF
) &&
173 (info
->oi_flags
& OPTF_CONF
) == 0)
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
, "");
184 /* option expects argument */
185 if (*++ptr
== '\0' &&
186 ((ptr
= *++argv
) == NULL
|| *ptr
== '-'))
188 "Option '%c' requires an argument",
190 opts_set(opts
, info
->oi_o
, ptr
);
199 * opts_free -- free a struct opts previously allocated by opts_parse()
202 opts_free(struct opts
*opts
)
205 lut_free(opts
->op_raw
, NULL
);
206 lut_free(opts
->op_ints
, NULL
);
207 fn_list_free(opts
->op_cmdargs
);
213 * opts_set -- set an option
216 opts_set(struct opts
*opts
, const char *o
, const char *optarg
)
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
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
)
247 for (; *options
; options
++) {
251 if (lut_lookup(opts
->op_raw
, lhs
))
258 * opts_optarg -- return the optarg for the given option, NULL if not set
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
270 opts_optarg_int(struct opts
*opts
, const char *o
)
274 ret
= (off_t
*)lut_lookup(opts
->op_ints
, o
);
281 * opts_cmdargs -- return list of op_cmdargs
284 opts_cmdargs(struct opts
*opts
)
286 return (opts
->op_cmdargs
);
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
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
);
317 * opts_parse_ctime -- parse a ctime format optarg
320 opts_parse_ctime(const char *o
, const char *optarg
)
325 if (strptime(optarg
, "%a %b %e %T %Z %Y", &tm
) == NULL
&&
326 strptime(optarg
, "%c", &tm
) == NULL
)
328 "Option '%c' requires ctime-style time", *o
);
330 if ((ret
= (off_t
)mktime(&tm
)) == -1 && errno
)
331 err(EF_FILE
|EF_SYS
|EF_JMP
, "Option '%c' Illegal time", *o
);
337 * opts_parse_atopi -- parse a positive integer format optarg
340 opts_parse_atopi(const char *o
, const char *optarg
)
342 off_t ret
= atoll(optarg
);
344 while (isdigit(*optarg
))
349 "Option '%c' requires non-negative number", *o
);
355 * opts_parse_atopi -- parse a size format optarg into bytes
358 opts_parse_bytes(const char *o
, const char *optarg
)
360 off_t ret
= atoll(optarg
);
361 while (isdigit(*optarg
))
379 if (optarg
[1] == '\0')
384 "Option '%c' requires number with suffix from [bkmg]", *o
);
390 * opts_parse_seconds -- parse a time format optarg into seconds
393 opts_parse_seconds(const char *o
, const char *optarg
)
397 if (strcasecmp(optarg
, "now") == 0)
400 if (strcasecmp(optarg
, "never") == 0)
404 while (isdigit(*optarg
))
407 if (optarg
[1] == '\0')
419 ret
*= 60 * 60 * 24 * 7;
423 ret
*= 60 * 60 * 24 * 30;
427 ret
*= 60 * 60 * 24 * 365;
432 "Option '%c' requires number with suffix from [hdwmy]", *o
);
437 /* info passed between opts_print() and printer() */
444 /* helper function for opts_print() */
446 printer(const char *lhs
, void *rhs
, void *arg
)
448 struct printerinfo
*pip
= (struct printerinfo
*)arg
;
449 char *s
= (char *)rhs
;
452 char *ep
= pip
->exclude
;
458 (void) fprintf(pip
->stream
, " %s%s", (pip
->isswitch
) ? "-" : "", lhs
);
460 (void) fprintf(pip
->stream
, " ");
461 opts_printword(s
, pip
->stream
);
466 * opts_printword -- print a word, quoting as necessary
469 opts_printword(const char *word
, FILE *stream
)
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
)
480 else if (strchr(word
, '"') == NULL
)
484 "Can't protect quotes in <%s>", word
);
485 (void) fprintf(stream
, "%s%s%s", q
, word
, q
);
487 (void) fprintf(stream
, "%s", word
);
492 * opts_print -- print options to stream, leaving out those in "exclude"
495 opts_print(struct opts
*opts
, FILE *stream
, char *exclude
)
497 struct printerinfo pi
;
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
);
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
[])
534 setbuf(stdout
, NULL
);
536 opts_init(Testopttable
,
537 sizeof (Testopttable
) / sizeof (struct optinfo
));
542 err(0, "opts parsing failed");
544 opts
= opts_parse(NULL
, argv
, OPTF_CLI
);
547 opts_print(opts
, stdout
, NULL
);
555 #endif /* TESTMODULE */