xref: /onnv-gate/usr/src/cmd/logadm/opts.c (revision 12986:04c3fb904c79)
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