10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52016Sbasabi * Common Development and Distribution License (the "License").
62016Sbasabi * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21236Schin
220Sstevel@tonic-gate /*
23*12986SJohn.Zolnowsky@Sun.COM * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
26236Schin /*
27236Schin * logadm/opts.c -- options handling routines
28236Schin */
29236Schin
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <strings.h>
350Sstevel@tonic-gate #include <time.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/stat.h>
380Sstevel@tonic-gate #include <errno.h>
390Sstevel@tonic-gate #include "err.h"
400Sstevel@tonic-gate #include "lut.h"
410Sstevel@tonic-gate #include "fn.h"
420Sstevel@tonic-gate #include "opts.h"
430Sstevel@tonic-gate
440Sstevel@tonic-gate /* forward declarations for private functions */
450Sstevel@tonic-gate static struct optinfo *opt_info(int c);
460Sstevel@tonic-gate static void opts_setcmdarg(struct opts *opts, const char *cmdarg);
470Sstevel@tonic-gate
480Sstevel@tonic-gate /* info created by opts_parse(), private to this module */
490Sstevel@tonic-gate struct opts {
500Sstevel@tonic-gate struct lut *op_raw; /* the raw text for the options */
510Sstevel@tonic-gate struct lut *op_ints; /* the int values for the options */
520Sstevel@tonic-gate struct fn_list *op_cmdargs; /* the op_cmdargs */
530Sstevel@tonic-gate };
540Sstevel@tonic-gate
55*12986SJohn.Zolnowsky@Sun.COM static off_t opts_parse_ctime(const char *o, const char *optarg);
56*12986SJohn.Zolnowsky@Sun.COM static off_t opts_parse_bytes(const char *o, const char *optarg);
57*12986SJohn.Zolnowsky@Sun.COM static off_t opts_parse_atopi(const char *o, const char *optarg);
58*12986SJohn.Zolnowsky@Sun.COM static off_t opts_parse_seconds(const char *o, const char *optarg);
59*12986SJohn.Zolnowsky@Sun.COM
600Sstevel@tonic-gate static struct lut *Info; /* table driving parsing */
610Sstevel@tonic-gate
62*12986SJohn.Zolnowsky@Sun.COM /* table that drives argument parsing */
63*12986SJohn.Zolnowsky@Sun.COM struct optinfo Opttable[] = {
64*12986SJohn.Zolnowsky@Sun.COM { "e", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
65*12986SJohn.Zolnowsky@Sun.COM { "F", OPTTYPE_STRING, NULL, OPTF_CLI },
66*12986SJohn.Zolnowsky@Sun.COM { "f", OPTTYPE_STRING, NULL, OPTF_CLI },
67*12986SJohn.Zolnowsky@Sun.COM { "h", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
68*12986SJohn.Zolnowsky@Sun.COM { "l", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF },
69*12986SJohn.Zolnowsky@Sun.COM { "N", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF },
70*12986SJohn.Zolnowsky@Sun.COM { "n", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
71*12986SJohn.Zolnowsky@Sun.COM { "r", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
72*12986SJohn.Zolnowsky@Sun.COM { "V", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
73*12986SJohn.Zolnowsky@Sun.COM { "v", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
74*12986SJohn.Zolnowsky@Sun.COM { "w", OPTTYPE_STRING, NULL, OPTF_CLI },
75*12986SJohn.Zolnowsky@Sun.COM { "p", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF },
76*12986SJohn.Zolnowsky@Sun.COM { "P", OPTTYPE_INT, opts_parse_ctime, OPTF_CLI|OPTF_CONF },
77*12986SJohn.Zolnowsky@Sun.COM { "s", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF },
78*12986SJohn.Zolnowsky@Sun.COM { "a", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
79*12986SJohn.Zolnowsky@Sun.COM { "b", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
80*12986SJohn.Zolnowsky@Sun.COM { "c", OPTTYPE_BOOLEAN, NULL, OPTF_CLI|OPTF_CONF },
81*12986SJohn.Zolnowsky@Sun.COM { "g", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
82*12986SJohn.Zolnowsky@Sun.COM { "m", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF },
83*12986SJohn.Zolnowsky@Sun.COM { "M", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
84*12986SJohn.Zolnowsky@Sun.COM { "o", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
85*12986SJohn.Zolnowsky@Sun.COM { "R", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
86*12986SJohn.Zolnowsky@Sun.COM { "t", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
87*12986SJohn.Zolnowsky@Sun.COM { "z", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF },
88*12986SJohn.Zolnowsky@Sun.COM { "A", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF },
89*12986SJohn.Zolnowsky@Sun.COM { "C", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF },
90*12986SJohn.Zolnowsky@Sun.COM { "E", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
91*12986SJohn.Zolnowsky@Sun.COM { "S", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF },
92*12986SJohn.Zolnowsky@Sun.COM { "T", OPTTYPE_STRING, NULL, OPTF_CLI|OPTF_CONF },
93*12986SJohn.Zolnowsky@Sun.COM };
94*12986SJohn.Zolnowsky@Sun.COM
95*12986SJohn.Zolnowsky@Sun.COM int Opttable_cnt = sizeof (Opttable) / sizeof (struct optinfo);
96*12986SJohn.Zolnowsky@Sun.COM
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate * opts_init -- set current options parsing table
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate void
opts_init(struct optinfo * table,int numentries)1010Sstevel@tonic-gate opts_init(struct optinfo *table, int numentries)
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate while (numentries-- > 0) {
1040Sstevel@tonic-gate Info = lut_add(Info, table->oi_o, table);
1050Sstevel@tonic-gate table++;
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /*
1100Sstevel@tonic-gate * opt_info -- fetch the optinfo struct for the given option
1110Sstevel@tonic-gate */
1120Sstevel@tonic-gate static struct optinfo *
opt_info(int c)1130Sstevel@tonic-gate opt_info(int c)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate char lhs[2];
1160Sstevel@tonic-gate lhs[0] = c;
1170Sstevel@tonic-gate lhs[1] = '\0';
1180Sstevel@tonic-gate return ((struct optinfo *)lut_lookup(Info, lhs));
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate * opts_parse -- parse an argv-style list of options
1230Sstevel@tonic-gate *
1240Sstevel@tonic-gate * prints a message to stderr and calls err(EF_FILE|EF_JMP, ...) on error
1250Sstevel@tonic-gate */
1260Sstevel@tonic-gate struct opts *
opts_parse(struct opts * opts,char ** argv,int flags)127*12986SJohn.Zolnowsky@Sun.COM opts_parse(struct opts *opts, char **argv, int flags)
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate int dashdash = 0;
1300Sstevel@tonic-gate char *ptr;
1310Sstevel@tonic-gate
132*12986SJohn.Zolnowsky@Sun.COM if (opts == NULL) {
133*12986SJohn.Zolnowsky@Sun.COM opts = MALLOC(sizeof (*opts));
134*12986SJohn.Zolnowsky@Sun.COM opts->op_raw = opts->op_ints = NULL;
135*12986SJohn.Zolnowsky@Sun.COM opts->op_cmdargs = fn_list_new(NULL);
136*12986SJohn.Zolnowsky@Sun.COM }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /* no words to process, just return empty opts struct */
1390Sstevel@tonic-gate if (argv == NULL)
140*12986SJohn.Zolnowsky@Sun.COM return (opts);
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate /* foreach word... */
1430Sstevel@tonic-gate for (; (ptr = *argv) != NULL; argv++) {
1440Sstevel@tonic-gate if (dashdash || *ptr != '-') {
1450Sstevel@tonic-gate /* found a cmdarg */
146*12986SJohn.Zolnowsky@Sun.COM opts_setcmdarg(opts, ptr);
1470Sstevel@tonic-gate continue;
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate if (*++ptr == '\0')
1500Sstevel@tonic-gate err(EF_FILE|EF_JMP, "Illegal option: dash by itself");
1510Sstevel@tonic-gate if (*ptr == '-') {
1520Sstevel@tonic-gate /* (here's where support for --longname would go) */
1530Sstevel@tonic-gate if (*(ptr + 1) != '\0')
1540Sstevel@tonic-gate err(EF_FILE|EF_JMP, "Illegal option: -%s", ptr);
1550Sstevel@tonic-gate dashdash++;
1560Sstevel@tonic-gate continue;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate for (; *ptr; ptr++) {
1590Sstevel@tonic-gate struct optinfo *info = opt_info(*ptr);
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate /* see if option was in our parsing table */
1620Sstevel@tonic-gate if (info == NULL)
1630Sstevel@tonic-gate err(EF_FILE|EF_JMP, "Illegal option: %c", *ptr);
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /* see if context allows this option */
1660Sstevel@tonic-gate if ((flags & OPTF_CLI) &&
1670Sstevel@tonic-gate (info->oi_flags & OPTF_CLI) == 0)
1680Sstevel@tonic-gate err(EF_FILE|EF_JMP,
1690Sstevel@tonic-gate "Option '%c' not allowed on "
1700Sstevel@tonic-gate "command line", *ptr);
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate if ((flags & OPTF_CONF) &&
1730Sstevel@tonic-gate (info->oi_flags & OPTF_CONF) == 0)
1740Sstevel@tonic-gate err(EF_FILE|EF_JMP,
1750Sstevel@tonic-gate "Option '%c' not allowed in "
1760Sstevel@tonic-gate "configuration file", *ptr);
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate /* for boolean options, we have all the info we need */
1790Sstevel@tonic-gate if (info->oi_t == OPTTYPE_BOOLEAN) {
180*12986SJohn.Zolnowsky@Sun.COM (void) opts_set(opts, info->oi_o, "");
1810Sstevel@tonic-gate continue;
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate /* option expects argument */
1850Sstevel@tonic-gate if (*++ptr == '\0' &&
1860Sstevel@tonic-gate ((ptr = *++argv) == NULL || *ptr == '-'))
1870Sstevel@tonic-gate err(EF_FILE|EF_JMP,
1880Sstevel@tonic-gate "Option '%c' requires an argument",
1890Sstevel@tonic-gate info->oi_o[0]);
190*12986SJohn.Zolnowsky@Sun.COM opts_set(opts, info->oi_o, ptr);
1910Sstevel@tonic-gate break;
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate
195*12986SJohn.Zolnowsky@Sun.COM return (opts);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * opts_free -- free a struct opts previously allocated by opts_parse()
2000Sstevel@tonic-gate */
2010Sstevel@tonic-gate void
opts_free(struct opts * opts)2020Sstevel@tonic-gate opts_free(struct opts *opts)
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate if (opts) {
2050Sstevel@tonic-gate lut_free(opts->op_raw, NULL);
2060Sstevel@tonic-gate lut_free(opts->op_ints, NULL);
2070Sstevel@tonic-gate fn_list_free(opts->op_cmdargs);
2080Sstevel@tonic-gate FREE(opts);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate * opts_set -- set an option
2140Sstevel@tonic-gate */
2150Sstevel@tonic-gate void
opts_set(struct opts * opts,const char * o,const char * optarg)2160Sstevel@tonic-gate opts_set(struct opts *opts, const char *o, const char *optarg)
2170Sstevel@tonic-gate {
2182016Sbasabi off_t *rval;
2190Sstevel@tonic-gate struct optinfo *info = opt_info(*o);
2200Sstevel@tonic-gate
2212016Sbasabi rval = MALLOC(sizeof (off_t));
2220Sstevel@tonic-gate opts->op_raw = lut_add(opts->op_raw, o, (void *)optarg);
2230Sstevel@tonic-gate
2242016Sbasabi if (info->oi_parser) {
2252016Sbasabi *rval = (*info->oi_parser)(o, optarg);
2262016Sbasabi opts->op_ints = lut_add(opts->op_ints, o, (void *)rval);
2272016Sbasabi }
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate * opts_setcmdarg -- add a cmdarg to the list of op_cmdargs
2320Sstevel@tonic-gate */
2330Sstevel@tonic-gate static void
opts_setcmdarg(struct opts * opts,const char * cmdarg)2340Sstevel@tonic-gate opts_setcmdarg(struct opts *opts, const char *cmdarg)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate fn_list_adds(opts->op_cmdargs, cmdarg);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate * opts_count -- return count of the options in *options that are set
2410Sstevel@tonic-gate */
2420Sstevel@tonic-gate int
opts_count(struct opts * opts,const char * options)2430Sstevel@tonic-gate opts_count(struct opts *opts, const char *options)
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate int count = 0;
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate for (; *options; options++) {
2480Sstevel@tonic-gate char lhs[2];
2490Sstevel@tonic-gate lhs[0] = *options;
2500Sstevel@tonic-gate lhs[1] = '\0';
2510Sstevel@tonic-gate if (lut_lookup(opts->op_raw, lhs))
2520Sstevel@tonic-gate count++;
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate return (count);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate * opts_optarg -- return the optarg for the given option, NULL if not set
2590Sstevel@tonic-gate */
2600Sstevel@tonic-gate const char *
opts_optarg(struct opts * opts,const char * o)2610Sstevel@tonic-gate opts_optarg(struct opts *opts, const char *o)
2620Sstevel@tonic-gate {
2630Sstevel@tonic-gate return ((char *)lut_lookup(opts->op_raw, o));
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate * opts_optarg_int -- return the int value for the given option
2680Sstevel@tonic-gate */
2692016Sbasabi off_t
opts_optarg_int(struct opts * opts,const char * o)2700Sstevel@tonic-gate opts_optarg_int(struct opts *opts, const char *o)
2710Sstevel@tonic-gate {
2722016Sbasabi off_t *ret;
2732016Sbasabi
2742016Sbasabi ret = (off_t *)lut_lookup(opts->op_ints, o);
2752016Sbasabi if (ret != NULL)
2762016Sbasabi return (*ret);
2772016Sbasabi return (0);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate /*
2810Sstevel@tonic-gate * opts_cmdargs -- return list of op_cmdargs
2820Sstevel@tonic-gate */
2830Sstevel@tonic-gate struct fn_list *
opts_cmdargs(struct opts * opts)2840Sstevel@tonic-gate opts_cmdargs(struct opts *opts)
2850Sstevel@tonic-gate {
2860Sstevel@tonic-gate return (opts->op_cmdargs);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate static void
merger(const char * lhs,void * rhs,void * arg)2900Sstevel@tonic-gate merger(const char *lhs, void *rhs, void *arg)
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate struct lut **destlutp = (struct lut **)arg;
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate *destlutp = lut_add(*destlutp, lhs, rhs);
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate /*
2980Sstevel@tonic-gate * opts_merge -- merge two option lists together
2990Sstevel@tonic-gate */
3000Sstevel@tonic-gate struct opts *
opts_merge(struct opts * back,struct opts * front)3010Sstevel@tonic-gate opts_merge(struct opts *back, struct opts *front)
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate struct opts *ret = MALLOC(sizeof (struct opts));
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate ret->op_raw = lut_dup(back->op_raw);
3060Sstevel@tonic-gate lut_walk(front->op_raw, merger, &(ret->op_raw));
3070Sstevel@tonic-gate
3080Sstevel@tonic-gate ret->op_ints = lut_dup(back->op_ints);
3090Sstevel@tonic-gate lut_walk(front->op_ints, merger, &(ret->op_ints));
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate ret->op_cmdargs = fn_list_dup(back->op_cmdargs);
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate return (ret);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate /*
3170Sstevel@tonic-gate * opts_parse_ctime -- parse a ctime format optarg
3180Sstevel@tonic-gate */
319*12986SJohn.Zolnowsky@Sun.COM static off_t
opts_parse_ctime(const char * o,const char * optarg)3200Sstevel@tonic-gate opts_parse_ctime(const char *o, const char *optarg)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate struct tm tm;
3232016Sbasabi off_t ret;
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate if (strptime(optarg, "%a %b %e %T %Z %Y", &tm) == NULL &&
3260Sstevel@tonic-gate strptime(optarg, "%c", &tm) == NULL)
3270Sstevel@tonic-gate err(EF_FILE|EF_JMP,
3280Sstevel@tonic-gate "Option '%c' requires ctime-style time", *o);
3290Sstevel@tonic-gate errno = 0;
3302016Sbasabi if ((ret = (off_t)mktime(&tm)) == -1 && errno)
3310Sstevel@tonic-gate err(EF_FILE|EF_SYS|EF_JMP, "Option '%c' Illegal time", *o);
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate return (ret);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate /*
3370Sstevel@tonic-gate * opts_parse_atopi -- parse a positive integer format optarg
3380Sstevel@tonic-gate */
339*12986SJohn.Zolnowsky@Sun.COM static off_t
opts_parse_atopi(const char * o,const char * optarg)3400Sstevel@tonic-gate opts_parse_atopi(const char *o, const char *optarg)
3410Sstevel@tonic-gate {
3422016Sbasabi off_t ret = atoll(optarg);
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate while (isdigit(*optarg))
3450Sstevel@tonic-gate optarg++;
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate if (*optarg)
3480Sstevel@tonic-gate err(EF_FILE|EF_JMP,
3490Sstevel@tonic-gate "Option '%c' requires non-negative number", *o);
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate return (ret);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate * opts_parse_atopi -- parse a size format optarg into bytes
3560Sstevel@tonic-gate */
357*12986SJohn.Zolnowsky@Sun.COM static off_t
opts_parse_bytes(const char * o,const char * optarg)3580Sstevel@tonic-gate opts_parse_bytes(const char *o, const char *optarg)
3590Sstevel@tonic-gate {
3602016Sbasabi off_t ret = atoll(optarg);
3610Sstevel@tonic-gate while (isdigit(*optarg))
3620Sstevel@tonic-gate optarg++;
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate switch (*optarg) {
3650Sstevel@tonic-gate case 'g':
3660Sstevel@tonic-gate case 'G':
3670Sstevel@tonic-gate ret *= 1024;
3680Sstevel@tonic-gate /*FALLTHROUGH*/
3690Sstevel@tonic-gate case 'm':
3700Sstevel@tonic-gate case 'M':
3710Sstevel@tonic-gate ret *= 1024;
3720Sstevel@tonic-gate /*FALLTHROUGH*/
3730Sstevel@tonic-gate case 'k':
3740Sstevel@tonic-gate case 'K':
3750Sstevel@tonic-gate ret *= 1024;
3760Sstevel@tonic-gate /*FALLTHROUGH*/
3770Sstevel@tonic-gate case 'b':
3780Sstevel@tonic-gate case 'B':
3790Sstevel@tonic-gate if (optarg[1] == '\0')
3800Sstevel@tonic-gate return (ret);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate err(EF_FILE|EF_JMP,
3840Sstevel@tonic-gate "Option '%c' requires number with suffix from [bkmg]", *o);
3850Sstevel@tonic-gate /*NOTREACHED*/
386236Schin return (0);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate /*
3900Sstevel@tonic-gate * opts_parse_seconds -- parse a time format optarg into seconds
3910Sstevel@tonic-gate */
392*12986SJohn.Zolnowsky@Sun.COM static off_t
opts_parse_seconds(const char * o,const char * optarg)3930Sstevel@tonic-gate opts_parse_seconds(const char *o, const char *optarg)
3940Sstevel@tonic-gate {
3952016Sbasabi off_t ret;
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate if (strcasecmp(optarg, "now") == 0)
3980Sstevel@tonic-gate return (OPTP_NOW);
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate if (strcasecmp(optarg, "never") == 0)
4010Sstevel@tonic-gate return (OPTP_NEVER);
4020Sstevel@tonic-gate
4032016Sbasabi ret = atoll(optarg);
4040Sstevel@tonic-gate while (isdigit(*optarg))
4050Sstevel@tonic-gate optarg++;
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate if (optarg[1] == '\0')
4080Sstevel@tonic-gate switch (*optarg) {
4090Sstevel@tonic-gate case 'h':
4100Sstevel@tonic-gate case 'H':
4110Sstevel@tonic-gate ret *= 60 * 60;
4120Sstevel@tonic-gate return (ret);
4130Sstevel@tonic-gate case 'd':
4140Sstevel@tonic-gate case 'D':
4150Sstevel@tonic-gate ret *= 60 * 60 * 24;
4160Sstevel@tonic-gate return (ret);
4170Sstevel@tonic-gate case 'w':
4180Sstevel@tonic-gate case 'W':
4190Sstevel@tonic-gate ret *= 60 * 60 * 24 * 7;
4200Sstevel@tonic-gate return (ret);
4210Sstevel@tonic-gate case 'm':
4220Sstevel@tonic-gate case 'M':
4230Sstevel@tonic-gate ret *= 60 * 60 * 24 * 30;
4240Sstevel@tonic-gate return (ret);
4250Sstevel@tonic-gate case 'y':
4260Sstevel@tonic-gate case 'Y':
4270Sstevel@tonic-gate ret *= 60 * 60 * 24 * 365;
4280Sstevel@tonic-gate return (ret);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate err(EF_FILE|EF_JMP,
4320Sstevel@tonic-gate "Option '%c' requires number with suffix from [hdwmy]", *o);
4330Sstevel@tonic-gate /*NOTREACHED*/
434236Schin return (0);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate /* info passed between opts_print() and printer() */
438236Schin struct printerinfo {
4390Sstevel@tonic-gate FILE *stream;
4400Sstevel@tonic-gate int isswitch;
4410Sstevel@tonic-gate char *exclude;
4420Sstevel@tonic-gate };
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate /* helper function for opts_print() */
4450Sstevel@tonic-gate static void
printer(const char * lhs,void * rhs,void * arg)4460Sstevel@tonic-gate printer(const char *lhs, void *rhs, void *arg)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate struct printerinfo *pip = (struct printerinfo *)arg;
4490Sstevel@tonic-gate char *s = (char *)rhs;
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate if (pip->isswitch) {
4520Sstevel@tonic-gate char *ep = pip->exclude;
4530Sstevel@tonic-gate while (ep && *ep)
4540Sstevel@tonic-gate if (*ep++ == *lhs)
4550Sstevel@tonic-gate return;
4560Sstevel@tonic-gate }
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate (void) fprintf(pip->stream, " %s%s", (pip->isswitch) ? "-" : "", lhs);
4590Sstevel@tonic-gate if (s && *s) {
4600Sstevel@tonic-gate (void) fprintf(pip->stream, " ");
4610Sstevel@tonic-gate opts_printword(s, pip->stream);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate /*
4660Sstevel@tonic-gate * opts_printword -- print a word, quoting as necessary
4670Sstevel@tonic-gate */
4680Sstevel@tonic-gate void
opts_printword(const char * word,FILE * stream)4690Sstevel@tonic-gate opts_printword(const char *word, FILE *stream)
4700Sstevel@tonic-gate {
4710Sstevel@tonic-gate char *q = "";
4720Sstevel@tonic-gate
4732397Sbasabi if (word != NULL) {
4742397Sbasabi if (strchr(word, ' ') || strchr(word, '\t') ||
4752397Sbasabi strchr(word, '$') || strchr(word, '[') ||
4762397Sbasabi strchr(word, '?') || strchr(word, '{') ||
4772397Sbasabi strchr(word, '`') || strchr(word, ';')) {
478*12986SJohn.Zolnowsky@Sun.COM if (strchr(word, '\'') == NULL)
479*12986SJohn.Zolnowsky@Sun.COM q = "'";
480*12986SJohn.Zolnowsky@Sun.COM else if (strchr(word, '"') == NULL)
4812397Sbasabi q = "\"";
482*12986SJohn.Zolnowsky@Sun.COM else
4832397Sbasabi err(EF_FILE|EF_JMP,
4842397Sbasabi "Can't protect quotes in <%s>", word);
4852397Sbasabi (void) fprintf(stream, "%s%s%s", q, word, q);
4862397Sbasabi } else
4872397Sbasabi (void) fprintf(stream, "%s", word);
4882397Sbasabi }
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate /*
4920Sstevel@tonic-gate * opts_print -- print options to stream, leaving out those in "exclude"
4930Sstevel@tonic-gate */
4940Sstevel@tonic-gate void
opts_print(struct opts * opts,FILE * stream,char * exclude)4950Sstevel@tonic-gate opts_print(struct opts *opts, FILE *stream, char *exclude)
4960Sstevel@tonic-gate {
4970Sstevel@tonic-gate struct printerinfo pi;
4980Sstevel@tonic-gate struct fn *fnp;
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate pi.stream = stream;
5010Sstevel@tonic-gate pi.isswitch = 1;
5020Sstevel@tonic-gate pi.exclude = exclude;
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate lut_walk(opts->op_raw, printer, &pi);
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate fn_list_rewind(opts->op_cmdargs);
5070Sstevel@tonic-gate while ((fnp = fn_list_next(opts->op_cmdargs)) != NULL) {
5080Sstevel@tonic-gate (void) fprintf(stream, " ");
5090Sstevel@tonic-gate opts_printword(fn_s(fnp), stream);
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate #ifdef TESTMODULE
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate /* table that drives argument parsing */
516*12986SJohn.Zolnowsky@Sun.COM static struct optinfo Testopttable[] = {
5170Sstevel@tonic-gate { "a", OPTTYPE_BOOLEAN, NULL, OPTF_CLI },
5180Sstevel@tonic-gate { "b", OPTTYPE_STRING, NULL, OPTF_CLI },
5190Sstevel@tonic-gate { "c", OPTTYPE_INT, opts_parse_seconds, OPTF_CLI|OPTF_CONF },
5200Sstevel@tonic-gate { "d", OPTTYPE_INT, opts_parse_ctime, OPTF_CLI|OPTF_CONF },
5210Sstevel@tonic-gate { "e", OPTTYPE_INT, opts_parse_bytes, OPTF_CLI|OPTF_CONF },
5220Sstevel@tonic-gate { "f", OPTTYPE_INT, opts_parse_atopi, OPTF_CLI|OPTF_CONF },
5230Sstevel@tonic-gate };
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate /*
5260Sstevel@tonic-gate * test main for opts module, usage: a.out options...
5270Sstevel@tonic-gate */
5282397Sbasabi int
main(int argc,char * argv[])5290Sstevel@tonic-gate main(int argc, char *argv[])
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate struct opts *opts;
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate err_init(argv[0]);
5340Sstevel@tonic-gate setbuf(stdout, NULL);
5350Sstevel@tonic-gate
536*12986SJohn.Zolnowsky@Sun.COM opts_init(Testopttable,
537*12986SJohn.Zolnowsky@Sun.COM sizeof (Testopttable) / sizeof (struct optinfo));
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate argv++;
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate if (SETJMP)
5420Sstevel@tonic-gate err(0, "opts parsing failed");
5430Sstevel@tonic-gate else
544*12986SJohn.Zolnowsky@Sun.COM opts = opts_parse(NULL, argv, OPTF_CLI);
5450Sstevel@tonic-gate
5460Sstevel@tonic-gate printf("options:");
5470Sstevel@tonic-gate opts_print(opts, stdout, NULL);
5480Sstevel@tonic-gate printf("\n");
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate err_done(0);
5512397Sbasabi /* NOTREACHED */
5522397Sbasabi return (0);
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate #endif /* TESTMODULE */
556