1/*
2 * Create a squashfs filesystem.  This is a highly compressed read only
3 * filesystem.
4 *
5 * Copyright (c) 2011, 2012, 2013, 2014
6 * Phillip Lougher <phillip@squashfs.org.uk>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * action.c
23 */
24
25#include <fcntl.h>
26#include <dirent.h>
27#include <stddef.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <unistd.h>
34#include <fnmatch.h>
35#include <pwd.h>
36#include <grp.h>
37#include <sys/wait.h>
38#include <regex.h>
39#include <limits.h>
40#include <errno.h>
41
42#ifndef FNM_EXTMATCH /* glibc extension */
43    #define FNM_EXTMATCH 0
44#endif
45
46#include "squashfs_fs.h"
47#include "mksquashfs.h"
48#include "action.h"
49#include "error.h"
50
51/*
52 * code to parse actions
53 */
54
55static char *cur_ptr, *source;
56static struct action *fragment_spec = NULL;
57static struct action *exclude_spec = NULL;
58static struct action *empty_spec = NULL;
59static struct action *move_spec = NULL;
60static struct action *prune_spec = NULL;
61static struct action *other_spec = NULL;
62static int fragment_count = 0;
63static int exclude_count = 0;
64static int empty_count = 0;
65static int move_count = 0;
66static int prune_count = 0;
67static int other_count = 0;
68static struct action_entry *parsing_action;
69
70static struct file_buffer *def_fragment = NULL;
71
72static 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
86static struct test_entry test_table[];
87
88static struct action_entry action_table[];
89
90static struct expr *parse_expr(int subexp);
91
92extern char *pathname(struct dir_ent *);
93
94extern char *subpathname(struct dir_ent *);
95
96extern int read_file(char *filename, char *type, int (parse_line)(char *));
97
98/*
99 * Lexical analyser
100 */
101#define STR_SIZE 256
102
103static 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
194static 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 */
208static 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
228static 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
250static 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
269static 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
351skip_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
373failed:
374	free(argv);
375	free(expr);
376	return NULL;
377}
378
379
380static 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
401static 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 */
446int 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
522skip_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
598failed:
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
615char *_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
658char *expr_log_cmnd(int cmnd)
659{
660	return _expr_log(NULL, cmnd);
661}
662
663
664char *expr_log(char *string)
665{
666	return _expr_log(string, LOG_PRINT);
667}
668
669
670void 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
691void expr_log_match(int match)
692{
693	if(match)
694		expr_log("=True");
695	else
696		expr_log("=False");
697}
698
699
700static 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
731static 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
755static 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 */
809int parse_action_true(char *s)
810{
811	return parse_action(s, ACTION_LOG_TRUE);
812}
813
814
815int parse_action_false(char *s)
816{
817	return parse_action(s, ACTION_LOG_FALSE);
818}
819
820
821int parse_action_verbose(char *s)
822{
823	return parse_action(s, ACTION_LOG_VERBOSE);
824}
825
826
827int parse_action_nonverbose(char *s)
828{
829	return parse_action(s, ACTION_LOG_NONE);
830}
831
832
833int 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 */
851static 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 */
874int actions()
875{
876	return other_count;
877}
878
879
880void 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 */
915void *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
943void *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 */
969int exclude_actions()
970{
971	return exclude_count;
972}
973
974
975int 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 */
998static 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
1005static 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
1012static 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
1019static 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 */
1030static 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
1037static 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 */
1048static 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
1072static 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
1096static 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
1117static 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
1138static 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
1164static 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
1172static 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
1180static 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 */
1194static 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 */
1244static 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
1280parse_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
1352perms_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
1372failed:
1373	return 0;
1374}
1375
1376
1377static 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
1392static 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
1411static 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
1459static 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 */
1469int empty_actions()
1470{
1471	return empty_count;
1472}
1473
1474
1475static 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
1510int 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 */
1565static struct move_ent *move_list = NULL;
1566
1567
1568int move_actions()
1569{
1570	return move_count;
1571}
1572
1573
1574static 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
1597static 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
1616static 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
1628void 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
1748static 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
1761void 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
1848finish:
1849	free(action_data.pathname);
1850	free(action_data.subpath);
1851}
1852
1853
1854static 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
1870static 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
1953void 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 */
1980int prune_actions()
1981{
1982	return prune_count;
1983}
1984
1985
1986int 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 */
2012static 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 */
2033static 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
2099static 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
2125static 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) \
2174static 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 */
2226static 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
2244TEST_FN(name, ACTION_ALL_LNK, \
2245	return fnmatch(atom->argv[0], action_data->name,
2246				FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;)
2247
2248TEST_FN(pathname, ACTION_ALL_LNK, \
2249	return fnmatch(atom->argv[0], action_data->subpath,
2250				FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;)
2251
2252
2253static 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
2269static 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
2289static 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 */
2305TEST_VAR_FN(filesize, ACTION_REG, action_data->buf->st_size)
2306
2307TEST_VAR_FN(dirsize, ACTION_DIR, action_data->buf->st_size)
2308
2309TEST_VAR_FN(size, ACTION_ALL_LNK, action_data->buf->st_size)
2310
2311TEST_VAR_FN(inode, ACTION_ALL_LNK, action_data->buf->st_ino)
2312
2313TEST_VAR_FN(nlink, ACTION_ALL_LNK, action_data->buf->st_nlink)
2314
2315TEST_VAR_FN(fileblocks, ACTION_REG, action_data->buf->st_blocks)
2316
2317TEST_VAR_FN(dirblocks, ACTION_DIR, action_data->buf->st_blocks)
2318
2319TEST_VAR_FN(blocks, ACTION_ALL_LNK, action_data->buf->st_blocks)
2320
2321TEST_VAR_FN(dircount, ACTION_DIR, action_data->dir_ent->dir->count)
2322
2323TEST_VAR_FN(depth, ACTION_ALL_LNK, action_data->depth)
2324
2325TEST_VAR_RANGE_FN(filesize, ACTION_REG, action_data->buf->st_size)
2326
2327TEST_VAR_RANGE_FN(dirsize, ACTION_DIR, action_data->buf->st_size)
2328
2329TEST_VAR_RANGE_FN(size, ACTION_ALL_LNK, action_data->buf->st_size)
2330
2331TEST_VAR_RANGE_FN(inode, ACTION_ALL_LNK, action_data->buf->st_ino)
2332
2333TEST_VAR_RANGE_FN(nlink, ACTION_ALL_LNK, action_data->buf->st_nlink)
2334
2335TEST_VAR_RANGE_FN(fileblocks, ACTION_REG, action_data->buf->st_blocks)
2336
2337TEST_VAR_RANGE_FN(dirblocks, ACTION_DIR, action_data->buf->st_blocks)
2338
2339TEST_VAR_RANGE_FN(blocks, ACTION_ALL_LNK, action_data->buf->st_blocks)
2340
2341TEST_VAR_RANGE_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid)
2342
2343TEST_VAR_RANGE_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid)
2344
2345TEST_VAR_RANGE_FN(depth, ACTION_ALL_LNK, action_data->depth)
2346
2347TEST_VAR_RANGE_FN(dircount, ACTION_DIR, action_data->dir_ent->dir->count)
2348
2349/*
2350 * uid specific test code
2351 */
2352TEST_VAR_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid)
2353
2354static 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 */
2397TEST_VAR_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid)
2398
2399static 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 */
2442struct 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
2454static 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
2470failed:
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
2477static 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 */
2488static 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 */
2497static 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 */
2506static 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
2531static 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 */
2605static 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 */
2685static 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
2753static 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
2781static 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
2803static 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
2832static int parse_expr_arg0(struct test_entry *test, struct atom *atom)
2833{
2834	return parse_expr_argX(test, atom, 0);
2835}
2836
2837
2838static int parse_expr_arg1(struct test_entry *test, struct atom *atom)
2839{
2840	return parse_expr_argX(test, atom, 1);
2841}
2842
2843
2844static 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
2893static 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
2944finish:
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
2956static 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 */
3053static 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
3105finish:
3106	while(head) {
3107		struct mode_data *tmp = head;
3108		head = head->next;
3109		free(tmp);
3110	}
3111
3112	return res;
3113}
3114
3115
3116static 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
3140static 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
3168void 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
3192void 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
3201void dump_actions()
3202{
3203}
3204#endif
3205
3206
3207static 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
3250static 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