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