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