Home | History | Annotate | Download | only in squashfs-tools
      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 (at) 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 
    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 
    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  */
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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 
    658 char *expr_log_cmnd(int cmnd)
    659 {
    660 	return _expr_log(NULL, cmnd);
    661 }
    662 
    663 
    664 char *expr_log(char *string)
    665 {
    666 	return _expr_log(string, LOG_PRINT);
    667 }
    668 
    669 
    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 
    691 void expr_log_match(int match)
    692 {
    693 	if(match)
    694 		expr_log("=True");
    695 	else
    696 		expr_log("=False");
    697 }
    698 
    699 
    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 
    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 
    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  */
    809 int parse_action_true(char *s)
    810 {
    811 	return parse_action(s, ACTION_LOG_TRUE);
    812 }
    813 
    814 
    815 int parse_action_false(char *s)
    816 {
    817 	return parse_action(s, ACTION_LOG_FALSE);
    818 }
    819 
    820 
    821 int parse_action_verbose(char *s)
    822 {
    823 	return parse_action(s, ACTION_LOG_VERBOSE);
    824 }
    825 
    826 
    827 int parse_action_nonverbose(char *s)
    828 {
    829 	return parse_action(s, ACTION_LOG_NONE);
    830 }
    831 
    832 
    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  */
    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  */
    874 int actions()
    875 {
    876 	return other_count;
    877 }
    878 
    879 
    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  */
    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 
    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  */
    969 int exclude_actions()
    970 {
    971 	return exclude_count;
    972 }
    973 
    974 
    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  */
    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 
   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 
   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 
   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  */
   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 
   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  */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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  */
   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  */
   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 
   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 
   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 
   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 
   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  */
   1469 int empty_actions()
   1470 {
   1471 	return empty_count;
   1472 }
   1473 
   1474 
   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 
   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 
   1568 int move_actions()
   1569 {
   1570 	return move_count;
   1571 }
   1572 
   1573 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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  */
   1980 int prune_actions()
   1981 {
   1982 	return prune_count;
   1983 }
   1984 
   1985 
   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  */
   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  */
   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 
   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 
   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  */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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  */
   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  */
   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  */
   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 
   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  */
   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  */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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  */
   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 
   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
   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 
   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 
   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
   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