xref: /illumos-gate/usr/src/cmd/cron/parse.c (revision 6b734416)
1*6b734416SAndy Fiddaman /*
2*6b734416SAndy Fiddaman  * CDDL HEADER START
3*6b734416SAndy Fiddaman  *
4*6b734416SAndy Fiddaman  * The contents of this file are subject to the terms of the
5*6b734416SAndy Fiddaman  * Common Development and Distribution License (the "License").
6*6b734416SAndy Fiddaman  * You may not use this file except in compliance with the License.
7*6b734416SAndy Fiddaman  *
8*6b734416SAndy Fiddaman  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6b734416SAndy Fiddaman  * or http://www.opensolaris.org/os/licensing.
10*6b734416SAndy Fiddaman  * See the License for the specific language governing permissions
11*6b734416SAndy Fiddaman  * and limitations under the License.
12*6b734416SAndy Fiddaman  *
13*6b734416SAndy Fiddaman  * When distributing Covered Code, include this CDDL HEADER in each
14*6b734416SAndy Fiddaman  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6b734416SAndy Fiddaman  * If applicable, add the following below this CDDL HEADER, with the
16*6b734416SAndy Fiddaman  * fields enclosed by brackets "[]" replaced with your own identifying
17*6b734416SAndy Fiddaman  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6b734416SAndy Fiddaman  *
19*6b734416SAndy Fiddaman  * CDDL HEADER END
20*6b734416SAndy Fiddaman  */
21*6b734416SAndy Fiddaman 
22*6b734416SAndy Fiddaman /*
23*6b734416SAndy Fiddaman  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*6b734416SAndy Fiddaman  * Use is subject to license terms.
25*6b734416SAndy Fiddaman  */
26*6b734416SAndy Fiddaman 
27*6b734416SAndy Fiddaman /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*6b734416SAndy Fiddaman /*	  All Rights Reserved	*/
29*6b734416SAndy Fiddaman 
30*6b734416SAndy Fiddaman /*
31*6b734416SAndy Fiddaman  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
32*6b734416SAndy Fiddaman  */
33*6b734416SAndy Fiddaman 
34*6b734416SAndy Fiddaman #include <stdio.h>
35*6b734416SAndy Fiddaman #include <err.h>
36*6b734416SAndy Fiddaman #include <sys/types.h>
37*6b734416SAndy Fiddaman #include <string.h>
38*6b734416SAndy Fiddaman #include <stdlib.h>
39*6b734416SAndy Fiddaman #include <ctype.h>
40*6b734416SAndy Fiddaman #include <assert.h>
41*6b734416SAndy Fiddaman #include <libcustr.h>
42*6b734416SAndy Fiddaman #include "cron.h"
43*6b734416SAndy Fiddaman 
44*6b734416SAndy Fiddaman #ifdef PARSETEST
45*6b734416SAndy Fiddaman #define	xstrdup(x) strdup((x))
46*6b734416SAndy Fiddaman #endif
47*6b734416SAndy Fiddaman 
48*6b734416SAndy Fiddaman #define	MAX_ELEMENTS 60
49*6b734416SAndy Fiddaman 
50*6b734416SAndy Fiddaman #define	READNUMBER(x) \
51*6b734416SAndy Fiddaman 	do { \
52*6b734416SAndy Fiddaman 		(x) = (x) * 10 + (line[cursor] - '0'); \
53*6b734416SAndy Fiddaman 		if ((x) > MAX_ELEMENTS) { \
54*6b734416SAndy Fiddaman 			err = CFOUTOFBOUND; \
55*6b734416SAndy Fiddaman 			goto out; \
56*6b734416SAndy Fiddaman 		} \
57*6b734416SAndy Fiddaman 	} while (isdigit(line[++cursor]))
58*6b734416SAndy Fiddaman 
59*6b734416SAndy Fiddaman #define	ADDELEMENT(x)  \
60*6b734416SAndy Fiddaman 	do { \
61*6b734416SAndy Fiddaman 		if (eindex >= MAX_ELEMENTS) { \
62*6b734416SAndy Fiddaman 			err = CFEOVERFLOW; \
63*6b734416SAndy Fiddaman 			goto out; \
64*6b734416SAndy Fiddaman 		} \
65*6b734416SAndy Fiddaman 		elements[eindex++] = (x); \
66*6b734416SAndy Fiddaman 	} while (0)
67*6b734416SAndy Fiddaman 
68*6b734416SAndy Fiddaman /* A more restrictive version of isspace(3C) that only looks for space/tab */
69*6b734416SAndy Fiddaman #define	ISSPACE(x) \
70*6b734416SAndy Fiddaman 	((x) == ' ' || (x) == '\t')
71*6b734416SAndy Fiddaman 
72*6b734416SAndy Fiddaman cferror_t
next_field(uint_t lower,uint_t upper,char * line,int * cursorp,char ** ret)73*6b734416SAndy Fiddaman next_field(uint_t lower, uint_t upper, char *line, int *cursorp, char **ret)
74*6b734416SAndy Fiddaman {
75*6b734416SAndy Fiddaman 	uint_t elements[MAX_ELEMENTS];
76*6b734416SAndy Fiddaman 	uint_t eindex = 0, i;
77*6b734416SAndy Fiddaman 	int cursor = *cursorp;
78*6b734416SAndy Fiddaman 	cferror_t err = CFOK;
79*6b734416SAndy Fiddaman 
80*6b734416SAndy Fiddaman 	assert(upper - lower <= MAX_ELEMENTS);
81*6b734416SAndy Fiddaman 
82*6b734416SAndy Fiddaman 	if (ret != NULL)
83*6b734416SAndy Fiddaman 		*ret = NULL;
84*6b734416SAndy Fiddaman 
85*6b734416SAndy Fiddaman 	while (ISSPACE(line[cursor]))
86*6b734416SAndy Fiddaman 		cursor++;
87*6b734416SAndy Fiddaman 
88*6b734416SAndy Fiddaman 	if (line[cursor] == '\0') {
89*6b734416SAndy Fiddaman 		err = CFEOLN;
90*6b734416SAndy Fiddaman 		goto out;
91*6b734416SAndy Fiddaman 	}
92*6b734416SAndy Fiddaman 
93*6b734416SAndy Fiddaman 	for (;;) {
94*6b734416SAndy Fiddaman 		uint_t num = 0, num2 = 0, step = 0;
95*6b734416SAndy Fiddaman 
96*6b734416SAndy Fiddaman 		if (line[cursor] == '*') {
97*6b734416SAndy Fiddaman 			cursor++;
98*6b734416SAndy Fiddaman 
99*6b734416SAndy Fiddaman 			/* Short circuit for plain '*' */
100*6b734416SAndy Fiddaman 			if (ISSPACE(line[cursor])) {
101*6b734416SAndy Fiddaman 				if (ret != NULL)
102*6b734416SAndy Fiddaman 					*ret = xstrdup("*");
103*6b734416SAndy Fiddaman 				goto out;
104*6b734416SAndy Fiddaman 			}
105*6b734416SAndy Fiddaman 
106*6b734416SAndy Fiddaman 			/*
107*6b734416SAndy Fiddaman 			 * '*' is only permitted alongside other elements if
108*6b734416SAndy Fiddaman 			 * it has an associated step.
109*6b734416SAndy Fiddaman 			 */
110*6b734416SAndy Fiddaman 
111*6b734416SAndy Fiddaman 			if (line[cursor] != '/') {
112*6b734416SAndy Fiddaman 				err = CFUNEXPECT;
113*6b734416SAndy Fiddaman 				goto out;
114*6b734416SAndy Fiddaman 			}
115*6b734416SAndy Fiddaman 
116*6b734416SAndy Fiddaman 			/* Treat it as a range covering all values */
117*6b734416SAndy Fiddaman 			num = lower;
118*6b734416SAndy Fiddaman 			num2 = upper;
119*6b734416SAndy Fiddaman 		} else {
120*6b734416SAndy Fiddaman 			if (!isdigit(line[cursor])) {
121*6b734416SAndy Fiddaman 				err = CFUNEXPECT;
122*6b734416SAndy Fiddaman 				goto out;
123*6b734416SAndy Fiddaman 			}
124*6b734416SAndy Fiddaman 
125*6b734416SAndy Fiddaman 			READNUMBER(num);
126*6b734416SAndy Fiddaman 
127*6b734416SAndy Fiddaman 			if (num < lower || num > upper) {
128*6b734416SAndy Fiddaman 				err = CFOUTOFBOUND;
129*6b734416SAndy Fiddaman 				goto out;
130*6b734416SAndy Fiddaman 			}
131*6b734416SAndy Fiddaman 
132*6b734416SAndy Fiddaman 			if (line[cursor] == '-') {
133*6b734416SAndy Fiddaman 				cursor++;
134*6b734416SAndy Fiddaman 				if (!isdigit(line[cursor])) {
135*6b734416SAndy Fiddaman 					err = CFUNEXPECT;
136*6b734416SAndy Fiddaman 					goto out;
137*6b734416SAndy Fiddaman 				}
138*6b734416SAndy Fiddaman 
139*6b734416SAndy Fiddaman 				READNUMBER(num2);
140*6b734416SAndy Fiddaman 
141*6b734416SAndy Fiddaman 				if (num2 < lower || num2 > upper) {
142*6b734416SAndy Fiddaman 					err = CFOUTOFBOUND;
143*6b734416SAndy Fiddaman 					goto out;
144*6b734416SAndy Fiddaman 				}
145*6b734416SAndy Fiddaman 			} else {
146*6b734416SAndy Fiddaman 				ADDELEMENT(num);
147*6b734416SAndy Fiddaman 				goto next;
148*6b734416SAndy Fiddaman 			}
149*6b734416SAndy Fiddaman 		}
150*6b734416SAndy Fiddaman 
151*6b734416SAndy Fiddaman 		/* Look for a step definition */
152*6b734416SAndy Fiddaman 		if (line[cursor] == '/') {
153*6b734416SAndy Fiddaman 			cursor++;
154*6b734416SAndy Fiddaman 			if (!isdigit(line[cursor])) {
155*6b734416SAndy Fiddaman 				err = CFUNEXPECT;
156*6b734416SAndy Fiddaman 				goto out;
157*6b734416SAndy Fiddaman 			}
158*6b734416SAndy Fiddaman 
159*6b734416SAndy Fiddaman 			READNUMBER(step);
160*6b734416SAndy Fiddaman 
161*6b734416SAndy Fiddaman 			if (step == 0) {
162*6b734416SAndy Fiddaman 				err = CFOUTOFBOUND;
163*6b734416SAndy Fiddaman 				goto out;
164*6b734416SAndy Fiddaman 			}
165*6b734416SAndy Fiddaman 		} else {
166*6b734416SAndy Fiddaman 			step = 1;
167*6b734416SAndy Fiddaman 		}
168*6b734416SAndy Fiddaman 
169*6b734416SAndy Fiddaman 		if (num <= num2) {
170*6b734416SAndy Fiddaman 			for (i = num; i <= num2; i += step) {
171*6b734416SAndy Fiddaman 				ADDELEMENT(i);
172*6b734416SAndy Fiddaman 			}
173*6b734416SAndy Fiddaman 		} else {
174*6b734416SAndy Fiddaman 			/* Wrap-around range */
175*6b734416SAndy Fiddaman 			for (i = num; i <= upper; i += step) {
176*6b734416SAndy Fiddaman 				ADDELEMENT(i);
177*6b734416SAndy Fiddaman 			}
178*6b734416SAndy Fiddaman 
179*6b734416SAndy Fiddaman 			i -= (upper - lower + 1);
180*6b734416SAndy Fiddaman 			for (; i <= num2; i += step) {
181*6b734416SAndy Fiddaman 				ADDELEMENT(i);
182*6b734416SAndy Fiddaman 			}
183*6b734416SAndy Fiddaman 		}
184*6b734416SAndy Fiddaman 
185*6b734416SAndy Fiddaman next:
186*6b734416SAndy Fiddaman 
187*6b734416SAndy Fiddaman 		if (line[cursor] != ',')
188*6b734416SAndy Fiddaman 			break;
189*6b734416SAndy Fiddaman 
190*6b734416SAndy Fiddaman 		cursor++;
191*6b734416SAndy Fiddaman 	}
192*6b734416SAndy Fiddaman 
193*6b734416SAndy Fiddaman 	if (line[cursor] == '\0') {
194*6b734416SAndy Fiddaman 		err = CFEOLN;
195*6b734416SAndy Fiddaman 		goto out;
196*6b734416SAndy Fiddaman 	}
197*6b734416SAndy Fiddaman 
198*6b734416SAndy Fiddaman 	if (!ISSPACE(line[cursor])) {
199*6b734416SAndy Fiddaman 		err = CFUNEXPECT;
200*6b734416SAndy Fiddaman 		goto out;
201*6b734416SAndy Fiddaman 	}
202*6b734416SAndy Fiddaman 
203*6b734416SAndy Fiddaman 	if (ret != NULL) {
204*6b734416SAndy Fiddaman 		custr_t *cs = NULL;
205*6b734416SAndy Fiddaman 
206*6b734416SAndy Fiddaman 		if (custr_alloc(&cs) != 0) {
207*6b734416SAndy Fiddaman 			err = CFENOMEM;
208*6b734416SAndy Fiddaman 			goto out;
209*6b734416SAndy Fiddaman 		}
210*6b734416SAndy Fiddaman 
211*6b734416SAndy Fiddaman 		for (i = 0; i < eindex; i++) {
212*6b734416SAndy Fiddaman 			if (custr_len(cs) > 0) {
213*6b734416SAndy Fiddaman 				if (custr_appendc(cs, ',') != 0) {
214*6b734416SAndy Fiddaman 					custr_free(cs);
215*6b734416SAndy Fiddaman 					err = CFENOMEM;
216*6b734416SAndy Fiddaman 					goto out;
217*6b734416SAndy Fiddaman 				}
218*6b734416SAndy Fiddaman 			}
219*6b734416SAndy Fiddaman 			if (custr_append_printf(cs, "%u", elements[i]) != 0) {
220*6b734416SAndy Fiddaman 				custr_free(cs);
221*6b734416SAndy Fiddaman 				err = CFENOMEM;
222*6b734416SAndy Fiddaman 				goto out;
223*6b734416SAndy Fiddaman 			}
224*6b734416SAndy Fiddaman 		}
225*6b734416SAndy Fiddaman 
226*6b734416SAndy Fiddaman 		if (custr_len(cs) != 0)
227*6b734416SAndy Fiddaman 			*ret = xstrdup(custr_cstr(cs));
228*6b734416SAndy Fiddaman 		custr_free(cs);
229*6b734416SAndy Fiddaman 	}
230*6b734416SAndy Fiddaman 
231*6b734416SAndy Fiddaman out:
232*6b734416SAndy Fiddaman 
233*6b734416SAndy Fiddaman 	*cursorp = cursor;
234*6b734416SAndy Fiddaman 
235*6b734416SAndy Fiddaman 	return (err);
236*6b734416SAndy Fiddaman }
237*6b734416SAndy Fiddaman 
238*6b734416SAndy Fiddaman #ifdef PARSETEST
239*6b734416SAndy Fiddaman int
main(int argc,char ** argv)240*6b734416SAndy Fiddaman main(int argc, char **argv)
241*6b734416SAndy Fiddaman {
242*6b734416SAndy Fiddaman 	int lower, upper, cursor = 0;
243*6b734416SAndy Fiddaman 	char *ret;
244*6b734416SAndy Fiddaman 
245*6b734416SAndy Fiddaman 	if (argc != 4)
246*6b734416SAndy Fiddaman 		errx(1, "<lower> <upper> <string>");
247*6b734416SAndy Fiddaman 
248*6b734416SAndy Fiddaman 	lower = atoi(argv[1]);
249*6b734416SAndy Fiddaman 	upper = atoi(argv[2]);
250*6b734416SAndy Fiddaman 
251*6b734416SAndy Fiddaman 	switch (next_field(lower, upper, argv[3], &cursor, &ret)) {
252*6b734416SAndy Fiddaman 	case CFOK:
253*6b734416SAndy Fiddaman 		(void) printf("%s\n", ret);
254*6b734416SAndy Fiddaman 		break;
255*6b734416SAndy Fiddaman 	case CFEOLN:
256*6b734416SAndy Fiddaman 		(void) printf("UnexpectedEOL\n");
257*6b734416SAndy Fiddaman 		break;
258*6b734416SAndy Fiddaman 	case CFUNEXPECT:
259*6b734416SAndy Fiddaman 		(void) printf("UnexpectedChar\n");
260*6b734416SAndy Fiddaman 		break;
261*6b734416SAndy Fiddaman 	case CFOUTOFBOUND:
262*6b734416SAndy Fiddaman 		(void) printf("OutOfBounds\n");
263*6b734416SAndy Fiddaman 		break;
264*6b734416SAndy Fiddaman 	case CFEOVERFLOW:
265*6b734416SAndy Fiddaman 		(void) printf("Overflow\n");
266*6b734416SAndy Fiddaman 		break;
267*6b734416SAndy Fiddaman 	case CFENOMEM:
268*6b734416SAndy Fiddaman 		(void) printf("OutOfMemory\n");
269*6b734416SAndy Fiddaman 		break;
270*6b734416SAndy Fiddaman 	default:
271*6b734416SAndy Fiddaman 		(void) printf("UnknownError\n");
272*6b734416SAndy Fiddaman 		break;
273*6b734416SAndy Fiddaman 	}
274*6b734416SAndy Fiddaman 
275*6b734416SAndy Fiddaman 	return (0);
276*6b734416SAndy Fiddaman }
277*6b734416SAndy Fiddaman #endif
278