1 /*
2  * Create a squashfs filesystem.  This is a highly compressed read only
3  * filesystem.
4  *
5  * Copyright (c) 2011, 2012, 2013, 2014
6  * Phillip Lougher <phillip@squashfs.org.uk>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2,
11  * or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  *
22  * action.c
23  */
24 
25 #include <fcntl.h>
26 #include <dirent.h>
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <pwd.h>
35 #include <grp.h>
36 #include <sys/wait.h>
37 #include <regex.h>
38 #include <limits.h>
39 #include <errno.h>
40 
41 #include "squashfs_fs.h"
42 #include "mksquashfs.h"
43 #include "action.h"
44 #include "error.h"
45 #include "fnmatch_compat.h"
46 
47 #ifndef strdupa
48 #include <string.h>  // required for str*()
49 #include <stdlib.h>  // required for alloca
50 #define strdupa(foo) (strncpy( alloca( strlen(foo) + 1 ), foo, strlen( foo ) + 1 ))
51 #endif
52 
53 /*
54  * code to parse actions
55  */
56 
57 static char *cur_ptr, *source;
58 static struct action *fragment_spec = NULL;
59 static struct action *exclude_spec = NULL;
60 static struct action *empty_spec = NULL;
61 static struct action *move_spec = NULL;
62 static struct action *prune_spec = NULL;
63 static struct action *other_spec = NULL;
64 static int fragment_count = 0;
65 static int exclude_count = 0;
66 static int empty_count = 0;
67 static int move_count = 0;
68 static int prune_count = 0;
69 static int other_count = 0;
70 static struct action_entry *parsing_action;
71 
72 static struct file_buffer *def_fragment = NULL;
73 
74 static struct token_entry token_table[] = {
75 	{ "(", TOK_OPEN_BRACKET, 1, },
76 	{ ")", TOK_CLOSE_BRACKET, 1 },
77 	{ "&&", TOK_AND, 2 },
78 	{ "||", TOK_OR, 2 },
79 	{ "!", TOK_NOT, 1 },
80 	{ ",", TOK_COMMA, 1 },
81 	{ "@", TOK_AT, 1},
82 	{ " ", 	TOK_WHITE_SPACE, 1 },
83 	{ "\t ", TOK_WHITE_SPACE, 1 },
84 	{ "", -1, 0 }
85 };
86 
87 
88 static struct test_entry test_table[];
89 
90 static struct action_entry action_table[];
91 
92 static struct expr *parse_expr(int subexp);
93 
94 extern char *pathname(struct dir_ent *);
95 
96 extern char *subpathname(struct dir_ent *);
97 
98 extern int read_file(char *filename, char *type, int (parse_line)(char *));
99 
100 /*
101  * Lexical analyser
102  */
103 #define STR_SIZE 256
104 
get_token(char ** string)105 static int get_token(char **string)
106 {
107 	/* string buffer */
108 	static char *str = NULL;
109 	static int size = 0;
110 
111 	char *str_ptr;
112 	int cur_size, i, quoted;
113 
114 	while (1) {
115 		if (*cur_ptr == '\0')
116 			return TOK_EOF;
117 		for (i = 0; token_table[i].token != -1; i++)
118 			if (strncmp(cur_ptr, token_table[i].string,
119 						token_table[i].size) == 0)
120 				break;
121 		if (token_table[i].token != TOK_WHITE_SPACE)
122 			break;
123 		cur_ptr ++;
124 	}
125 
126 	if (token_table[i].token != -1) {
127 		cur_ptr += token_table[i].size;
128 		return token_table[i].token;
129 	}
130 
131 	/* string */
132 	if(str == NULL) {
133 		str = malloc(STR_SIZE);
134 		if(str == NULL)
135 			MEM_ERROR();
136 		size = STR_SIZE;
137 	}
138 
139 	/* Initialise string being read */
140 	str_ptr = str;
141 	cur_size = 0;
142 	quoted = 0;
143 
144 	while(1) {
145 		while(*cur_ptr == '"') {
146 			cur_ptr ++;
147 			quoted = !quoted;
148 		}
149 
150 		if(*cur_ptr == '\0') {
151 			/* inside quoted string EOF, otherwise end of string */
152 			if(quoted)
153 				return TOK_EOF;
154 			else
155 				break;
156 		}
157 
158 		if(!quoted) {
159 			for(i = 0; token_table[i].token != -1; i++)
160 				if (strncmp(cur_ptr, token_table[i].string,
161 						token_table[i].size) == 0)
162 					break;
163 			if (token_table[i].token != -1)
164 				break;
165 		}
166 
167 		if(*cur_ptr == '\\') {
168 			cur_ptr ++;
169 			if(*cur_ptr == '\0')
170 				return TOK_EOF;
171 		}
172 
173 		if(cur_size + 2 > size) {
174 			char *tmp;
175 
176 			size = (cur_size + 1  + STR_SIZE) & ~(STR_SIZE - 1);
177 
178 			tmp = realloc(str, size);
179 			if(tmp == NULL)
180 				MEM_ERROR();
181 
182 			str_ptr = str_ptr - str + tmp;
183 			str = tmp;
184 		}
185 
186 		*str_ptr ++ = *cur_ptr ++;
187 		cur_size ++;
188 	}
189 
190 	*str_ptr = '\0';
191 	*string = str;
192 	return TOK_STRING;
193 }
194 
195 
peek_token(char ** string)196 static int peek_token(char **string)
197 {
198 	char *saved = cur_ptr;
199 	int token = get_token(string);
200 
201 	cur_ptr = saved;
202 
203 	return token;
204 }
205 
206 
207 /*
208  * Expression parser
209  */
free_parse_tree(struct expr * expr)210 static void free_parse_tree(struct expr *expr)
211 {
212 	if(expr->type == ATOM_TYPE) {
213 		int i;
214 
215 		for(i = 0; i < expr->atom.test->args; i++)
216 			free(expr->atom.argv[i]);
217 
218 		free(expr->atom.argv);
219 	} else if (expr->type == UNARY_TYPE)
220 		free_parse_tree(expr->unary_op.expr);
221 	else {
222 		free_parse_tree(expr->expr_op.lhs);
223 		free_parse_tree(expr->expr_op.rhs);
224 	}
225 
226 	free(expr);
227 }
228 
229 
create_expr(struct expr * lhs,int op,struct expr * rhs)230 static struct expr *create_expr(struct expr *lhs, int op, struct expr *rhs)
231 {
232 	struct expr *expr;
233 
234 	if (rhs == NULL) {
235 		free_parse_tree(lhs);
236 		return NULL;
237 	}
238 
239 	expr = malloc(sizeof(*expr));
240 	if (expr == NULL)
241 		MEM_ERROR();
242 
243 	expr->type = OP_TYPE;
244 	expr->expr_op.lhs = lhs;
245 	expr->expr_op.rhs = rhs;
246 	expr->expr_op.op = op;
247 
248 	return expr;
249 }
250 
251 
create_unary_op(struct expr * lhs,int op)252 static struct expr *create_unary_op(struct expr *lhs, int op)
253 {
254 	struct expr *expr;
255 
256 	if (lhs == NULL)
257 		return NULL;
258 
259 	expr = malloc(sizeof(*expr));
260 	if (expr == NULL)
261 		MEM_ERROR();
262 
263 	expr->type = UNARY_TYPE;
264 	expr->unary_op.expr = lhs;
265 	expr->unary_op.op = op;
266 
267 	return expr;
268 }
269 
270 
parse_test(char * name)271 static struct expr *parse_test(char *name)
272 {
273 	char *string, **argv = NULL;
274 	int token, args = 0;
275 	int i;
276 	struct test_entry *test;
277 	struct expr *expr;
278 
279 	for (i = 0; test_table[i].args != -1; i++)
280 		if (strcmp(name, test_table[i].name) == 0)
281 			break;
282 
283 	test = &test_table[i];
284 
285 	if (test->args == -1) {
286 		SYNTAX_ERROR("Non-existent test \"%s\"\n", name);
287 		return NULL;
288 	}
289 
290 	if(parsing_action->type == EXCLUDE_ACTION && !test->exclude_ok) {
291 		fprintf(stderr, "Failed to parse action \"%s\"\n", source);
292 		fprintf(stderr, "Test \"%s\" cannot be used in exclude "
293 							"actions\n", name);
294 		fprintf(stderr, "Use prune action instead ...\n");
295 		return NULL;
296 	}
297 
298 	expr = malloc(sizeof(*expr));
299 	if (expr == NULL)
300 		MEM_ERROR();
301 
302 	expr->type = ATOM_TYPE;
303 
304 	expr->atom.test = test;
305 	expr->atom.data = NULL;
306 
307 	/*
308 	 * If the test has no arguments, then go straight to checking if there's
309 	 * enough arguments
310 	 */
311 	token = peek_token(&string);
312 
313 	if (token != TOK_OPEN_BRACKET)
314 			goto skip_args;
315 
316 	get_token(&string);
317 
318 	/*
319 	 * speculatively read all the arguments, and then see if the
320 	 * number of arguments read is the number expected, this handles
321 	 * tests with a variable number of arguments
322 	 */
323 	token = get_token(&string);
324 	if (token == TOK_CLOSE_BRACKET)
325 		goto skip_args;
326 
327 	while(1) {
328 		if (token != TOK_STRING) {
329 			SYNTAX_ERROR("Unexpected token \"%s\", expected "
330 				"argument\n", TOK_TO_STR(token, string));
331 			goto failed;
332 		}
333 
334 		argv = realloc(argv, (args + 1) * sizeof(char *));
335 		if (argv == NULL)
336 			MEM_ERROR();
337 
338 		argv[args ++ ] = strdup(string);
339 
340 		token = get_token(&string);
341 
342 		if (token == TOK_CLOSE_BRACKET)
343 			break;
344 
345 		if (token != TOK_COMMA) {
346 			SYNTAX_ERROR("Unexpected token \"%s\", expected "
347 				"\",\" or \")\"\n", TOK_TO_STR(token, string));
348 			goto failed;
349 		}
350 		token = get_token(&string);
351 	}
352 
353 skip_args:
354 	/*
355 	 * expected number of arguments?
356 	 */
357 	if(test->args != -2 && args != test->args) {
358 		SYNTAX_ERROR("Unexpected number of arguments, expected %d, "
359 			"got %d\n", test->args, args);
360 		goto failed;
361 	}
362 
363 	expr->atom.args = args;
364 	expr->atom.argv = argv;
365 
366 	if (test->parse_args) {
367 		int res = test->parse_args(test, &expr->atom);
368 
369 		if (res == 0)
370 			goto failed;
371 	}
372 
373 	return expr;
374 
375 failed:
376 	free(argv);
377 	free(expr);
378 	return NULL;
379 }
380 
381 
get_atom()382 static struct expr *get_atom()
383 {
384 	char *string;
385 	int token = get_token(&string);
386 
387 	switch(token) {
388 	case TOK_NOT:
389 		return create_unary_op(get_atom(), token);
390 	case TOK_OPEN_BRACKET:
391 		return parse_expr(1);
392 	case TOK_STRING:
393 		return parse_test(string);
394 	default:
395 		SYNTAX_ERROR("Unexpected token \"%s\", expected test "
396 					"operation, \"!\", or \"(\"\n",
397 					TOK_TO_STR(token, string));
398 		return NULL;
399 	}
400 }
401 
402 
parse_expr(int subexp)403 static struct expr *parse_expr(int subexp)
404 {
405 	struct expr *expr = get_atom();
406 
407 	while (expr) {
408 		char *string;
409 		int op = get_token(&string);
410 
411 		if (op == TOK_EOF) {
412 			if (subexp) {
413 				free_parse_tree(expr);
414 				SYNTAX_ERROR("Expected \"&&\", \"||\" or "
415 						"\")\", got EOF\n");
416 				return NULL;
417 			}
418 			break;
419 		}
420 
421 		if (op == TOK_CLOSE_BRACKET) {
422 			if (!subexp) {
423 				free_parse_tree(expr);
424 				SYNTAX_ERROR("Unexpected \")\", expected "
425 						"\"&&\", \"!!\" or EOF\n");
426 				return NULL;
427 			}
428 			break;
429 		}
430 
431 		if (op != TOK_AND && op != TOK_OR) {
432 			free_parse_tree(expr);
433 			SYNTAX_ERROR("Unexpected token \"%s\", expected "
434 				"\"&&\" or \"||\"\n", TOK_TO_STR(op, string));
435 			return NULL;
436 		}
437 
438 		expr = create_expr(expr, op, get_atom());
439 	}
440 
441 	return expr;
442 }
443 
444 
445 /*
446  * Action parser
447  */
parse_action(char * s,int verbose)448 int parse_action(char *s, int verbose)
449 {
450 	char *string, **argv = NULL;
451 	int i, token, args = 0;
452 	struct expr *expr;
453 	struct action_entry *action;
454 	void *data = NULL;
455 	struct action **spec_list;
456 	int spec_count;
457 
458 	cur_ptr = source = s;
459 	token = get_token(&string);
460 
461 	if (token != TOK_STRING) {
462 		SYNTAX_ERROR("Unexpected token \"%s\", expected name\n",
463 						TOK_TO_STR(token, string));
464 		return 0;
465 	}
466 
467 	for (i = 0; action_table[i].args != -1; i++)
468 		if (strcmp(string, action_table[i].name) == 0)
469 			break;
470 
471 	if (action_table[i].args == -1) {
472 		SYNTAX_ERROR("Non-existent action \"%s\"\n", string);
473 		return 0;
474 	}
475 
476 	action = &action_table[i];
477 
478 	token = get_token(&string);
479 
480 	if (token == TOK_AT)
481 		goto skip_args;
482 
483 	if (token != TOK_OPEN_BRACKET) {
484 		SYNTAX_ERROR("Unexpected token \"%s\", expected \"(\"\n",
485 						TOK_TO_STR(token, string));
486 		goto failed;
487 	}
488 
489 	/*
490 	 * speculatively read all the arguments, and then see if the
491 	 * number of arguments read is the number expected, this handles
492 	 * actions with a variable number of arguments
493 	 */
494 	token = get_token(&string);
495 	if (token == TOK_CLOSE_BRACKET)
496 		goto skip_args;
497 
498 	while (1) {
499 		if (token != TOK_STRING) {
500 			SYNTAX_ERROR("Unexpected token \"%s\", expected "
501 				"argument\n", TOK_TO_STR(token, string));
502 			goto failed;
503 		}
504 
505 		argv = realloc(argv, (args + 1) * sizeof(char *));
506 		if (argv == NULL)
507 			MEM_ERROR();
508 
509 		argv[args ++] = strdup(string);
510 
511 		token = get_token(&string);
512 
513 		if (token == TOK_CLOSE_BRACKET)
514 			break;
515 
516 		if (token != TOK_COMMA) {
517 			SYNTAX_ERROR("Unexpected token \"%s\", expected "
518 				"\",\" or \")\"\n", TOK_TO_STR(token, string));
519 			goto failed;
520 		}
521 		token = get_token(&string);
522 	}
523 
524 skip_args:
525 	/*
526 	 * expected number of arguments?
527 	 */
528 	if(action->args != -2 && args != action->args) {
529 		SYNTAX_ERROR("Unexpected number of arguments, expected %d, "
530 			"got %d\n", action->args, args);
531 		goto failed;
532 	}
533 
534 	if (action->parse_args) {
535 		int res = action->parse_args(action, args, argv, &data);
536 
537 		if (res == 0)
538 			goto failed;
539 	}
540 
541 	if (token == TOK_CLOSE_BRACKET)
542 		token = get_token(&string);
543 
544 	if (token != TOK_AT) {
545 		SYNTAX_ERROR("Unexpected token \"%s\", expected \"@\"\n",
546 						TOK_TO_STR(token, string));
547 		goto failed;
548 	}
549 
550 	parsing_action = action;
551 	expr = parse_expr(0);
552 
553 	if (expr == NULL)
554 		goto failed;
555 
556 	/*
557 	 * choose action list and increment action counter
558 	 */
559 	switch(action->type) {
560 	case FRAGMENT_ACTION:
561 		spec_count = fragment_count ++;
562 		spec_list = &fragment_spec;
563 		break;
564 	case EXCLUDE_ACTION:
565 		spec_count = exclude_count ++;
566 		spec_list = &exclude_spec;
567 		break;
568 	case EMPTY_ACTION:
569 		spec_count = empty_count ++;
570 		spec_list = &empty_spec;
571 		break;
572 	case MOVE_ACTION:
573 		spec_count = move_count ++;
574 		spec_list = &move_spec;
575 		break;
576 	case PRUNE_ACTION:
577 		spec_count = prune_count ++;
578 		spec_list = &prune_spec;
579 		break;
580 	default:
581 		spec_count = other_count ++;
582 		spec_list = &other_spec;
583 	}
584 
585 	*spec_list = realloc(*spec_list, (spec_count + 1) *
586 					sizeof(struct action));
587 	if (*spec_list == NULL)
588 		MEM_ERROR();
589 
590 	(*spec_list)[spec_count].type = action->type;
591 	(*spec_list)[spec_count].action = action;
592 	(*spec_list)[spec_count].args = args;
593 	(*spec_list)[spec_count].argv = argv;
594 	(*spec_list)[spec_count].expr = expr;
595 	(*spec_list)[spec_count].data = data;
596 	(*spec_list)[spec_count].verbose = verbose;
597 
598 	return 1;
599 
600 failed:
601 	free(argv);
602 	return 0;
603 }
604 
605 
606 /*
607  * Evaluate expressions
608  */
609 
610 #define ALLOC_SZ 128
611 
612 #define LOG_ENABLE	0
613 #define LOG_DISABLE	1
614 #define LOG_PRINT	2
615 #define LOG_ENABLED	3
616 
_expr_log(char * string,int cmnd)617 char *_expr_log(char *string, int cmnd)
618 {
619 	static char *expr_msg = NULL;
620 	static int cur_size = 0, alloc_size = 0;
621 	int size;
622 
623 	switch(cmnd) {
624 	case LOG_ENABLE:
625 		expr_msg = malloc(ALLOC_SZ);
626 		alloc_size = ALLOC_SZ;
627 		cur_size = 0;
628 		return expr_msg;
629 	case LOG_DISABLE:
630 		free(expr_msg);
631 		alloc_size = cur_size = 0;
632 		return expr_msg = NULL;
633 	case LOG_ENABLED:
634 		return expr_msg;
635 	default:
636 		if(expr_msg == NULL)
637 			return NULL;
638 		break;
639 	}
640 
641 	/* if string is empty append '\0' */
642 	size = strlen(string) ? : 1;
643 
644 	if(alloc_size - cur_size < size) {
645 		/* buffer too small, expand */
646 		alloc_size = (cur_size + size + ALLOC_SZ - 1) & ~(ALLOC_SZ - 1);
647 
648 		expr_msg = realloc(expr_msg, alloc_size);
649 		if(expr_msg == NULL)
650 			MEM_ERROR();
651 	}
652 
653 	memcpy(expr_msg + cur_size, string, size);
654 	cur_size += size;
655 
656 	return expr_msg;
657 }
658 
659 
expr_log_cmnd(int cmnd)660 char *expr_log_cmnd(int cmnd)
661 {
662 	return _expr_log(NULL, cmnd);
663 }
664 
665 
expr_log(char * string)666 char *expr_log(char *string)
667 {
668 	return _expr_log(string, LOG_PRINT);
669 }
670 
671 
expr_log_atom(struct atom * atom)672 void expr_log_atom(struct atom *atom)
673 {
674 	int i;
675 
676 	if(atom->test->handle_logging)
677 		return;
678 
679 	expr_log(atom->test->name);
680 
681 	if(atom->args) {
682 		expr_log("(");
683 		for(i = 0; i < atom->args; i++) {
684 			expr_log(atom->argv[i]);
685 			if (i + 1 < atom->args)
686 				expr_log(",");
687 		}
688 		expr_log(")");
689 	}
690 }
691 
692 
expr_log_match(int match)693 void expr_log_match(int match)
694 {
695 	if(match)
696 		expr_log("=True");
697 	else
698 		expr_log("=False");
699 }
700 
701 
eval_expr_log(struct expr * expr,struct action_data * action_data)702 static int eval_expr_log(struct expr *expr, struct action_data *action_data)
703 {
704 	int match;
705 
706 	switch (expr->type) {
707 	case ATOM_TYPE:
708 		expr_log_atom(&expr->atom);
709 		match = expr->atom.test->fn(&expr->atom, action_data);
710 		expr_log_match(match);
711 		break;
712 	case UNARY_TYPE:
713 		expr_log("!");
714 		match = !eval_expr_log(expr->unary_op.expr, action_data);
715 		break;
716 	default:
717 		expr_log("(");
718 		match = eval_expr_log(expr->expr_op.lhs, action_data);
719 
720 		if ((expr->expr_op.op == TOK_AND && match) ||
721 				(expr->expr_op.op == TOK_OR && !match)) {
722 			expr_log(token_table[expr->expr_op.op].string);
723 			match = eval_expr_log(expr->expr_op.rhs, action_data);
724 		}
725 		expr_log(")");
726 		break;
727 	}
728 
729 	return match;
730 }
731 
732 
eval_expr(struct expr * expr,struct action_data * action_data)733 static int eval_expr(struct expr *expr, struct action_data *action_data)
734 {
735 	int match;
736 
737 	switch (expr->type) {
738 	case ATOM_TYPE:
739 		match = expr->atom.test->fn(&expr->atom, action_data);
740 		break;
741 	case UNARY_TYPE:
742 		match = !eval_expr(expr->unary_op.expr, action_data);
743 		break;
744 	default:
745 		match = eval_expr(expr->expr_op.lhs, action_data);
746 
747 		if ((expr->expr_op.op == TOK_AND && match) ||
748 					(expr->expr_op.op == TOK_OR && !match))
749 			match = eval_expr(expr->expr_op.rhs, action_data);
750 		break;
751 	}
752 
753 	return match;
754 }
755 
756 
eval_expr_top(struct action * action,struct action_data * action_data)757 static int eval_expr_top(struct action *action, struct action_data *action_data)
758 {
759 	if(action->verbose) {
760 		int match, n;
761 
762 		expr_log_cmnd(LOG_ENABLE);
763 
764 		if(action_data->subpath)
765 			expr_log(action_data->subpath);
766 
767 		expr_log("=");
768 		expr_log(action->action->name);
769 
770 		if(action->args) {
771 			expr_log("(");
772 			for (n = 0; n < action->args; n++) {
773 				expr_log(action->argv[n]);
774 				if(n + 1 < action->args)
775 					expr_log(",");
776 			}
777 			expr_log(")");
778 		}
779 
780 		expr_log("@");
781 
782 		match = eval_expr_log(action->expr, action_data);
783 
784 		/*
785 		 * Print the evaluated expression log, if the
786 		 * result matches the logging specified
787 		 */
788 		if((match && (action->verbose & ACTION_LOG_TRUE)) || (!match
789 				&& (action->verbose & ACTION_LOG_FALSE)))
790 			progressbar_info("%s\n", expr_log(""));
791 
792 		expr_log_cmnd(LOG_DISABLE);
793 
794 		return match;
795 	} else
796 		return eval_expr(action->expr, action_data);
797 }
798 
799 
800 /*
801  * Read action file, passing each line to parse_action() for
802  * parsing.
803  *
804  * One action per line, of the form
805  *	action(arg1,arg2)@expr(arg1,arg2)....
806  *
807  * Actions can be split across multiple lines using "\".
808  *
809  * Blank lines and comment lines indicated by # are supported.
810  */
parse_action_true(char * s)811 int parse_action_true(char *s)
812 {
813 	return parse_action(s, ACTION_LOG_TRUE);
814 }
815 
816 
parse_action_false(char * s)817 int parse_action_false(char *s)
818 {
819 	return parse_action(s, ACTION_LOG_FALSE);
820 }
821 
822 
parse_action_verbose(char * s)823 int parse_action_verbose(char *s)
824 {
825 	return parse_action(s, ACTION_LOG_VERBOSE);
826 }
827 
828 
parse_action_nonverbose(char * s)829 int parse_action_nonverbose(char *s)
830 {
831 	return parse_action(s, ACTION_LOG_NONE);
832 }
833 
834 
read_action_file(char * filename,int verbose)835 int read_action_file(char *filename, int verbose)
836 {
837 	switch(verbose) {
838 	case ACTION_LOG_TRUE:
839 		return read_file(filename, "action", parse_action_true);
840 	case ACTION_LOG_FALSE:
841 		return read_file(filename, "action", parse_action_false);
842 	case ACTION_LOG_VERBOSE:
843 		return read_file(filename, "action", parse_action_verbose);
844 	default:
845 		return read_file(filename, "action", parse_action_nonverbose);
846 	}
847 }
848 
849 
850 /*
851  * helper to evaluate whether action/test acts on this file type
852  */
file_type_match(int st_mode,int type)853 static int file_type_match(int st_mode, int type)
854 {
855 	switch(type) {
856 	case ACTION_DIR:
857 		return S_ISDIR(st_mode);
858 	case ACTION_REG:
859 		return S_ISREG(st_mode);
860 	case ACTION_ALL:
861 		return S_ISREG(st_mode) || S_ISDIR(st_mode) ||
862 			S_ISCHR(st_mode) || S_ISBLK(st_mode) ||
863 			S_ISFIFO(st_mode) || S_ISSOCK(st_mode);
864 	case ACTION_LNK:
865 		return S_ISLNK(st_mode);
866 	case ACTION_ALL_LNK:
867 	default:
868 		return 1;
869 	}
870 }
871 
872 
873 /*
874  * General action evaluation code
875  */
actions()876 int actions()
877 {
878 	return other_count;
879 }
880 
881 
eval_actions(struct dir_info * root,struct dir_ent * dir_ent)882 void eval_actions(struct dir_info *root, struct dir_ent *dir_ent)
883 {
884 	int i, match;
885 	struct action_data action_data;
886 	int st_mode = dir_ent->inode->buf.st_mode;
887 
888 	action_data.name = dir_ent->name;
889 	action_data.pathname = strdup(pathname(dir_ent));
890 	action_data.subpath = strdup(subpathname(dir_ent));
891 	action_data.buf = &dir_ent->inode->buf;
892 	action_data.depth = dir_ent->our_dir->depth;
893 	action_data.dir_ent = dir_ent;
894 	action_data.root = root;
895 
896 	for (i = 0; i < other_count; i++) {
897 		struct action *action = &other_spec[i];
898 
899 		if (!file_type_match(st_mode, action->action->file_types))
900 			/* action does not operate on this file type */
901 			continue;
902 
903 		match = eval_expr_top(action, &action_data);
904 
905 		if (match)
906 			action->action->run_action(action, dir_ent);
907 	}
908 
909 	free(action_data.pathname);
910 	free(action_data.subpath);
911 }
912 
913 
914 /*
915  * Fragment specific action code
916  */
eval_frag_actions(struct dir_info * root,struct dir_ent * dir_ent)917 void *eval_frag_actions(struct dir_info *root, struct dir_ent *dir_ent)
918 {
919 	int i, match;
920 	struct action_data action_data;
921 
922 	action_data.name = dir_ent->name;
923 	action_data.pathname = strdup(pathname(dir_ent));
924 	action_data.subpath = strdup(subpathname(dir_ent));
925 	action_data.buf = &dir_ent->inode->buf;
926 	action_data.depth = dir_ent->our_dir->depth;
927 	action_data.dir_ent = dir_ent;
928 	action_data.root = root;
929 
930 	for (i = 0; i < fragment_count; i++) {
931 		match = eval_expr_top(&fragment_spec[i], &action_data);
932 		if (match) {
933 			free(action_data.pathname);
934 			free(action_data.subpath);
935 			return &fragment_spec[i].data;
936 		}
937 	}
938 
939 	free(action_data.pathname);
940 	free(action_data.subpath);
941 	return &def_fragment;
942 }
943 
944 
get_frag_action(void * fragment)945 void *get_frag_action(void *fragment)
946 {
947 	struct action *spec_list_end = &fragment_spec[fragment_count];
948 	struct action *action;
949 
950 	if (fragment == NULL)
951 		return &def_fragment;
952 
953 	if (fragment_count == 0)
954 		return NULL;
955 
956 	if (fragment == &def_fragment)
957 		action = &fragment_spec[0] - 1;
958 	else
959 		action = fragment - offsetof(struct action, data);
960 
961 	if (++action == spec_list_end)
962 		return NULL;
963 
964 	return &action->data;
965 }
966 
967 
968 /*
969  * Exclude specific action code
970  */
exclude_actions()971 int exclude_actions()
972 {
973 	return exclude_count;
974 }
975 
976 
eval_exclude_actions(char * name,char * pathname,char * subpath,struct stat * buf,int depth,struct dir_ent * dir_ent)977 int eval_exclude_actions(char *name, char *pathname, char *subpath,
978 	struct stat *buf, int depth, struct dir_ent *dir_ent)
979 {
980 	int i, match = 0;
981 	struct action_data action_data;
982 
983 	action_data.name = name;
984 	action_data.pathname = pathname;
985 	action_data.subpath = subpath;
986 	action_data.buf = buf;
987 	action_data.depth = depth;
988 	action_data.dir_ent = dir_ent;
989 
990 	for (i = 0; i < exclude_count && !match; i++)
991 		match = eval_expr_top(&exclude_spec[i], &action_data);
992 
993 	return match;
994 }
995 
996 
997 /*
998  * Fragment specific action code
999  */
frag_action(struct action * action,struct dir_ent * dir_ent)1000 static void frag_action(struct action *action, struct dir_ent *dir_ent)
1001 {
1002 	struct inode_info *inode = dir_ent->inode;
1003 
1004 	inode->no_fragments = 0;
1005 }
1006 
no_frag_action(struct action * action,struct dir_ent * dir_ent)1007 static void no_frag_action(struct action *action, struct dir_ent *dir_ent)
1008 {
1009 	struct inode_info *inode = dir_ent->inode;
1010 
1011 	inode->no_fragments = 1;
1012 }
1013 
always_frag_action(struct action * action,struct dir_ent * dir_ent)1014 static void always_frag_action(struct action *action, struct dir_ent *dir_ent)
1015 {
1016 	struct inode_info *inode = dir_ent->inode;
1017 
1018 	inode->always_use_fragments = 1;
1019 }
1020 
no_always_frag_action(struct action * action,struct dir_ent * dir_ent)1021 static void no_always_frag_action(struct action *action, struct dir_ent *dir_ent)
1022 {
1023 	struct inode_info *inode = dir_ent->inode;
1024 
1025 	inode->always_use_fragments = 0;
1026 }
1027 
1028 
1029 /*
1030  * Compression specific action code
1031  */
comp_action(struct action * action,struct dir_ent * dir_ent)1032 static void comp_action(struct action *action, struct dir_ent *dir_ent)
1033 {
1034 	struct inode_info *inode = dir_ent->inode;
1035 
1036 	inode->noD = inode->noF = 0;
1037 }
1038 
uncomp_action(struct action * action,struct dir_ent * dir_ent)1039 static void uncomp_action(struct action *action, struct dir_ent *dir_ent)
1040 {
1041 	struct inode_info *inode = dir_ent->inode;
1042 
1043 	inode->noD = inode->noF = 1;
1044 }
1045 
1046 
1047 /*
1048  * Uid/gid specific action code
1049  */
parse_uid(char * arg)1050 static long long parse_uid(char *arg) {
1051 	char *b;
1052 	long long uid = strtoll(arg, &b, 10);
1053 
1054 	if (*b == '\0') {
1055 		if (uid < 0 || uid >= (1LL << 32)) {
1056 			SYNTAX_ERROR("Uid out of range\n");
1057 			return -1;
1058 		}
1059 	} else {
1060 		struct passwd *passwd = getpwnam(arg);
1061 
1062 		if (passwd)
1063 			uid = passwd->pw_uid;
1064 		else {
1065 			SYNTAX_ERROR("Invalid uid or unknown user\n");
1066 			return -1;
1067 		}
1068 	}
1069 
1070 	return uid;
1071 }
1072 
1073 
parse_gid(char * arg)1074 static long long parse_gid(char *arg) {
1075 	char *b;
1076 	long long gid = strtoll(arg, &b, 10);
1077 
1078 	if (*b == '\0') {
1079 		if (gid < 0 || gid >= (1LL << 32)) {
1080 			SYNTAX_ERROR("Gid out of range\n");
1081 			return -1;
1082 		}
1083 	} else {
1084 		struct group *group = getgrnam(arg);
1085 
1086 		if (group)
1087 			gid = group->gr_gid;
1088 		else {
1089 			SYNTAX_ERROR("Invalid gid or unknown group\n");
1090 			return -1;
1091 		}
1092 	}
1093 
1094 	return gid;
1095 }
1096 
1097 
parse_uid_args(struct action_entry * action,int args,char ** argv,void ** data)1098 static int parse_uid_args(struct action_entry *action, int args, char **argv,
1099 								void **data)
1100 {
1101 	long long uid;
1102 	struct uid_info *uid_info;
1103 
1104 	uid = parse_uid(argv[0]);
1105 	if (uid == -1)
1106 		return 0;
1107 
1108 	uid_info = malloc(sizeof(struct uid_info));
1109 	if (uid_info == NULL)
1110 		MEM_ERROR();
1111 
1112 	uid_info->uid = uid;
1113 	*data = uid_info;
1114 
1115 	return 1;
1116 }
1117 
1118 
parse_gid_args(struct action_entry * action,int args,char ** argv,void ** data)1119 static int parse_gid_args(struct action_entry *action, int args, char **argv,
1120 								void **data)
1121 {
1122 	long long gid;
1123 	struct gid_info *gid_info;
1124 
1125 	gid = parse_gid(argv[0]);
1126 	if (gid == -1)
1127 		return 0;
1128 
1129 	gid_info = malloc(sizeof(struct gid_info));
1130 	if (gid_info == NULL)
1131 		MEM_ERROR();
1132 
1133 	gid_info->gid = gid;
1134 	*data = gid_info;
1135 
1136 	return 1;
1137 }
1138 
1139 
parse_guid_args(struct action_entry * action,int args,char ** argv,void ** data)1140 static int parse_guid_args(struct action_entry *action, int args, char **argv,
1141 								void **data)
1142 {
1143 	long long uid, gid;
1144 	struct guid_info *guid_info;
1145 
1146 	uid = parse_uid(argv[0]);
1147 	if (uid == -1)
1148 		return 0;
1149 
1150 	gid = parse_gid(argv[1]);
1151 	if (gid == -1)
1152 		return 0;
1153 
1154 	guid_info = malloc(sizeof(struct guid_info));
1155 	if (guid_info == NULL)
1156 		MEM_ERROR();
1157 
1158 	guid_info->uid = uid;
1159 	guid_info->gid = gid;
1160 	*data = guid_info;
1161 
1162 	return 1;
1163 }
1164 
1165 
uid_action(struct action * action,struct dir_ent * dir_ent)1166 static void uid_action(struct action *action, struct dir_ent *dir_ent)
1167 {
1168 	struct inode_info *inode = dir_ent->inode;
1169 	struct uid_info *uid_info = action->data;
1170 
1171 	inode->buf.st_uid = uid_info->uid;
1172 }
1173 
gid_action(struct action * action,struct dir_ent * dir_ent)1174 static void gid_action(struct action *action, struct dir_ent *dir_ent)
1175 {
1176 	struct inode_info *inode = dir_ent->inode;
1177 	struct gid_info *gid_info = action->data;
1178 
1179 	inode->buf.st_gid = gid_info->gid;
1180 }
1181 
guid_action(struct action * action,struct dir_ent * dir_ent)1182 static void guid_action(struct action *action, struct dir_ent *dir_ent)
1183 {
1184 	struct inode_info *inode = dir_ent->inode;
1185 	struct guid_info *guid_info = action->data;
1186 
1187 	inode->buf.st_uid = guid_info->uid;
1188 	inode->buf.st_gid = guid_info->gid;
1189 
1190 }
1191 
1192 
1193 /*
1194  * Mode specific action code
1195  */
parse_octal_mode_args(int args,char ** argv,void ** data)1196 static int parse_octal_mode_args(int args, char **argv,
1197 			void **data)
1198 {
1199 	int n, bytes;
1200 	unsigned int mode;
1201 	struct mode_data *mode_data;
1202 
1203 	/* octal mode number? */
1204 	n = sscanf(argv[0], "%o%n", &mode, &bytes);
1205 	if (n == 0)
1206 		return -1; /* not an octal number arg */
1207 
1208 
1209 	/* check there's no trailing junk */
1210 	if (argv[0][bytes] != '\0') {
1211 		SYNTAX_ERROR("Unexpected trailing bytes after octal "
1212 			"mode number\n");
1213 		return 0; /* bad octal number arg */
1214 	}
1215 
1216 	/* check there's only one argument */
1217 	if (args > 1) {
1218 		SYNTAX_ERROR("Octal mode number is first argument, "
1219 			"expected one argument, got %d\n", args);
1220 		return 0; /* bad octal number arg */
1221 	}
1222 
1223 	/*  check mode is within range */
1224 	if (mode > 07777) {
1225 		SYNTAX_ERROR("Octal mode %o is out of range\n", mode);
1226 		return 0; /* bad octal number arg */
1227 	}
1228 
1229 	mode_data = malloc(sizeof(struct mode_data));
1230 	if (mode_data == NULL)
1231 		MEM_ERROR();
1232 
1233 	mode_data->operation = ACTION_MODE_OCT;
1234 	mode_data->mode = mode;
1235 	mode_data->next = NULL;
1236 	*data = mode_data;
1237 
1238 	return 1;
1239 }
1240 
1241 
1242 /*
1243  * Parse symbolic mode of format [ugoa]*[[+-=]PERMS]+
1244  * PERMS = [rwxXst]+ or [ugo]
1245  */
parse_sym_mode_arg(char * arg,struct mode_data ** head,struct mode_data ** cur)1246 static int parse_sym_mode_arg(char *arg, struct mode_data **head,
1247 	struct mode_data **cur)
1248 {
1249 	struct mode_data *mode_data;
1250 	int mode;
1251 	int mask = 0;
1252 	int op;
1253 	char X;
1254 
1255 	if (arg[0] != 'u' && arg[0] != 'g' && arg[0] != 'o' && arg[0] != 'a') {
1256 		/* no ownership specifiers, default to a */
1257 		mask = 0777;
1258 		goto parse_operation;
1259 	}
1260 
1261 	/* parse ownership specifiers */
1262 	while(1) {
1263 		switch(*arg) {
1264 		case 'u':
1265 			mask |= 04700;
1266 			break;
1267 		case 'g':
1268 			mask |= 02070;
1269 			break;
1270 		case 'o':
1271 			mask |= 01007;
1272 			break;
1273 		case 'a':
1274 			mask = 07777;
1275 			break;
1276 		default:
1277 			goto parse_operation;
1278 		}
1279 		arg ++;
1280 	}
1281 
1282 parse_operation:
1283 	/* trap a symbolic mode with just an ownership specification */
1284 	if(*arg == '\0') {
1285 		SYNTAX_ERROR("Expected one of '+', '-' or '=', got EOF\n");
1286 		goto failed;
1287 	}
1288 
1289 	while(*arg != '\0') {
1290 		mode = 0;
1291 		X = 0;
1292 
1293 		switch(*arg) {
1294 		case '+':
1295 			op = ACTION_MODE_ADD;
1296 			break;
1297 		case '-':
1298 			op = ACTION_MODE_REM;
1299 			break;
1300 		case '=':
1301 			op = ACTION_MODE_SET;
1302 			break;
1303 		default:
1304 			SYNTAX_ERROR("Expected one of '+', '-' or '=', got "
1305 				"'%c'\n", *arg);
1306 			goto failed;
1307 		}
1308 
1309 		arg ++;
1310 
1311 		/* Parse PERMS */
1312 		if (*arg == 'u' || *arg == 'g' || *arg == 'o') {
1313 	 		/* PERMS = [ugo] */
1314 			mode = - *arg;
1315 			arg ++;
1316 		} else {
1317 	 		/* PERMS = [rwxXst]* */
1318 			while(1) {
1319 				switch(*arg) {
1320 				case 'r':
1321 					mode |= 0444;
1322 					break;
1323 				case 'w':
1324 					mode |= 0222;
1325 					break;
1326 				case 'x':
1327 					mode |= 0111;
1328 					break;
1329 				case 's':
1330 					mode |= 06000;
1331 					break;
1332 				case 't':
1333 					mode |= 01000;
1334 					break;
1335 				case 'X':
1336 					X = 1;
1337 					break;
1338 				case '+':
1339 				case '-':
1340 				case '=':
1341 				case '\0':
1342 					mode &= mask;
1343 					goto perms_parsed;
1344 				default:
1345 					SYNTAX_ERROR("Unrecognised permission "
1346 								"'%c'\n", *arg);
1347 					goto failed;
1348 				}
1349 
1350 				arg ++;
1351 			}
1352 		}
1353 
1354 perms_parsed:
1355 		mode_data = malloc(sizeof(*mode_data));
1356 		if (mode_data == NULL)
1357 			MEM_ERROR();
1358 
1359 		mode_data->operation = op;
1360 		mode_data->mode = mode;
1361 		mode_data->mask = mask;
1362 		mode_data->X = X;
1363 		mode_data->next = NULL;
1364 
1365 		if (*cur) {
1366 			(*cur)->next = mode_data;
1367 			*cur = mode_data;
1368 		} else
1369 			*head = *cur = mode_data;
1370 	}
1371 
1372 	return 1;
1373 
1374 failed:
1375 	return 0;
1376 }
1377 
1378 
parse_sym_mode_args(struct action_entry * action,int args,char ** argv,void ** data)1379 static int parse_sym_mode_args(struct action_entry *action, int args,
1380 					char **argv, void **data)
1381 {
1382 	int i, res = 1;
1383 	struct mode_data *head = NULL, *cur = NULL;
1384 
1385 	for (i = 0; i < args && res; i++)
1386 		res = parse_sym_mode_arg(argv[i], &head, &cur);
1387 
1388 	*data = head;
1389 
1390 	return res;
1391 }
1392 
1393 
parse_mode_args(struct action_entry * action,int args,char ** argv,void ** data)1394 static int parse_mode_args(struct action_entry *action, int args,
1395 					char **argv, void **data)
1396 {
1397 	int res;
1398 
1399 	if (args == 0) {
1400 		SYNTAX_ERROR("Mode action expects one or more arguments\n");
1401 		return 0;
1402 	}
1403 
1404 	res = parse_octal_mode_args(args, argv, data);
1405 	if(res >= 0)
1406 		/* Got an octal mode argument */
1407 		return res;
1408 	else  /* not an octal mode argument */
1409 		return parse_sym_mode_args(action, args, argv, data);
1410 }
1411 
1412 
mode_execute(struct mode_data * mode_data,int st_mode)1413 static int mode_execute(struct mode_data *mode_data, int st_mode)
1414 {
1415 	int mode = 0;
1416 
1417 	for (;mode_data; mode_data = mode_data->next) {
1418 		if (mode_data->mode < 0) {
1419 			/* 'u', 'g' or 'o' */
1420 			switch(-mode_data->mode) {
1421 			case 'u':
1422 				mode = (st_mode >> 6) & 07;
1423 				break;
1424 			case 'g':
1425 				mode = (st_mode >> 3) & 07;
1426 				break;
1427 			case 'o':
1428 				mode = st_mode & 07;
1429 				break;
1430 			}
1431 			mode = ((mode << 6) | (mode << 3) | mode) &
1432 				mode_data->mask;
1433 		} else if (mode_data->X &&
1434 				((st_mode & S_IFMT) == S_IFDIR ||
1435 				(st_mode & 0111)))
1436 			/* X permission, only takes effect if inode is a
1437 			 * directory or x is set for some owner */
1438 			mode = mode_data->mode | (0111 & mode_data->mask);
1439 		else
1440 			mode = mode_data->mode;
1441 
1442 		switch(mode_data->operation) {
1443 		case ACTION_MODE_OCT:
1444 			st_mode = (st_mode & S_IFMT) | mode;
1445 			break;
1446 		case ACTION_MODE_SET:
1447 			st_mode = (st_mode & ~mode_data->mask) | mode;
1448 			break;
1449 		case ACTION_MODE_ADD:
1450 			st_mode |= mode;
1451 			break;
1452 		case ACTION_MODE_REM:
1453 			st_mode &= ~mode;
1454 		}
1455 	}
1456 
1457 	return st_mode;
1458 }
1459 
1460 
mode_action(struct action * action,struct dir_ent * dir_ent)1461 static void mode_action(struct action *action, struct dir_ent *dir_ent)
1462 {
1463 	dir_ent->inode->buf.st_mode = mode_execute(action->data,
1464 					dir_ent->inode->buf.st_mode);
1465 }
1466 
1467 
1468 /*
1469  *  Empty specific action code
1470  */
empty_actions()1471 int empty_actions()
1472 {
1473 	return empty_count;
1474 }
1475 
1476 
parse_empty_args(struct action_entry * action,int args,char ** argv,void ** data)1477 static int parse_empty_args(struct action_entry *action, int args,
1478 					char **argv, void **data)
1479 {
1480 	struct empty_data *empty_data;
1481 	int val;
1482 
1483 	if (args >= 2) {
1484 		SYNTAX_ERROR("Empty action expects zero or one argument\n");
1485 		return 0;
1486 	}
1487 
1488 	if (args == 0 || strcmp(argv[0], "all") == 0)
1489 		val = EMPTY_ALL;
1490 	else if (strcmp(argv[0], "source") == 0)
1491 		val = EMPTY_SOURCE;
1492 	else if (strcmp(argv[0], "excluded") == 0)
1493 		val = EMPTY_EXCLUDED;
1494 	else {
1495 		SYNTAX_ERROR("Empty action expects zero arguments, or one"
1496 			"argument containing \"all\", \"source\", or \"excluded\""
1497 			"\n");
1498 		return 0;
1499 	}
1500 
1501 	empty_data = malloc(sizeof(*empty_data));
1502 	if (empty_data == NULL)
1503 		MEM_ERROR();
1504 
1505 	empty_data->val = val;
1506 	*data = empty_data;
1507 
1508 	return 1;
1509 }
1510 
1511 
eval_empty_actions(struct dir_info * root,struct dir_ent * dir_ent)1512 int eval_empty_actions(struct dir_info *root, struct dir_ent *dir_ent)
1513 {
1514 	int i, match = 0;
1515 	struct action_data action_data;
1516 	struct empty_data *data;
1517 	struct dir_info *dir = dir_ent->dir;
1518 
1519 	/*
1520 	 * Empty action only works on empty directories
1521 	 */
1522 	if (dir->count != 0)
1523 		return 0;
1524 
1525 	action_data.name = dir_ent->name;
1526 	action_data.pathname = strdup(pathname(dir_ent));
1527 	action_data.subpath = strdup(subpathname(dir_ent));
1528 	action_data.buf = &dir_ent->inode->buf;
1529 	action_data.depth = dir_ent->our_dir->depth;
1530 	action_data.dir_ent = dir_ent;
1531 	action_data.root = root;
1532 
1533 	for (i = 0; i < empty_count && !match; i++) {
1534 		data = empty_spec[i].data;
1535 
1536 		/*
1537 		 * determine the cause of the empty directory and evaluate
1538 		 * the empty action specified.  Three empty actions:
1539 		 * - EMPTY_SOURCE: empty action triggers only if the directory
1540 		 *	was originally empty, i.e directories that are empty
1541 		 *	only due to excluding are ignored.
1542 		 * - EMPTY_EXCLUDED: empty action triggers only if the directory
1543 		 *	is empty because of excluding, i.e. directories that
1544 		 *	were originally empty are ignored.
1545 		 * - EMPTY_ALL (the default): empty action triggers if the
1546 		 *	directory is empty, irrespective of the reason, i.e.
1547 		 *	the directory could have been originally empty or could
1548 		 *	be empty due to excluding.
1549 		 */
1550 		if ((data->val == EMPTY_EXCLUDED && !dir->excluded) ||
1551 				(data->val == EMPTY_SOURCE && dir->excluded))
1552 			continue;
1553 
1554 		match = eval_expr_top(&empty_spec[i], &action_data);
1555 	}
1556 
1557 	free(action_data.pathname);
1558 	free(action_data.subpath);
1559 
1560 	return match;
1561 }
1562 
1563 
1564 /*
1565  *  Move specific action code
1566  */
1567 static struct move_ent *move_list = NULL;
1568 
1569 
move_actions()1570 int move_actions()
1571 {
1572 	return move_count;
1573 }
1574 
1575 
move_pathname(struct move_ent * move)1576 static char *move_pathname(struct move_ent *move)
1577 {
1578 	struct dir_info *dest;
1579 	char *name, *pathname;
1580 	int res;
1581 
1582 	dest = (move->ops & ACTION_MOVE_MOVE) ?
1583 		move->dest : move->dir_ent->our_dir;
1584 	name = (move->ops & ACTION_MOVE_RENAME) ?
1585 		move->name : move->dir_ent->name;
1586 
1587 	if(dest->subpath[0] != '\0')
1588 		res = asprintf(&pathname, "%s/%s", dest->subpath, name);
1589 	else
1590 		res = asprintf(&pathname, "/%s", name);
1591 
1592 	if(res == -1)
1593 		BAD_ERROR("asprintf failed in move_pathname\n");
1594 
1595 	return pathname;
1596 }
1597 
1598 
get_comp(char ** pathname)1599 static char *get_comp(char **pathname)
1600 {
1601 	char *path = *pathname, *start;
1602 
1603 	while(*path == '/')
1604 		path ++;
1605 
1606 	if(*path == '\0')
1607 		return NULL;
1608 
1609 	start = path;
1610 	while(*path != '/' && *path != '\0')
1611 		path ++;
1612 
1613 	*pathname = path;
1614 	return strndup(start, path - start);
1615 }
1616 
1617 
lookup_comp(char * comp,struct dir_info * dest)1618 static struct dir_ent *lookup_comp(char *comp, struct dir_info *dest)
1619 {
1620 	struct dir_ent *dir_ent;
1621 
1622 	for(dir_ent = dest->list; dir_ent; dir_ent = dir_ent->next)
1623 		if(strcmp(comp, dir_ent->name) == 0)
1624 			break;
1625 
1626 	return dir_ent;
1627 }
1628 
1629 
eval_move(struct action_data * action_data,struct move_ent * move,struct dir_info * root,struct dir_ent * dir_ent,char * pathname)1630 void eval_move(struct action_data *action_data, struct move_ent *move,
1631 		struct dir_info *root, struct dir_ent *dir_ent, char *pathname)
1632 {
1633 	struct dir_info *dest, *source = dir_ent->our_dir;
1634 	struct dir_ent *comp_ent;
1635 	char *comp, *path = pathname;
1636 
1637 	/*
1638 	 * Walk pathname to get the destination directory
1639 	 *
1640 	 * Like the mv command, if the last component exists and it
1641 	 * is a directory, then move the file into that directory,
1642 	 * otherwise, move the file into parent directory of the last
1643 	 * component and rename to the last component.
1644 	 */
1645 	if (pathname[0] == '/')
1646 		/* absolute pathname, walk from root directory */
1647 		dest = root;
1648 	else
1649 		/* relative pathname, walk from current directory */
1650 		dest = source;
1651 
1652 	for(comp = get_comp(&pathname); comp; free(comp),
1653 						comp = get_comp(&pathname)) {
1654 
1655 		if (strcmp(comp, ".") == 0)
1656 			continue;
1657 
1658 		if (strcmp(comp, "..") == 0) {
1659 			/* if we're in the root directory then ignore */
1660 			if(dest->depth > 1)
1661 				dest = dest->dir_ent->our_dir;
1662 			continue;
1663 		}
1664 
1665 		/*
1666 		 * Look up comp in current directory, if it exists and it is a
1667 		 * directory continue walking the pathname, otherwise exit,
1668 		 * we've walked as far as we can go, normally this is because
1669 		 * we've arrived at the leaf component which we are going to
1670 		 * rename source to
1671 		 */
1672 		comp_ent = lookup_comp(comp, dest);
1673 		if (comp_ent == NULL || (comp_ent->inode->buf.st_mode & S_IFMT)
1674 							!= S_IFDIR)
1675 			break;
1676 
1677 		dest = comp_ent->dir;
1678 	}
1679 
1680 	if(comp) {
1681 		/* Leaf component? If so we're renaming to this  */
1682 		char *remainder = get_comp(&pathname);
1683 		free(remainder);
1684 
1685 		if(remainder) {
1686 			/*
1687 			 * trying to move source to a subdirectory of
1688 			 * comp, but comp either doesn't exist, or it isn't
1689 			 * a directory, which is impossible
1690 			 */
1691 			if (comp_ent == NULL)
1692 				ERROR("Move action: cannot move %s to %s, no "
1693 					"such directory %s\n",
1694 					action_data->subpath, path, comp);
1695 			else
1696 				ERROR("Move action: cannot move %s to %s, %s "
1697 					"is not a directory\n",
1698 					action_data->subpath, path, comp);
1699 			free(comp);
1700 			return;
1701 		}
1702 
1703 		/*
1704 		 * Multiple move actions triggering on one file can be merged
1705 		 * if one is a RENAME and the other is a MOVE.  Multiple RENAMEs
1706 		 * can only merge if they're doing the same thing
1707 	 	 */
1708 		if(move->ops & ACTION_MOVE_RENAME) {
1709 			if(strcmp(comp, move->name) != 0) {
1710 				char *conf_path = move_pathname(move);
1711 				ERROR("Move action: Cannot move %s to %s, "
1712 					"conflicting move, already moving "
1713 					"to %s via another move action!\n",
1714 					action_data->subpath, path, conf_path);
1715 				free(conf_path);
1716 				free(comp);
1717 				return;
1718 			}
1719 			free(comp);
1720 		} else {
1721 			move->name = comp;
1722 			move->ops |= ACTION_MOVE_RENAME;
1723 		}
1724 	}
1725 
1726 	if(dest != source) {
1727 		/*
1728 		 * Multiple move actions triggering on one file can be merged
1729 		 * if one is a RENAME and the other is a MOVE.  Multiple MOVEs
1730 		 * can only merge if they're doing the same thing
1731 	 	 */
1732 		if(move->ops & ACTION_MOVE_MOVE) {
1733 			if(dest != move->dest) {
1734 				char *conf_path = move_pathname(move);
1735 				ERROR("Move action: Cannot move %s to %s, "
1736 					"conflicting move, already moving "
1737 					"to %s via another move action!\n",
1738 					action_data->subpath, path, conf_path);
1739 				free(conf_path);
1740 				return;
1741 			}
1742 		} else {
1743 			move->dest = dest;
1744 			move->ops |= ACTION_MOVE_MOVE;
1745 		}
1746 	}
1747 }
1748 
1749 
subdirectory(struct dir_info * source,struct dir_info * dest)1750 static int subdirectory(struct dir_info *source, struct dir_info *dest)
1751 {
1752 	if(source == NULL)
1753 		return 0;
1754 
1755 	return strlen(source->subpath) <= strlen(dest->subpath) &&
1756 		(dest->subpath[strlen(source->subpath)] == '/' ||
1757 		dest->subpath[strlen(source->subpath)] == '\0') &&
1758 		strncmp(source->subpath, dest->subpath,
1759 		strlen(source->subpath)) == 0;
1760 }
1761 
1762 
eval_move_actions(struct dir_info * root,struct dir_ent * dir_ent)1763 void eval_move_actions(struct dir_info *root, struct dir_ent *dir_ent)
1764 {
1765 	int i;
1766 	struct action_data action_data;
1767 	struct move_ent *move = NULL;
1768 
1769 	action_data.name = dir_ent->name;
1770 	action_data.pathname = strdup(pathname(dir_ent));
1771 	action_data.subpath = strdup(subpathname(dir_ent));
1772 	action_data.buf = &dir_ent->inode->buf;
1773 	action_data.depth = dir_ent->our_dir->depth;
1774 	action_data.dir_ent = dir_ent;
1775 	action_data.root = root;
1776 
1777 	/*
1778 	 * Evaluate each move action against the current file.  For any
1779 	 * move actions that match don't actually perform the move now, but,
1780 	 * store it, and execute all the stored move actions together once the
1781 	 * directory scan is complete.  This is done to ensure each separate
1782 	 * move action does not nondeterministically interfere with other move
1783 	 * actions.  Each move action is considered to act independently, and
1784 	 * each move action sees the directory tree in the same state.
1785 	 */
1786 	for (i = 0; i < move_count; i++) {
1787 		struct action *action = &move_spec[i];
1788 		int match = eval_expr_top(action, &action_data);
1789 
1790 		if(match) {
1791 			if(move == NULL) {
1792 				move = malloc(sizeof(*move));
1793 				if(move == NULL)
1794 					MEM_ERROR();
1795 
1796 				move->ops = 0;
1797 				move->dir_ent = dir_ent;
1798 			}
1799 			eval_move(&action_data, move, root, dir_ent,
1800 				action->argv[0]);
1801 		}
1802 	}
1803 
1804 	if(move) {
1805 		struct dir_ent *comp_ent;
1806 		struct dir_info *dest;
1807 		char *name;
1808 
1809 		/*
1810 		 * Move contains the result of all triggered move actions.
1811 		 * Check the destination doesn't already exist
1812 		 */
1813 		if(move->ops == 0) {
1814 			free(move);
1815 			goto finish;
1816 		}
1817 
1818 		dest = (move->ops & ACTION_MOVE_MOVE) ?
1819 			move->dest : dir_ent->our_dir;
1820 		name = (move->ops & ACTION_MOVE_RENAME) ?
1821 			move->name : dir_ent->name;
1822 		comp_ent = lookup_comp(name, dest);
1823 		if(comp_ent) {
1824 			char *conf_path = move_pathname(move);
1825 			ERROR("Move action: Cannot move %s to %s, "
1826 				"destination already exists\n",
1827 				action_data.subpath, conf_path);
1828 			free(conf_path);
1829 			free(move);
1830 			goto finish;
1831 		}
1832 
1833 		/*
1834 		 * If we're moving a directory, check we're not moving it to a
1835 		 * subdirectory of itself
1836 		 */
1837 		if(subdirectory(dir_ent->dir, dest)) {
1838 			char *conf_path = move_pathname(move);
1839 			ERROR("Move action: Cannot move %s to %s, this is a "
1840 				"subdirectory of itself\n",
1841 				action_data.subpath, conf_path);
1842 			free(conf_path);
1843 			free(move);
1844 			goto finish;
1845 		}
1846 		move->next = move_list;
1847 		move_list = move;
1848 	}
1849 
1850 finish:
1851 	free(action_data.pathname);
1852 	free(action_data.subpath);
1853 }
1854 
1855 
move_dir(struct dir_ent * dir_ent)1856 static void move_dir(struct dir_ent *dir_ent)
1857 {
1858 	struct dir_info *dir = dir_ent->dir;
1859 	struct dir_ent *comp_ent;
1860 
1861 	/* update our directory's subpath name */
1862 	free(dir->subpath);
1863 	dir->subpath = strdup(subpathname(dir_ent));
1864 
1865 	/* recursively update the subpaths of any sub-directories */
1866 	for(comp_ent = dir->list; comp_ent; comp_ent = comp_ent->next)
1867 		if(comp_ent->dir)
1868 			move_dir(comp_ent);
1869 }
1870 
1871 
move_file(struct move_ent * move_ent)1872 static void move_file(struct move_ent *move_ent)
1873 {
1874 	struct dir_ent *dir_ent = move_ent->dir_ent;
1875 
1876 	if(move_ent->ops & ACTION_MOVE_MOVE) {
1877 		struct dir_ent *comp_ent, *prev = NULL;
1878 		struct dir_info *source = dir_ent->our_dir,
1879 							*dest = move_ent->dest;
1880 		char *filename = pathname(dir_ent);
1881 
1882 		/*
1883 		 * If we're moving a directory, check we're not moving it to a
1884 		 * subdirectory of itself
1885 		 */
1886 		if(subdirectory(dir_ent->dir, dest)) {
1887 			char *conf_path = move_pathname(move_ent);
1888 			ERROR("Move action: Cannot move %s to %s, this is a "
1889 				"subdirectory of itself\n",
1890 				subpathname(dir_ent), conf_path);
1891 			free(conf_path);
1892 			return;
1893 		}
1894 
1895 		/* Remove the file from source directory */
1896 		for(comp_ent = source->list; comp_ent != dir_ent;
1897 				prev = comp_ent, comp_ent = comp_ent->next);
1898 
1899 		if(prev)
1900 			prev->next = comp_ent->next;
1901 		else
1902 			source->list = comp_ent->next;
1903 
1904 		source->count --;
1905 		if((comp_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
1906 			source->directory_count --;
1907 
1908 		/* Add the file to dest directory */
1909 		comp_ent->next = dest->list;
1910 		dest->list = comp_ent;
1911 		comp_ent->our_dir = dest;
1912 
1913 		dest->count ++;
1914 		if((comp_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
1915 			dest->directory_count ++;
1916 
1917 		/*
1918 		 * We've moved the file, and so we can't now use the
1919 		 * parent directory's pathname to calculate the pathname
1920 		 */
1921 		if(dir_ent->nonstandard_pathname == NULL) {
1922 			dir_ent->nonstandard_pathname = strdup(filename);
1923 			if(dir_ent->source_name) {
1924 				free(dir_ent->source_name);
1925 				dir_ent->source_name = NULL;
1926 			}
1927 		}
1928 	}
1929 
1930 	if(move_ent->ops & ACTION_MOVE_RENAME) {
1931 		/*
1932 		 * If we're using name in conjunction with the parent
1933 		 * directory's pathname to calculate the pathname, we need
1934 		 * to use source_name to override.  Otherwise it's already being
1935 		 * over-ridden
1936 		 */
1937 		if(dir_ent->nonstandard_pathname == NULL &&
1938 						dir_ent->source_name == NULL)
1939 			dir_ent->source_name = dir_ent->name;
1940 		else
1941 			free(dir_ent->name);
1942 
1943 		dir_ent->name = move_ent->name;
1944 	}
1945 
1946 	if(dir_ent->dir)
1947 		/*
1948 		 * dir_ent is a directory, and we have to recursively fix-up
1949 		 * its subpath, and the subpaths of all of its sub-directories
1950 		 */
1951 		move_dir(dir_ent);
1952 }
1953 
1954 
do_move_actions()1955 void do_move_actions()
1956 {
1957 	while(move_list) {
1958 		struct move_ent *temp = move_list;
1959 		struct dir_info *dest = (move_list->ops & ACTION_MOVE_MOVE) ?
1960 			move_list->dest : move_list->dir_ent->our_dir;
1961 		char *name = (move_list->ops & ACTION_MOVE_RENAME) ?
1962 			move_list->name : move_list->dir_ent->name;
1963 		struct dir_ent *comp_ent = lookup_comp(name, dest);
1964 		if(comp_ent) {
1965 			char *conf_path = move_pathname(move_list);
1966 			ERROR("Move action: Cannot move %s to %s, "
1967 				"destination already exists\n",
1968 				subpathname(move_list->dir_ent), conf_path);
1969 			free(conf_path);
1970 		} else
1971 			move_file(move_list);
1972 
1973 		move_list = move_list->next;
1974 		free(temp);
1975 	}
1976 }
1977 
1978 
1979 /*
1980  * Prune specific action code
1981  */
prune_actions()1982 int prune_actions()
1983 {
1984 	return prune_count;
1985 }
1986 
1987 
eval_prune_actions(struct dir_info * root,struct dir_ent * dir_ent)1988 int eval_prune_actions(struct dir_info *root, struct dir_ent *dir_ent)
1989 {
1990 	int i, match = 0;
1991 	struct action_data action_data;
1992 
1993 	action_data.name = dir_ent->name;
1994 	action_data.pathname = strdup(pathname(dir_ent));
1995 	action_data.subpath = strdup(subpathname(dir_ent));
1996 	action_data.buf = &dir_ent->inode->buf;
1997 	action_data.depth = dir_ent->our_dir->depth;
1998 	action_data.dir_ent = dir_ent;
1999 	action_data.root = root;
2000 
2001 	for (i = 0; i < prune_count && !match; i++)
2002 		match = eval_expr_top(&prune_spec[i], &action_data);
2003 
2004 	free(action_data.pathname);
2005 	free(action_data.subpath);
2006 
2007 	return match;
2008 }
2009 
2010 
2011 /*
2012  * Noop specific action code
2013  */
noop_action(struct action * action,struct dir_ent * dir_ent)2014 static void noop_action(struct action *action, struct dir_ent *dir_ent)
2015 {
2016 }
2017 
2018 
2019 /*
2020  * General test evaluation code
2021  */
2022 
2023 /*
2024  * A number can be of the form [range]number[size]
2025  * [range] is either:
2026  *	'<' or '-', match on less than number
2027  *	'>' or '+', match on greater than number
2028  *	'' (nothing), match on exactly number
2029  * [size] is either:
2030  *	'' (nothing), number
2031  *	'k' or 'K', number * 2^10
2032  * 	'm' or 'M', number * 2^20
2033  *	'g' or 'G', number * 2^30
2034  */
parse_number(char * start,long long * size,int * range,char ** error)2035 static int parse_number(char *start, long long *size, int *range, char **error)
2036 {
2037 	char *end;
2038 	long long number;
2039 
2040 	if (*start == '>' || *start == '+') {
2041 		*range = NUM_GREATER;
2042 		start ++;
2043 	} else if (*start == '<' || *start == '-') {
2044 		*range = NUM_LESS;
2045 		start ++;
2046 	} else
2047 		*range = NUM_EQ;
2048 
2049 	errno = 0; /* To enable failure after call to be determined */
2050 	number = strtoll(start, &end, 10);
2051 
2052 	if((errno == ERANGE && (number == LLONG_MAX || number == LLONG_MIN))
2053 				|| (errno != 0 && number == 0)) {
2054 		/* long long underflow or overflow in conversion, or other
2055 		 * conversion error.
2056 		 * Note: we don't check for LLONG_MIN and LLONG_MAX only
2057 		 * because strtoll can validly return that if the
2058 		 * user used these values
2059 		 */
2060 		*error = "Long long underflow, overflow or other conversion "
2061 								"error";
2062 		return 0;
2063 	}
2064 
2065 	if (end == start) {
2066 		/* Couldn't read any number  */
2067 		*error = "Number expected";
2068 		return 0;
2069 	}
2070 
2071 	switch (end[0]) {
2072 	case 'g':
2073 	case 'G':
2074 		number *= 1024;
2075 	case 'm':
2076 	case 'M':
2077 		number *= 1024;
2078 	case 'k':
2079 	case 'K':
2080 		number *= 1024;
2081 
2082 		if (end[1] != '\0') {
2083 			*error = "Trailing junk after size specifier";
2084 			return 0;
2085 		}
2086 
2087 		break;
2088 	case '\0':
2089 		break;
2090 	default:
2091 		*error = "Trailing junk after number";
2092 		return 0;
2093 	}
2094 
2095 	*size = number;
2096 
2097 	return 1;
2098 }
2099 
2100 
parse_number_arg(struct test_entry * test,struct atom * atom)2101 static int parse_number_arg(struct test_entry *test, struct atom *atom)
2102 {
2103 	struct test_number_arg *number;
2104 	long long size;
2105 	int range;
2106 	char *error;
2107 	int res = parse_number(atom->argv[0], &size, &range, &error);
2108 
2109 	if (res == 0) {
2110 		TEST_SYNTAX_ERROR(test, 0, "%s\n", error);
2111 		return 0;
2112 	}
2113 
2114 	number = malloc(sizeof(*number));
2115 	if (number == NULL)
2116 		MEM_ERROR();
2117 
2118 	number->range = range;
2119 	number->size = size;
2120 
2121 	atom->data = number;
2122 
2123 	return 1;
2124 }
2125 
2126 
parse_range_args(struct test_entry * test,struct atom * atom)2127 static int parse_range_args(struct test_entry *test, struct atom *atom)
2128 {
2129 	struct test_range_args *range;
2130 	long long start, end;
2131 	int type;
2132 	int res;
2133 	char *error;
2134 
2135 	res = parse_number(atom->argv[0], &start, &type, &error);
2136 	if (res == 0) {
2137 		TEST_SYNTAX_ERROR(test, 0, "%s\n", error);
2138 		return 0;
2139 	}
2140 
2141 	if (type != NUM_EQ) {
2142 		TEST_SYNTAX_ERROR(test, 0, "Range specifier (<, >, -, +) not "
2143 			"expected\n");
2144 		return 0;
2145 	}
2146 
2147 	res = parse_number(atom->argv[1], &end, &type, &error);
2148 	if (res == 0) {
2149 		TEST_SYNTAX_ERROR(test, 1, "%s\n", error);
2150 		return 0;
2151 	}
2152 
2153 	if (type != NUM_EQ) {
2154 		TEST_SYNTAX_ERROR(test, 1, "Range specifier (<, >, -, +) not "
2155 			"expected\n");
2156 		return 0;
2157 	}
2158 
2159 	range = malloc(sizeof(*range));
2160 	if (range == NULL)
2161 		MEM_ERROR();
2162 
2163 	range->start = start;
2164 	range->end = end;
2165 
2166 	atom->data = range;
2167 
2168 	return 1;
2169 }
2170 
2171 
2172 /*
2173  * Generic test code macro
2174  */
2175 #define TEST_FN(NAME, MATCH, CODE) \
2176 static int NAME##_fn(struct atom *atom, struct action_data *action_data) \
2177 { \
2178 	/* test operates on MATCH file types only */ \
2179 	if (!file_type_match(action_data->buf->st_mode, MATCH)) \
2180 		return 0; \
2181  \
2182 	CODE \
2183 }
2184 
2185 /*
2186  * Generic test code macro testing VAR for size (eq, less than, greater than)
2187  */
2188 #define TEST_VAR_FN(NAME, MATCH, VAR) TEST_FN(NAME, MATCH, \
2189 	{ \
2190 	int match = 0; \
2191 	struct test_number_arg *number = atom->data; \
2192 	\
2193 	switch (number->range) { \
2194 	case NUM_EQ: \
2195 		match = VAR == number->size; \
2196 		break; \
2197 	case NUM_LESS: \
2198 		match = VAR < number->size; \
2199 		break; \
2200 	case NUM_GREATER: \
2201 		match = VAR > number->size; \
2202 		break; \
2203 	} \
2204 	\
2205 	return match; \
2206 	})
2207 
2208 
2209 /*
2210  * Generic test code macro testing VAR for range [x, y] (value between x and y
2211  * inclusive).
2212  */
2213 #define TEST_VAR_RANGE_FN(NAME, MATCH, VAR) TEST_FN(NAME##_range, MATCH, \
2214 	{ \
2215 	struct test_range_args *range = atom->data; \
2216 	\
2217 	return range->start <= VAR && VAR <= range->end; \
2218 	})
2219 
2220 
2221 /*
2222  * Name, Pathname and Subpathname test specific code
2223  */
2224 
2225 /*
2226  * Add a leading "/" if subpathname and pathname lacks it
2227  */
check_pathname(struct test_entry * test,struct atom * atom)2228 static int check_pathname(struct test_entry *test, struct atom *atom)
2229 {
2230 	int res;
2231 	char *name;
2232 
2233 	if(atom->argv[0][0] != '/') {
2234 		res = asprintf(&name, "/%s", atom->argv[0]);
2235 		if(res == -1)
2236 			BAD_ERROR("asprintf failed in check_pathname\n");
2237 
2238 		free(atom->argv[0]);
2239 		atom->argv[0] = name;
2240 	}
2241 
2242 	return 1;
2243 }
2244 
2245 
2246 TEST_FN(name, ACTION_ALL_LNK, \
2247 	return fnmatch(atom->argv[0], action_data->name,
2248 				FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;)
2249 
2250 TEST_FN(pathname, ACTION_ALL_LNK, \
2251 	return fnmatch(atom->argv[0], action_data->subpath,
2252 				FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;)
2253 
2254 
count_components(char * path)2255 static int count_components(char *path)
2256 {
2257 	int count;
2258 
2259 	for (count = 0; *path != '\0'; count ++) {
2260 		while (*path == '/')
2261 			path ++;
2262 
2263 		while (*path != '\0' && *path != '/')
2264 			path ++;
2265 	}
2266 
2267 	return count;
2268 }
2269 
2270 
get_start(char * s,int n)2271 static char *get_start(char *s, int n)
2272 {
2273 	int count;
2274 	char *path = s;
2275 
2276 	for (count = 0; *path != '\0' && count < n; count ++) {
2277 		while (*path == '/')
2278 			path ++;
2279 
2280 		while (*path != '\0' && *path != '/')
2281 			path ++;
2282 	}
2283 
2284 	if (count == n)
2285 		*path = '\0';
2286 
2287 	return s;
2288 }
2289 
2290 
subpathname_fn(struct atom * atom,struct action_data * action_data)2291 static int subpathname_fn(struct atom *atom, struct action_data *action_data)
2292 {
2293 	return fnmatch(atom->argv[0], get_start(strdupa(action_data->subpath),
2294 		count_components(atom->argv[0])),
2295 		FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
2296 }
2297 
2298 /*
2299  * Inode attribute test operations using generic
2300  * TEST_VAR_FN(test name, file scope, attribute name) macro.
2301  * This is for tests that do not need to be specially handled in any way.
2302  * They just take a variable and compare it against a number.
2303  */
2304 TEST_VAR_FN(filesize, ACTION_REG, action_data->buf->st_size)
2305 
2306 TEST_VAR_FN(dirsize, ACTION_DIR, action_data->buf->st_size)
2307 
2308 TEST_VAR_FN(size, ACTION_ALL_LNK, action_data->buf->st_size)
2309 
2310 TEST_VAR_FN(inode, ACTION_ALL_LNK, action_data->buf->st_ino)
2311 
2312 TEST_VAR_FN(nlink, ACTION_ALL_LNK, action_data->buf->st_nlink)
2313 
2314 TEST_VAR_FN(fileblocks, ACTION_REG, action_data->buf->st_blocks)
2315 
2316 TEST_VAR_FN(dirblocks, ACTION_DIR, action_data->buf->st_blocks)
2317 
2318 TEST_VAR_FN(blocks, ACTION_ALL_LNK, action_data->buf->st_blocks)
2319 
2320 TEST_VAR_FN(dircount, ACTION_DIR, action_data->dir_ent->dir->count)
2321 
2322 TEST_VAR_FN(depth, ACTION_ALL_LNK, action_data->depth)
2323 
2324 TEST_VAR_RANGE_FN(filesize, ACTION_REG, action_data->buf->st_size)
2325 
2326 TEST_VAR_RANGE_FN(dirsize, ACTION_DIR, action_data->buf->st_size)
2327 
2328 TEST_VAR_RANGE_FN(size, ACTION_ALL_LNK, action_data->buf->st_size)
2329 
2330 TEST_VAR_RANGE_FN(inode, ACTION_ALL_LNK, action_data->buf->st_ino)
2331 
2332 TEST_VAR_RANGE_FN(nlink, ACTION_ALL_LNK, action_data->buf->st_nlink)
2333 
2334 TEST_VAR_RANGE_FN(fileblocks, ACTION_REG, action_data->buf->st_blocks)
2335 
2336 TEST_VAR_RANGE_FN(dirblocks, ACTION_DIR, action_data->buf->st_blocks)
2337 
2338 TEST_VAR_RANGE_FN(blocks, ACTION_ALL_LNK, action_data->buf->st_blocks)
2339 
2340 TEST_VAR_RANGE_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid)
2341 
2342 TEST_VAR_RANGE_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid)
2343 
2344 TEST_VAR_RANGE_FN(depth, ACTION_ALL_LNK, action_data->depth)
2345 
2346 TEST_VAR_RANGE_FN(dircount, ACTION_DIR, action_data->dir_ent->dir->count)
2347 
2348 /*
2349  * uid specific test code
2350  */
2351 TEST_VAR_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid)
2352 
parse_uid_arg(struct test_entry * test,struct atom * atom)2353 static int parse_uid_arg(struct test_entry *test, struct atom *atom)
2354 {
2355 	struct test_number_arg *number;
2356 	long long size;
2357 	int range;
2358 	char *error;
2359 
2360 	if(parse_number(atom->argv[0], &size, &range, &error)) {
2361 		/* managed to fully parse argument as a number */
2362 		if(size < 0 || size > (((long long) 1 << 32) - 1)) {
2363 			TEST_SYNTAX_ERROR(test, 1, "Numeric uid out of "
2364 								"range\n");
2365 			return 0;
2366 		}
2367 	} else {
2368 		/* couldn't parse (fully) as a number, is it a user name? */
2369 		struct passwd *uid = getpwnam(atom->argv[0]);
2370 		if(uid) {
2371 			size = uid->pw_uid;
2372 			range = NUM_EQ;
2373 		} else {
2374 			TEST_SYNTAX_ERROR(test, 1, "Invalid uid or unknown "
2375 								"user\n");
2376 			return 0;
2377 		}
2378 	}
2379 
2380 	number = malloc(sizeof(*number));
2381 	if(number == NULL)
2382 		MEM_ERROR();
2383 
2384 	number->range = range;
2385 	number->size= size;
2386 
2387 	atom->data = number;
2388 
2389 	return 1;
2390 }
2391 
2392 
2393 /*
2394  * gid specific test code
2395  */
2396 TEST_VAR_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid)
2397 
parse_gid_arg(struct test_entry * test,struct atom * atom)2398 static int parse_gid_arg(struct test_entry *test, struct atom *atom)
2399 {
2400 	struct test_number_arg *number;
2401 	long long size;
2402 	int range;
2403 	char *error;
2404 
2405 	if(parse_number(atom->argv[0], &size, &range, &error)) {
2406 		/* managed to fully parse argument as a number */
2407 		if(size < 0 || size > (((long long) 1 << 32) - 1)) {
2408 			TEST_SYNTAX_ERROR(test, 1, "Numeric gid out of "
2409 								"range\n");
2410 			return 0;
2411 		}
2412 	} else {
2413 		/* couldn't parse (fully) as a number, is it a group name? */
2414 		struct group *gid = getgrnam(atom->argv[0]);
2415 		if(gid) {
2416 			size = gid->gr_gid;
2417 			range = NUM_EQ;
2418 		} else {
2419 			TEST_SYNTAX_ERROR(test, 1, "Invalid gid or unknown "
2420 								"group\n");
2421 			return 0;
2422 		}
2423 	}
2424 
2425 	number = malloc(sizeof(*number));
2426 	if(number == NULL)
2427 		MEM_ERROR();
2428 
2429 	number->range = range;
2430 	number->size= size;
2431 
2432 	atom->data = number;
2433 
2434 	return 1;
2435 }
2436 
2437 
2438 /*
2439  * Type test specific code
2440  */
2441 struct type_entry type_table[] = {
2442 	{ S_IFSOCK, 's' },
2443 	{ S_IFLNK, 'l' },
2444 	{ S_IFREG, 'f' },
2445 	{ S_IFBLK, 'b' },
2446 	{ S_IFDIR, 'd' },
2447 	{ S_IFCHR, 'c' },
2448 	{ S_IFIFO, 'p' },
2449 	{ 0, 0 },
2450 };
2451 
2452 
parse_type_arg(struct test_entry * test,struct atom * atom)2453 static int parse_type_arg(struct test_entry *test, struct atom *atom)
2454 {
2455 	int i;
2456 
2457 	if (strlen(atom->argv[0]) != 1)
2458 		goto failed;
2459 
2460 	for(i = 0; type_table[i].type != 0; i++)
2461 		if (type_table[i].type == atom->argv[0][0])
2462 			break;
2463 
2464 	atom->data = &type_table[i];
2465 
2466 	if(type_table[i].type != 0)
2467 		return 1;
2468 
2469 failed:
2470 	TEST_SYNTAX_ERROR(test, 0, "Unexpected file type, expected 'f', 'd', "
2471 		"'c', 'b', 'l', 's' or 'p'\n");
2472 	return 0;
2473 }
2474 
2475 
type_fn(struct atom * atom,struct action_data * action_data)2476 static int type_fn(struct atom *atom, struct action_data *action_data)
2477 {
2478 	struct type_entry *type = atom->data;
2479 
2480 	return (action_data->buf->st_mode & S_IFMT) == type->value;
2481 }
2482 
2483 
2484 /*
2485  * True test specific code
2486  */
true_fn(struct atom * atom,struct action_data * action_data)2487 static int true_fn(struct atom *atom, struct action_data *action_data)
2488 {
2489 	return 1;
2490 }
2491 
2492 
2493 /*
2494  *  False test specific code
2495  */
false_fn(struct atom * atom,struct action_data * action_data)2496 static int false_fn(struct atom *atom, struct action_data *action_data)
2497 {
2498 	return 0;
2499 }
2500 
2501 
2502 /*
2503  *  File test specific code
2504  */
parse_file_arg(struct test_entry * test,struct atom * atom)2505 static int parse_file_arg(struct test_entry *test, struct atom *atom)
2506 {
2507 	int res;
2508 	regex_t *preg = malloc(sizeof(regex_t));
2509 
2510 	if (preg == NULL)
2511 		MEM_ERROR();
2512 
2513 	res = regcomp(preg, atom->argv[0], REG_EXTENDED);
2514 	if (res) {
2515 		char str[1024]; /* overflow safe */
2516 
2517 		regerror(res, preg, str, 1024);
2518 		free(preg);
2519 		TEST_SYNTAX_ERROR(test, 0, "invalid regex \"%s\" because "
2520 			"\"%s\"\n", atom->argv[0], str);
2521 		return 0;
2522 	}
2523 
2524 	atom->data = preg;
2525 
2526 	return 1;
2527 }
2528 
2529 
file_fn(struct atom * atom,struct action_data * action_data)2530 static int file_fn(struct atom *atom, struct action_data *action_data)
2531 {
2532 	int child, res, size = 0, status;
2533 	int pipefd[2];
2534 	char *buffer = NULL;
2535 	regex_t *preg = atom->data;
2536 
2537 	res = pipe(pipefd);
2538 	if (res == -1)
2539 		BAD_ERROR("file_fn pipe failed\n");
2540 
2541 	child = fork();
2542 	if (child == -1)
2543 		BAD_ERROR("file_fn fork_failed\n");
2544 
2545 	if (child == 0) {
2546 		/*
2547 		 * Child process
2548 		 * Connect stdout to pipefd[1] and execute file command
2549 		 */
2550 		close(STDOUT_FILENO);
2551 		res = dup(pipefd[1]);
2552 		if (res == -1)
2553 			exit(EXIT_FAILURE);
2554 
2555 		execlp("file", "file", "-b", action_data->pathname,
2556 			(char *) NULL);
2557 		exit(EXIT_FAILURE);
2558 	}
2559 
2560 	/*
2561 	 * Parent process.  Read stdout from file command
2562  	 */
2563 	close(pipefd[1]);
2564 
2565 	do {
2566 		buffer = realloc(buffer, size + 512);
2567 		if (buffer == NULL)
2568 			MEM_ERROR();
2569 
2570 		res = read_bytes(pipefd[0], buffer + size, 512);
2571 
2572 		if (res == -1)
2573 			BAD_ERROR("file_fn pipe read error\n");
2574 
2575 		size += 512;
2576 
2577 	} while (res == 512);
2578 
2579 	size = size + res - 512;
2580 
2581 	buffer[size] = '\0';
2582 
2583 	res = waitpid(child,  &status, 0);
2584 
2585 	if (res == -1)
2586 		BAD_ERROR("file_fn waitpid failed\n");
2587 
2588 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
2589 		BAD_ERROR("file_fn file returned error\n");
2590 
2591 	close(pipefd[0]);
2592 
2593 	res = regexec(preg, buffer, (size_t) 0, NULL, 0);
2594 
2595 	free(buffer);
2596 
2597 	return res == 0;
2598 }
2599 
2600 
2601 /*
2602  *  Exec test specific code
2603  */
exec_fn(struct atom * atom,struct action_data * action_data)2604 static int exec_fn(struct atom *atom, struct action_data *action_data)
2605 {
2606 	int child, i, res, status;
2607 
2608 	child = fork();
2609 	if (child == -1)
2610 		BAD_ERROR("exec_fn fork_failed\n");
2611 
2612 	if (child == 0) {
2613 		/*
2614 		 * Child process
2615 		 * redirect stdin, stdout & stderr to /dev/null and
2616 		 * execute atom->argv[0]
2617 		 */
2618 		int fd = open("/dev/null", O_RDWR);
2619 		if(fd == -1)
2620 			exit(EXIT_FAILURE);
2621 
2622 		close(STDIN_FILENO);
2623 		close(STDOUT_FILENO);
2624 		close(STDERR_FILENO);
2625 		for(i = 0; i < 3; i++) {
2626 			res = dup(fd);
2627 			if (res == -1)
2628 				exit(EXIT_FAILURE);
2629 		}
2630 		close(fd);
2631 
2632 		/*
2633 		 * Create environment variables
2634 		 * NAME: name of file
2635 		 * PATHNAME: pathname of file relative to squashfs root
2636 		 * SOURCE_PATHNAME: the pathname of the file in the source
2637 		 *                  directory
2638 		 */
2639 		res = setenv("NAME", action_data->name, 1);
2640 		if(res == -1)
2641 			exit(EXIT_FAILURE);
2642 
2643 		res = setenv("PATHNAME", action_data->subpath, 1);
2644 		if(res == -1)
2645 			exit(EXIT_FAILURE);
2646 
2647 		res = setenv("SOURCE_PATHNAME", action_data->pathname, 1);
2648 		if(res == -1)
2649 			exit(EXIT_FAILURE);
2650 
2651 		execl("/bin/sh", "sh", "-c", atom->argv[0], (char *) NULL);
2652 		exit(EXIT_FAILURE);
2653 	}
2654 
2655 	/*
2656 	 * Parent process.
2657  	 */
2658 
2659 	res = waitpid(child,  &status, 0);
2660 
2661 	if (res == -1)
2662 		BAD_ERROR("exec_fn waitpid failed\n");
2663 
2664 	return WIFEXITED(status) ? WEXITSTATUS(status) == 0 : 0;
2665 }
2666 
2667 
2668 /*
2669  * Symbolic link specific test code
2670  */
2671 
2672 /*
2673  * Walk the supplied pathname and return the directory entry corresponding
2674  * to the pathname.  If any symlinks are encountered whilst walking the
2675  * pathname, then recursively walk these, to obtain the fully
2676  * dereferenced canonicalised directory entry.
2677  *
2678  * If follow_path fails to walk a pathname either because a component
2679  * doesn't exist, it is a non directory component when a directory
2680  * component is expected, a symlink with an absolute path is encountered,
2681  * or a symlink is encountered which cannot be recursively walked due to
2682  * the above failures, then return NULL.
2683  */
follow_path(struct dir_info * dir,char * pathname)2684 static struct dir_ent *follow_path(struct dir_info *dir, char *pathname)
2685 {
2686 	char *comp, *path = pathname;
2687 	struct dir_ent *dir_ent = NULL;
2688 
2689 	/* We cannot follow absolute paths */
2690 	if(pathname[0] == '/')
2691 		return NULL;
2692 
2693 	for(comp = get_comp(&path); comp; free(comp), comp = get_comp(&path)) {
2694 		if(strcmp(comp, ".") == 0)
2695 			continue;
2696 
2697 		if(strcmp(comp, "..") == 0) {
2698 			/* Move to parent if we're not in the root directory */
2699 			if(dir->depth > 1) {
2700 				dir = dir->dir_ent->our_dir;
2701 				dir_ent = NULL; /* lazily eval at loop exit */
2702 				continue;
2703 			} else
2704 				/* Failed to walk pathname */
2705 				return NULL;
2706 		}
2707 
2708 		/* Lookup comp in current directory */
2709 		dir_ent = lookup_comp(comp, dir);
2710 		if(dir_ent == NULL)
2711 			/* Doesn't exist, failed to walk pathname */
2712 			return NULL;
2713 
2714 		if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFLNK) {
2715 			/* Symbolic link, try to walk it */
2716 			dir_ent = follow_path(dir, dir_ent->inode->symlink);
2717 			if(dir_ent == NULL)
2718 				/* Failed to follow symlink */
2719 				return NULL;
2720 		}
2721 
2722 		if((dir_ent->inode->buf.st_mode & S_IFMT) != S_IFDIR)
2723 			/* Cannot walk further */
2724 			break;
2725 
2726 		dir = dir_ent->dir;
2727 	}
2728 
2729 	/* We will have exited the loop either because we've processed
2730 	 * all the components, which means we've successfully walked the
2731 	 * pathname, or because we've hit a non-directory, in which case
2732 	 * it's success if this is the leaf component */
2733 	if(comp) {
2734 		free(comp);
2735 		comp = get_comp(&path);
2736 		free(comp);
2737 		if(comp != NULL)
2738 			/* Not a leaf component */
2739 			return NULL;
2740 	} else {
2741 		/* Fully walked pathname, dir_ent contains correct value unless
2742 		 * we've walked to the parent ("..") in which case we need
2743 		 * to resolve it here */
2744 		if(!dir_ent)
2745 			dir_ent = dir->dir_ent;
2746 	}
2747 
2748 	return dir_ent;
2749 }
2750 
2751 
exists_fn(struct atom * atom,struct action_data * action_data)2752 static int exists_fn(struct atom *atom, struct action_data *action_data)
2753 {
2754 	/*
2755 	 * Test if a symlink exists within the output filesystem, that is,
2756 	 * the symlink has a relative path, and the relative path refers
2757 	 * to an entry within the output filesystem.
2758 	 *
2759 	 * This test function evaluates the path for symlinks - that is it
2760 	 * follows any symlinks in the path (and any symlinks that it contains
2761  	 * etc.), to discover the fully dereferenced canonicalised relative
2762 	 * path.
2763 	 *
2764 	 * If any symlinks within the path do not exist or are absolute
2765 	 * then the symlink is considered to not exist, as it cannot be
2766 	 * fully dereferenced.
2767 	 *
2768 	 * exists operates on symlinks only, other files by definition
2769 	 * exist
2770 	 */
2771 	if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
2772 		return 1;
2773 
2774 	/* dereference the symlink, and return TRUE if it exists */
2775 	return follow_path(action_data->dir_ent->our_dir,
2776 			action_data->dir_ent->inode->symlink) ? 1 : 0;
2777 }
2778 
2779 
absolute_fn(struct atom * atom,struct action_data * action_data)2780 static int absolute_fn(struct atom *atom, struct action_data *action_data)
2781 {
2782 	/*
2783 	 * Test if a symlink has an absolute path, which by definition
2784 	 * means the symbolic link may be broken (even if the absolute path
2785 	 * does point into the filesystem being squashed, because the resultant
2786 	 * filesystem can be mounted/unsquashed anywhere, it is unlikely the
2787 	 * absolute path will still point to the right place).  If you know that
2788 	 * an absolute symlink will point to the right place then you don't need
2789 	 * to use this function, and/or these symlinks can be excluded by
2790 	 * use of other test operators.
2791 	 *
2792 	 * absolute operates on symlinks only, other files by definition
2793 	 * don't have problems
2794 	 */
2795 	if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
2796 		return 0;
2797 
2798 	return action_data->dir_ent->inode->symlink[0] == '/';
2799 }
2800 
2801 
parse_expr_argX(struct test_entry * test,struct atom * atom,int argno)2802 static int parse_expr_argX(struct test_entry *test, struct atom *atom,
2803 	int argno)
2804 {
2805 	/* Call parse_expr to parse argument, which should be an expression */
2806 
2807 	 /* save the current parser state */
2808 	char *save_cur_ptr = cur_ptr;
2809 	char *save_source = source;
2810 
2811 	cur_ptr = source = atom->argv[argno];
2812 	atom->data = parse_expr(0);
2813 
2814 	cur_ptr = save_cur_ptr;
2815 	source = save_source;
2816 
2817 	if(atom->data == NULL) {
2818 		/* parse_expr(0) will have reported the exact syntax error,
2819 		 * but, because we recursively evaluated the expression, it
2820 		 * will have been reported without the context of the stat
2821 		 * test().  So here additionally report our failure to parse
2822 		 * the expression in the stat() test to give context */
2823 		TEST_SYNTAX_ERROR(test, 0, "Failed to parse expression\n");
2824 		return 0;
2825 	}
2826 
2827 	return 1;
2828 }
2829 
2830 
parse_expr_arg0(struct test_entry * test,struct atom * atom)2831 static int parse_expr_arg0(struct test_entry *test, struct atom *atom)
2832 {
2833 	return parse_expr_argX(test, atom, 0);
2834 }
2835 
2836 
parse_expr_arg1(struct test_entry * test,struct atom * atom)2837 static int parse_expr_arg1(struct test_entry *test, struct atom *atom)
2838 {
2839 	return parse_expr_argX(test, atom, 1);
2840 }
2841 
2842 
stat_fn(struct atom * atom,struct action_data * action_data)2843 static int stat_fn(struct atom *atom, struct action_data *action_data)
2844 {
2845 	struct stat buf;
2846 	struct action_data eval_action;
2847 	int match, res;
2848 
2849 	/* evaluate the expression using the context of the inode
2850 	 * pointed to by the symlink.  This allows the inode attributes
2851 	 * of the file pointed to by the symlink to be evaluated, rather
2852 	 * than the symlink itself.
2853 	 *
2854 	 * Note, stat() deliberately does not evaluate the pathname, name or
2855 	 * depth of the symlink, these are left with the symlink values.
2856 	 * This allows stat() to be used on any symlink, rather than
2857 	 * just symlinks which are contained (if the symlink is *not*
2858 	 * contained then pathname, name and depth are meaningless as they
2859 	 * are relative to the filesystem being squashed). */
2860 
2861 	/* if this isn't a symlink then stat will just return the current
2862 	 * information, i.e. stat(expr) == expr.  This is harmless and
2863 	 * is better than returning TRUE or FALSE in a non symlink case */
2864 	res = stat(action_data->pathname, &buf);
2865 	if(res == -1) {
2866 		if(expr_log_cmnd(LOG_ENABLED)) {
2867 			expr_log(atom->test->name);
2868 			expr_log("(");
2869 			expr_log_match(0);
2870 			expr_log(")");
2871 		}
2872 		return 0;
2873 	}
2874 
2875 	/* fill in the inode values of the file pointed to by the
2876 	 * symlink, but, leave everything else the same */
2877 	memcpy(&eval_action, action_data, sizeof(struct action_data));
2878 	eval_action.buf = &buf;
2879 
2880 	if(expr_log_cmnd(LOG_ENABLED)) {
2881 		expr_log(atom->test->name);
2882 		expr_log("(");
2883 		match = eval_expr_log(atom->data, &eval_action);
2884 		expr_log(")");
2885 	} else
2886 		match = eval_expr(atom->data, &eval_action);
2887 
2888 	return match;
2889 }
2890 
2891 
readlink_fn(struct atom * atom,struct action_data * action_data)2892 static int readlink_fn(struct atom *atom, struct action_data *action_data)
2893 {
2894 	int match = 0;
2895 	struct dir_ent *dir_ent;
2896 	struct action_data eval_action;
2897 
2898 	/* Dereference the symlink and evaluate the expression in the
2899 	 * context of the file pointed to by the symlink.
2900 	 * All attributes are updated to refer to the file that is pointed to.
2901 	 * Thus the inode attributes, pathname, name and depth all refer to
2902 	 * the dereferenced file, and not the symlink.
2903 	 *
2904 	 * If the symlink cannot be dereferenced because it doesn't exist in
2905 	 * the output filesystem, or due to some other failure to
2906 	 * walk the pathname (see follow_path above), then FALSE is returned.
2907 	 *
2908 	 * If you wish to evaluate the inode attributes of symlinks which
2909 	 * exist in the source filestem (but not in the output filesystem then
2910 	 * use stat instead (see above).
2911 	 *
2912 	 * readlink operates on symlinks only */
2913 	if (!file_type_match(action_data->buf->st_mode, ACTION_LNK))
2914 		goto finish;
2915 
2916 	/* dereference the symlink, and get the directory entry it points to */
2917 	dir_ent = follow_path(action_data->dir_ent->our_dir,
2918 			action_data->dir_ent->inode->symlink);
2919 	if(dir_ent == NULL)
2920 		goto finish;
2921 
2922 	eval_action.name = dir_ent->name;
2923 	eval_action.pathname = strdup(pathname(dir_ent));
2924 	eval_action.subpath = strdup(subpathname(dir_ent));
2925 	eval_action.buf = &dir_ent->inode->buf;
2926 	eval_action.depth = dir_ent->our_dir->depth;
2927 	eval_action.dir_ent = dir_ent;
2928 	eval_action.root = action_data->root;
2929 
2930 	if(expr_log_cmnd(LOG_ENABLED)) {
2931 		expr_log(atom->test->name);
2932 		expr_log("(");
2933 		match = eval_expr_log(atom->data, &eval_action);
2934 		expr_log(")");
2935 	} else
2936 		match = eval_expr(atom->data, &eval_action);
2937 
2938 	free(eval_action.pathname);
2939 	free(eval_action.subpath);
2940 
2941 	return match;
2942 
2943 finish:
2944 	if(expr_log_cmnd(LOG_ENABLED)) {
2945 		expr_log(atom->test->name);
2946 		expr_log("(");
2947 		expr_log_match(0);
2948 		expr_log(")");
2949 	}
2950 
2951 	return 0;
2952 }
2953 
2954 
eval_fn(struct atom * atom,struct action_data * action_data)2955 static int eval_fn(struct atom *atom, struct action_data *action_data)
2956 {
2957 	int match;
2958 	char *path = atom->argv[0];
2959 	struct dir_ent *dir_ent = action_data->dir_ent;
2960 	struct stat *buf = action_data->buf;
2961 	struct action_data eval_action;
2962 
2963 	/* Follow path (arg1) and evaluate the expression (arg2)
2964 	 * in the context of the file discovered.  All attributes are updated
2965 	 * to refer to the file that is pointed to.
2966 	 *
2967 	 * This test operation allows you to add additional context to the
2968 	 * evaluation of the file being scanned, such as "if current file is
2969 	 * XXX and the parent is YYY, then ..."  Often times you need or
2970 	 * want to test a combination of file status
2971 	 *
2972 	 * If the file referenced by the path does not exist in
2973 	 * the output filesystem, or some other failure is experienced in
2974 	 * walking the path (see follow_path above), then FALSE is returned.
2975 	 *
2976 	 * If you wish to evaluate the inode attributes of files which
2977 	 * exist in the source filestem (but not in the output filesystem then
2978 	 * use stat instead (see above). */
2979 
2980 	/* try to follow path, and get the directory entry it points to */
2981 	if(path[0] == '/') {
2982 		/* absolute, walk from root - first skip the leading / */
2983 		while(path[0] == '/')
2984 			path ++;
2985 		if(path[0] == '\0')
2986 			dir_ent = action_data->root->dir_ent;
2987 		else
2988 			dir_ent = follow_path(action_data->root, path);
2989 	} else {
2990 		/* relative, if first component is ".." walk from parent,
2991 		 * otherwise walk from dir_ent.
2992 		 * Note: this has to be handled here because follow_path
2993 		 * will quite correctly refuse to execute ".." on anything
2994 		 * which isn't a directory */
2995 		if(strncmp(path, "..", 2) == 0 && (path[2] == '\0' ||
2996 							path[2] == '/')) {
2997 			/* walk from parent */
2998 			path += 2;
2999 			while(path[0] == '/')
3000 				path ++;
3001 			if(path[0] == '\0')
3002 				dir_ent = dir_ent->our_dir->dir_ent;
3003 			else
3004 				dir_ent = follow_path(dir_ent->our_dir, path);
3005 		} else if(!file_type_match(buf->st_mode, ACTION_DIR))
3006 			dir_ent = NULL;
3007 		else
3008 			dir_ent = follow_path(dir_ent->dir, path);
3009 	}
3010 
3011 	if(dir_ent == NULL) {
3012 		if(expr_log_cmnd(LOG_ENABLED)) {
3013 			expr_log(atom->test->name);
3014 			expr_log("(");
3015 			expr_log(atom->argv[0]);
3016 			expr_log(",");
3017 			expr_log_match(0);
3018 			expr_log(")");
3019 		}
3020 
3021 		return 0;
3022 	}
3023 
3024 	eval_action.name = dir_ent->name;
3025 	eval_action.pathname = strdup(pathname(dir_ent));
3026 	eval_action.subpath = strdup(subpathname(dir_ent));
3027 	eval_action.buf = &dir_ent->inode->buf;
3028 	eval_action.depth = dir_ent->our_dir->depth;
3029 	eval_action.dir_ent = dir_ent;
3030 	eval_action.root = action_data->root;
3031 
3032 	if(expr_log_cmnd(LOG_ENABLED)) {
3033 		expr_log(atom->test->name);
3034 		expr_log("(");
3035 		expr_log(eval_action.subpath);
3036 		expr_log(",");
3037 		match = eval_expr_log(atom->data, &eval_action);
3038 		expr_log(")");
3039 	} else
3040 		match = eval_expr(atom->data, &eval_action);
3041 
3042 	free(eval_action.pathname);
3043 	free(eval_action.subpath);
3044 
3045 	return match;
3046 }
3047 
3048 
3049 /*
3050  * Perm specific test code
3051  */
parse_perm_args(struct test_entry * test,struct atom * atom)3052 static int parse_perm_args(struct test_entry *test, struct atom *atom)
3053 {
3054 	int res = 1, mode, op, i;
3055 	char *arg;
3056 	struct mode_data *head = NULL, *cur = NULL;
3057 	struct perm_data *perm_data;
3058 
3059 	if(atom->args == 0) {
3060 		TEST_SYNTAX_ERROR(test, 0, "One or more arguments expected\n");
3061 		return 0;
3062 	}
3063 
3064 	switch(atom->argv[0][0]) {
3065 	case '-':
3066 		op = PERM_ALL;
3067 		arg = atom->argv[0] + 1;
3068 		break;
3069 	case '/':
3070 		op = PERM_ANY;
3071 		arg = atom->argv[0] + 1;
3072 		break;
3073 	default:
3074 		op = PERM_EXACT;
3075 		arg = atom->argv[0];
3076 		break;
3077 	}
3078 
3079 	/* try to parse as an octal number */
3080 	res = parse_octal_mode_args(atom->args, atom->argv, (void **) &head);
3081 	if(res == -1) {
3082 		/* parse as sym mode argument */
3083 		for(i = 0; i < atom->args && res; i++, arg = atom->argv[i])
3084 			res = parse_sym_mode_arg(arg, &head, &cur);
3085 	}
3086 
3087 	if (res == 0)
3088 		goto finish;
3089 
3090 	/*
3091 	 * Evaluate the symbolic mode against a permission of 0000 octal
3092 	 */
3093 	mode = mode_execute(head, 0);
3094 
3095 	perm_data = malloc(sizeof(struct perm_data));
3096 	if (perm_data == NULL)
3097 		MEM_ERROR();
3098 
3099 	perm_data->op = op;
3100 	perm_data->mode = mode;
3101 
3102 	atom->data = perm_data;
3103 
3104 finish:
3105 	while(head) {
3106 		struct mode_data *tmp = head;
3107 		head = head->next;
3108 		free(tmp);
3109 	}
3110 
3111 	return res;
3112 }
3113 
3114 
perm_fn(struct atom * atom,struct action_data * action_data)3115 static int perm_fn(struct atom *atom, struct action_data *action_data)
3116 {
3117 	struct perm_data *perm_data = atom->data;
3118 	struct stat *buf = action_data->buf;
3119 
3120 	switch(perm_data->op) {
3121 	case PERM_EXACT:
3122 		return (buf->st_mode & ~S_IFMT) == perm_data->mode;
3123 	case PERM_ALL:
3124 		return (buf->st_mode & perm_data->mode) == perm_data->mode;
3125 	case PERM_ANY:
3126 	default:
3127 		/*
3128 		 * if no permission bits are set in perm_data->mode match
3129 		 * on any file, this is to be consistent with find, which
3130 		 * does this to be consistent with the behaviour of
3131 		 * -perm -000
3132 		 */
3133 		return perm_data->mode == 0 || (buf->st_mode & perm_data->mode);
3134 	}
3135 }
3136 
3137 
3138 #ifdef SQUASHFS_TRACE
dump_parse_tree(struct expr * expr)3139 static void dump_parse_tree(struct expr *expr)
3140 {
3141 	int i;
3142 
3143 	if(expr->type == ATOM_TYPE) {
3144 		printf("%s", expr->atom.test->name);
3145 		if(expr->atom.args) {
3146 			printf("(");
3147 			for(i = 0; i < expr->atom.args; i++) {
3148 				printf("%s", expr->atom.argv[i]);
3149 				if (i + 1 < expr->atom.args)
3150 					printf(",");
3151 			}
3152 			printf(")");
3153 		}
3154 	} else if (expr->type == UNARY_TYPE) {
3155 		printf("%s", token_table[expr->unary_op.op].string);
3156 		dump_parse_tree(expr->unary_op.expr);
3157 	} else {
3158 		printf("(");
3159 		dump_parse_tree(expr->expr_op.lhs);
3160 		printf("%s", token_table[expr->expr_op.op].string);
3161 		dump_parse_tree(expr->expr_op.rhs);
3162 		printf(")");
3163 	}
3164 }
3165 
3166 
dump_action_list(struct action * spec_list,int spec_count)3167 void dump_action_list(struct action *spec_list, int spec_count)
3168 {
3169 	int i;
3170 
3171 	for (i = 0; i < spec_count; i++) {
3172 		printf("%s", spec_list[i].action->name);
3173 		if (spec_list[i].args) {
3174 			int n;
3175 
3176 			printf("(");
3177 			for (n = 0; n < spec_list[i].args; n++) {
3178 				printf("%s", spec_list[i].argv[n]);
3179 				if (n + 1 < spec_list[i].args)
3180 					printf(",");
3181 			}
3182 			printf(")");
3183 		}
3184 		printf("=");
3185 		dump_parse_tree(spec_list[i].expr);
3186 		printf("\n");
3187 	}
3188 }
3189 
3190 
dump_actions()3191 void dump_actions()
3192 {
3193 	dump_action_list(exclude_spec, exclude_count);
3194 	dump_action_list(fragment_spec, fragment_count);
3195 	dump_action_list(other_spec, other_count);
3196 	dump_action_list(move_spec, move_count);
3197 	dump_action_list(empty_spec, empty_count);
3198 }
3199 #else
dump_actions()3200 void dump_actions()
3201 {
3202 }
3203 #endif
3204 
3205 
3206 static struct test_entry test_table[] = {
3207 	{ "name", 1, name_fn, NULL, 1},
3208 	{ "pathname", 1, pathname_fn, check_pathname, 1, 0},
3209 	{ "subpathname", 1, subpathname_fn, check_pathname, 1, 0},
3210 	{ "filesize", 1, filesize_fn, parse_number_arg, 1, 0},
3211 	{ "dirsize", 1, dirsize_fn, parse_number_arg, 1, 0},
3212 	{ "size", 1, size_fn, parse_number_arg, 1, 0},
3213 	{ "inode", 1, inode_fn, parse_number_arg, 1, 0},
3214 	{ "nlink", 1, nlink_fn, parse_number_arg, 1, 0},
3215 	{ "fileblocks", 1, fileblocks_fn, parse_number_arg, 1, 0},
3216 	{ "dirblocks", 1, dirblocks_fn, parse_number_arg, 1, 0},
3217 	{ "blocks", 1, blocks_fn, parse_number_arg, 1, 0},
3218 	{ "gid", 1, gid_fn, parse_gid_arg, 1, 0},
3219 	{ "uid", 1, uid_fn, parse_uid_arg, 1, 0},
3220 	{ "depth", 1, depth_fn, parse_number_arg, 1, 0},
3221 	{ "dircount", 1, dircount_fn, parse_number_arg, 0, 0},
3222 	{ "filesize_range", 2, filesize_range_fn, parse_range_args, 1, 0},
3223 	{ "dirsize_range", 2, dirsize_range_fn, parse_range_args, 1, 0},
3224 	{ "size_range", 2, size_range_fn, parse_range_args, 1, 0},
3225 	{ "inode_range", 2, inode_range_fn, parse_range_args, 1, 0},
3226 	{ "nlink_range", 2, nlink_range_fn, parse_range_args, 1, 0},
3227 	{ "fileblocks_range", 2, fileblocks_range_fn, parse_range_args, 1, 0},
3228 	{ "dirblocks_range", 2, dirblocks_range_fn, parse_range_args, 1, 0},
3229 	{ "blocks_range", 2, blocks_range_fn, parse_range_args, 1, 0},
3230 	{ "gid_range", 2, gid_range_fn, parse_range_args, 1, 0},
3231 	{ "uid_range", 2, uid_range_fn, parse_range_args, 1, 0},
3232 	{ "depth_range", 2, depth_range_fn, parse_range_args, 1, 0},
3233 	{ "dircount_range", 2, dircount_range_fn, parse_range_args, 0, 0},
3234 	{ "type", 1, type_fn, parse_type_arg, 1, 0},
3235 	{ "true", 0, true_fn, NULL, 1, 0},
3236 	{ "false", 0, false_fn, NULL, 1, 0},
3237 	{ "file", 1, file_fn, parse_file_arg, 1, 0},
3238 	{ "exec", 1, exec_fn, NULL, 1, 0},
3239 	{ "exists", 0, exists_fn, NULL, 0, 0},
3240 	{ "absolute", 0, absolute_fn, NULL, 0, 0},
3241 	{ "stat", 1, stat_fn, parse_expr_arg0, 1, 1},
3242 	{ "readlink", 1, readlink_fn, parse_expr_arg0, 0, 1},
3243 	{ "eval", 2, eval_fn, parse_expr_arg1, 0, 1},
3244 	{ "perm", -2, perm_fn, parse_perm_args, 1, 0},
3245 	{ "", -1 }
3246 };
3247 
3248 
3249 static struct action_entry action_table[] = {
3250 	{ "fragment", FRAGMENT_ACTION, 1, ACTION_REG, NULL, NULL},
3251 	{ "exclude", EXCLUDE_ACTION, 0, ACTION_ALL_LNK, NULL, NULL},
3252 	{ "fragments", FRAGMENTS_ACTION, 0, ACTION_REG, NULL, frag_action},
3253 	{ "no-fragments", NO_FRAGMENTS_ACTION, 0, ACTION_REG, NULL,
3254 						no_frag_action},
3255 	{ "always-use-fragments", ALWAYS_FRAGS_ACTION, 0, ACTION_REG, NULL,
3256 						always_frag_action},
3257 	{ "dont-always-use-fragments", NO_ALWAYS_FRAGS_ACTION, 0, ACTION_REG,
3258 						NULL, no_always_frag_action},
3259 	{ "compressed", COMPRESSED_ACTION, 0, ACTION_REG, NULL, comp_action},
3260 	{ "uncompressed", UNCOMPRESSED_ACTION, 0, ACTION_REG, NULL,
3261 						uncomp_action},
3262 	{ "uid", UID_ACTION, 1, ACTION_ALL_LNK, parse_uid_args, uid_action},
3263 	{ "gid", GID_ACTION, 1, ACTION_ALL_LNK, parse_gid_args, gid_action},
3264 	{ "guid", GUID_ACTION, 2, ACTION_ALL_LNK, parse_guid_args, guid_action},
3265 	{ "mode", MODE_ACTION, -2, ACTION_ALL, parse_mode_args, mode_action },
3266 	{ "empty", EMPTY_ACTION, -2, ACTION_DIR, parse_empty_args, NULL},
3267 	{ "move", MOVE_ACTION, 1, ACTION_ALL_LNK, NULL, NULL},
3268 	{ "prune", PRUNE_ACTION, 0, ACTION_ALL_LNK, NULL, NULL},
3269 	{ "chmod", MODE_ACTION, -2, ACTION_ALL, parse_mode_args, mode_action },
3270 	{ "noop", NOOP_ACTION, 0, ACTION_ALL, NULL, noop_action },
3271 	{ "", 0, -1, 0, NULL, NULL}
3272 };
3273