GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rdist/gram.y Lines: 0 173 0.0 %
Date: 2017-11-07 Branches: 0 150 0.0 %

Line Branch Exec Source
1
%{
2
/*	$OpenBSD: gram.y,v 1.12 2015/01/20 09:00:16 guenther Exp $	*/
3
4
/*
5
 * Copyright (c) 1993 Michael A. Cooper
6
 * Copyright (c) 1993 Regents of the University of California.
7
 * All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 * 3. Neither the name of the University nor the names of its contributors
18
 *    may be used to endorse or promote products derived from this software
19
 *    without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
 * SUCH DAMAGE.
32
 */
33
34
#include "client.h"
35
36
static struct namelist *addnl(struct namelist *, struct namelist *);
37
static struct namelist *subnl(struct namelist *, struct namelist *);
38
static struct namelist *andnl(struct namelist *, struct namelist *);
39
static int innl(struct namelist *nl, char *p);
40
41
struct	cmd *cmds = NULL;
42
struct	cmd *last_cmd;
43
struct	namelist *last_n;
44
struct	subcmd *last_sc;
45
int	parendepth = 0;
46
47
%}
48
49
%term ARROW		1
50
%term COLON		2
51
%term DCOLON		3
52
%term NAME		4
53
%term STRING		5
54
%term INSTALL		6
55
%term NOTIFY		7
56
%term EXCEPT		8
57
%term PATTERN		9
58
%term SPECIAL		10
59
%term CMDSPECIAL	11
60
%term OPTION		12
61
62
%union {
63
	opt_t 			optval;
64
	char 		       *string;
65
	struct subcmd 	       *subcmd;
66
	struct namelist        *namel;
67
}
68
69
%type <optval> OPTION, options
70
%type <string> NAME, STRING
71
%type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, CMDSPECIAL, cmdlist, cmd
72
%type <namel> namelist, names, opt_namelist nlist
73
74
%%
75
76
file:		  /* VOID */
77
		| file command
78
		;
79
80
command:	  NAME '=' namelist = {
81
			(void) lookup($1, INSERT, $3);
82
		}
83
		| namelist ARROW namelist cmdlist = {
84
			insert((char *)NULL, $1, $3, $4);
85
		}
86
		| NAME COLON namelist ARROW namelist cmdlist = {
87
			insert($1, $3, $5, $6);
88
		}
89
		| namelist DCOLON NAME cmdlist = {
90
			append((char *)NULL, $1, $3, $4);
91
		}
92
		| NAME COLON namelist DCOLON NAME cmdlist = {
93
			append($1, $3, $5, $6);
94
		}
95
		| error
96
		;
97
98
namelist: 	nlist {
99
			$$ = $1;
100
		}
101
		| nlist '-' nlist {
102
			$$ = subnl($1, $3);
103
		}
104
		| nlist '+' nlist {
105
			$$ = addnl($1, $3);
106
		}
107
		| nlist '&' nlist {
108
			$$ = andnl($1, $3);
109
		}
110
		;
111
112
nlist:	  NAME = {
113
			$$ = makenl($1);
114
		}
115
		| '(' names ')' = {
116
			$$ = $2;
117
		}
118
		;
119
120
names:		  /* VOID */ {
121
			$$ = last_n = NULL;
122
		}
123
		| names NAME = {
124
			if (last_n == NULL)
125
				$$ = last_n = makenl($2);
126
			else {
127
				last_n->n_next = makenl($2);
128
				last_n = last_n->n_next;
129
				$$ = $1;
130
			}
131
		}
132
		;
133
134
cmdlist:	  /* VOID */ {
135
			$$ = last_sc = NULL;
136
		}
137
		| cmdlist cmd = {
138
			if (last_sc == NULL)
139
				$$ = last_sc = $2;
140
			else {
141
				last_sc->sc_next = $2;
142
				last_sc = $2;
143
				$$ = $1;
144
			}
145
		}
146
		;
147
148
cmd:		  INSTALL options opt_namelist ';' = {
149
			struct namelist *nl;
150
151
			$1->sc_options = $2 | options;
152
			if ($3 != NULL) {
153
				nl = expand($3, E_VARS);
154
				if (nl) {
155
					if (nl->n_next != NULL)
156
					    yyerror("only one name allowed\n");
157
					$1->sc_name = nl->n_name;
158
					free(nl);
159
				} else
160
					$1->sc_name = NULL;
161
			}
162
			$$ = $1;
163
		}
164
		| NOTIFY namelist ';' = {
165
			if ($2 != NULL)
166
				$1->sc_args = expand($2, E_VARS);
167
			$$ = $1;
168
		}
169
		| EXCEPT namelist ';' = {
170
			if ($2 != NULL)
171
				$1->sc_args = expand($2, E_ALL);
172
			$$ = $1;
173
		}
174
		| PATTERN namelist ';' = {
175
			struct namelist *nl;
176
			char ebuf[BUFSIZ];
177
			regex_t reg;
178
			int ecode;
179
180
			for (nl = $2; nl != NULL; nl = nl->n_next) {
181
				/* check for a valid regex */
182
				ecode = regcomp(&reg, nl->n_name, REG_NOSUB);
183
				if (ecode) {
184
					regerror(ecode, &reg, ebuf,
185
					    sizeof(ebuf));
186
					yyerror(ebuf);
187
				}
188
				regfree(&reg);
189
			}
190
			$1->sc_args = expand($2, E_VARS);
191
			$$ = $1;
192
		}
193
		| SPECIAL opt_namelist STRING ';' = {
194
			if ($2 != NULL)
195
				$1->sc_args = expand($2, E_ALL);
196
			$1->sc_name = $3;
197
			$$ = $1;
198
		}
199
		| CMDSPECIAL opt_namelist STRING ';' = {
200
			if ($2 != NULL)
201
				$1->sc_args = expand($2, E_ALL);
202
			$1->sc_name = $3;
203
			$$ = $1;
204
		}
205
		;
206
207
options:	  /* VOID */ = {
208
			$$ = 0;
209
		}
210
		| options OPTION = {
211
			$$ |= $2;
212
		}
213
		;
214
215
opt_namelist:	  /* VOID */ = {
216
			$$ = NULL;
217
		}
218
		| namelist = {
219
			$$ = $1;
220
		}
221
		;
222
223
%%
224
225
int	yylineno = 1;
226
extern	FILE *fin;
227
228
int
229
yylex(void)
230
{
231
	static char yytext[INMAX];
232
	int c;
233
	char *cp1, *cp2;
234
	static char quotechars[] = "[]{}*?$";
235
236
again:
237
	switch (c = getc(fin)) {
238
	case EOF:  /* end of file */
239
		return(0);
240
241
	case '#':  /* start of comment */
242
		while ((c = getc(fin)) != EOF && c != '\n')
243
			;
244
		if (c == EOF)
245
			return(0);
246
	case '\n':
247
		yylineno++;
248
	case ' ':
249
	case '\t':  /* skip blanks */
250
		goto again;
251
252
	case '=':  /* EQUAL */
253
	case ';':  /* SM */
254
	case '+':
255
	case '&':
256
		return(c);
257
258
	case '(':  /* LP */
259
		++parendepth;
260
		return(c);
261
262
	case ')':  /* RP */
263
		--parendepth;
264
		return(c);
265
266
	case '-':  /* -> */
267
		if ((c = getc(fin)) == '>')
268
			return(ARROW);
269
		(void) ungetc(c, fin);
270
		c = '-';
271
		break;
272
273
	case '"':  /* STRING */
274
		cp1 = yytext;
275
		cp2 = &yytext[INMAX - 1];
276
		for (;;) {
277
			if (cp1 >= cp2) {
278
				yyerror("command string too long\n");
279
				break;
280
			}
281
			c = getc(fin);
282
			if (c == EOF || c == '"')
283
				break;
284
			if (c == '\\') {
285
				if ((c = getc(fin)) == EOF) {
286
					*cp1++ = '\\';
287
					break;
288
				}
289
			}
290
			if (c == '\n') {
291
				yylineno++;
292
				c = ' '; /* can't send '\n' */
293
			}
294
			*cp1++ = c;
295
		}
296
		if (c != '"')
297
			yyerror("missing closing '\"'\n");
298
		*cp1 = '\0';
299
		yylval.string = xstrdup(yytext);
300
		return(STRING);
301
302
	case ':':  /* : or :: */
303
		if ((c = getc(fin)) == ':')
304
			return(DCOLON);
305
		(void) ungetc(c, fin);
306
		return(COLON);
307
	}
308
	cp1 = yytext;
309
	cp2 = &yytext[INMAX - 1];
310
	for (;;) {
311
		if (cp1 >= cp2) {
312
			yyerror("input line too long\n");
313
			break;
314
		}
315
		if (c == '\\') {
316
			if ((c = getc(fin)) != EOF) {
317
				if (any(c, quotechars))
318
					*cp1++ = QUOTECHAR;
319
			} else {
320
				*cp1++ = '\\';
321
				break;
322
			}
323
		}
324
		*cp1++ = c;
325
		c = getc(fin);
326
		if (c == EOF || any(c, " \"'\t()=;:\n")) {
327
			(void) ungetc(c, fin);
328
			break;
329
		}
330
	}
331
	*cp1 = '\0';
332
	if (yytext[0] == '-' && yytext[1] == CNULL)
333
		return '-';
334
	if (yytext[0] == '-' && parendepth <= 0) {
335
		opt_t opt = 0;
336
		static char ebuf[BUFSIZ];
337
338
		switch (yytext[1]) {
339
		case 'o':
340
			if (parsedistopts(&yytext[2], &opt, TRUE)) {
341
				(void) snprintf(ebuf, sizeof(ebuf),
342
					        "Bad distfile options \"%s\".",
343
					        &yytext[2]);
344
				yyerror(ebuf);
345
			}
346
			break;
347
348
			/*
349
			 * These options are obsoleted by -o.
350
			 */
351
		case 'b':	opt = DO_COMPARE;		break;
352
		case 'R':	opt = DO_REMOVE;		break;
353
		case 'v':	opt = DO_VERIFY;		break;
354
		case 'w':	opt = DO_WHOLE;			break;
355
		case 'y':	opt = DO_YOUNGER;		break;
356
		case 'h':	opt = DO_FOLLOW;		break;
357
		case 'i':	opt = DO_IGNLNKS;		break;
358
		case 'q':	opt = DO_QUIET;			break;
359
		case 'x':	opt = DO_NOEXEC;		break;
360
		case 'N':	opt = DO_CHKNFS;		break;
361
		case 'O':	opt = DO_CHKREADONLY;		break;
362
		case 's':	opt = DO_SAVETARGETS;		break;
363
		case 'r':	opt = DO_NODESCEND;		break;
364
365
		default:
366
			(void) snprintf(ebuf, sizeof(ebuf),
367
					"Unknown option \"%s\".", yytext);
368
			yyerror(ebuf);
369
		}
370
371
		yylval.optval = opt;
372
		return(OPTION);
373
	}
374
	if (!strcmp(yytext, "install"))
375
		c = INSTALL;
376
	else if (!strcmp(yytext, "notify"))
377
		c = NOTIFY;
378
	else if (!strcmp(yytext, "except"))
379
		c = EXCEPT;
380
	else if (!strcmp(yytext, "except_pat"))
381
		c = PATTERN;
382
	else if (!strcmp(yytext, "special"))
383
		c = SPECIAL;
384
	else if (!strcmp(yytext, "cmdspecial"))
385
		c = CMDSPECIAL;
386
	else {
387
		yylval.string = xstrdup(yytext);
388
		return(NAME);
389
	}
390
	yylval.subcmd = makesubcmd(c);
391
	return(c);
392
}
393
394
/*
395
 * XXX We should use strchr(), but most versions can't handle
396
 * some of the characters we use.
397
 */
398
int any(int c, char *str)
399
{
400
	while (*str)
401
		if (c == *str++)
402
			return(1);
403
	return(0);
404
}
405
406
/*
407
 * Insert or append ARROW command to list of hosts to be updated.
408
 */
409
void
410
insert(char *label, struct namelist *files, struct namelist *hosts,
411
    struct subcmd *scmds)
412
{
413
	struct cmd *c, *prev, *nc;
414
	struct namelist *h, *lasth;
415
416
	debugmsg(DM_CALL, "insert(%s, %p, %p, %p) start, files = %s",
417
		 label == NULL ? "(null)" : label,
418
		 files, hosts, scmds, getnlstr(files));
419
420
	files = expand(files, E_VARS|E_SHELL);
421
	hosts = expand(hosts, E_ALL);
422
	for (h = hosts; h != NULL; lasth = h, h = h->n_next,
423
	     free((char *)lasth)) {
424
		/*
425
		 * Search command list for an update to the same host.
426
		 */
427
		for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
428
			if (strcmp(c->c_name, h->n_name) == 0) {
429
				do {
430
					prev = c;
431
					c = c->c_next;
432
				} while (c != NULL &&
433
					strcmp(c->c_name, h->n_name) == 0);
434
				break;
435
			}
436
		}
437
		/*
438
		 * Insert new command to update host.
439
		 */
440
		nc = ALLOC(cmd);
441
		nc->c_type = ARROW;
442
		nc->c_name = h->n_name;
443
		nc->c_label = label;
444
		nc->c_files = files;
445
		nc->c_cmds = scmds;
446
		nc->c_flags = 0;
447
		nc->c_next = c;
448
		if (prev == NULL)
449
			cmds = nc;
450
		else
451
			prev->c_next = nc;
452
		/* update last_cmd if appending nc to cmds */
453
		if (c == NULL)
454
			last_cmd = nc;
455
	}
456
}
457
458
/*
459
 * Append DCOLON command to the end of the command list since these are always
460
 * executed in the order they appear in the distfile.
461
 */
462
void
463
append(char *label, struct namelist *files, char *stamp, struct subcmd *scmds)
464
{
465
	struct cmd *c;
466
467
	c = ALLOC(cmd);
468
	c->c_type = DCOLON;
469
	c->c_name = stamp;
470
	c->c_label = label;
471
	c->c_files = expand(files, E_ALL);
472
	c->c_cmds = scmds;
473
	c->c_next = NULL;
474
	if (cmds == NULL)
475
		cmds = last_cmd = c;
476
	else {
477
		last_cmd->c_next = c;
478
		last_cmd = c;
479
	}
480
}
481
482
/*
483
 * Error printing routine in parser.
484
 */
485
void
486
yyerror(char *s)
487
{
488
	error("Error in distfile: line %d: %s", yylineno, s);
489
}
490
491
/*
492
 * Allocate a namelist structure.
493
 */
494
struct namelist *
495
makenl(char *name)
496
{
497
	struct namelist *nl;
498
499
	debugmsg(DM_CALL, "makenl(%s)", name == NULL ? "null" : name);
500
501
	nl = ALLOC(namelist);
502
	nl->n_name = name;
503
	nl->n_regex = NULL;
504
	nl->n_next = NULL;
505
506
	return(nl);
507
}
508
509
510
/*
511
 * Is the name p in the namelist nl?
512
 */
513
static int
514
innl(struct namelist *nl, char *p)
515
{
516
	for ( ; nl; nl = nl->n_next)
517
		if (!strcmp(p, nl->n_name))
518
			return(1);
519
	return(0);
520
}
521
522
/*
523
 * Join two namelists.
524
 */
525
static struct namelist *
526
addnl(struct namelist *n1, struct namelist *n2)
527
{
528
	struct namelist *nl, *prev;
529
530
	n1 = expand(n1, E_VARS);
531
	n2 = expand(n2, E_VARS);
532
	for (prev = NULL, nl = NULL; n1; n1 = n1->n_next, prev = nl) {
533
		nl = makenl(n1->n_name);
534
		nl->n_next = prev;
535
	}
536
	for (; n2; n2 = n2->n_next)
537
		if (!innl(nl, n2->n_name)) {
538
			nl = makenl(n2->n_name);
539
			nl->n_next = prev;
540
			prev = nl;
541
		}
542
	return(prev);
543
}
544
545
/*
546
 * Copy n1 except for elements that are in n2.
547
 */
548
static struct namelist *
549
subnl(struct namelist *n1, struct namelist *n2)
550
{
551
	struct namelist *nl, *prev;
552
553
	n1 = expand(n1, E_VARS);
554
	n2 = expand(n2, E_VARS);
555
	for (prev = NULL; n1; n1 = n1->n_next)
556
		if (!innl(n2, n1->n_name)) {
557
			nl = makenl(n1->n_name);
558
			nl->n_next = prev;
559
			prev = nl;
560
		}
561
	return(prev);
562
}
563
564
/*
565
 * Copy all items of n1 that are also in n2.
566
 */
567
static struct namelist *
568
andnl(struct namelist *n1, struct namelist *n2)
569
{
570
	struct namelist *nl, *prev;
571
572
	n1 = expand(n1, E_VARS);
573
	n2 = expand(n2, E_VARS);
574
	for (prev = NULL; n1; n1 = n1->n_next)
575
		if (innl(n2, n1->n_name)) {
576
			nl = makenl(n1->n_name);
577
			nl->n_next = prev;
578
			prev = nl;
579
		}
580
	return(prev);
581
}
582
583
/*
584
 * Make a sub command for lists of variables, commands, etc.
585
 */
586
struct subcmd *
587
makesubcmd(int type)
588
{
589
	struct subcmd *sc;
590
591
	sc = ALLOC(subcmd);
592
	sc->sc_type = type;
593
	sc->sc_args = NULL;
594
	sc->sc_next = NULL;
595
	sc->sc_name = NULL;
596
597
	return(sc);
598
}