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