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