2 * Create a squashfs filesystem. This is a highly compressed read only
5 * Copyright (c) 2011, 2012, 2013, 2014
6 * Phillip Lougher <phillip@squashfs.org.uk>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <sys/types.h>
41 #include "squashfs_fs.h"
42 #include "mksquashfs.h"
45 #include "fnmatch_compat.h"
48 * code to parse actions
51 static char *cur_ptr
, *source
;
52 static struct action
*fragment_spec
= NULL
;
53 static struct action
*exclude_spec
= NULL
;
54 static struct action
*empty_spec
= NULL
;
55 static struct action
*move_spec
= NULL
;
56 static struct action
*prune_spec
= NULL
;
57 static struct action
*other_spec
= NULL
;
58 static int fragment_count
= 0;
59 static int exclude_count
= 0;
60 static int empty_count
= 0;
61 static int move_count
= 0;
62 static int prune_count
= 0;
63 static int other_count
= 0;
64 static struct action_entry
*parsing_action
;
66 static struct file_buffer
*def_fragment
= NULL
;
68 static struct token_entry token_table
[] = {
69 { "(", TOK_OPEN_BRACKET
, 1, },
70 { ")", TOK_CLOSE_BRACKET
, 1 },
74 { ",", TOK_COMMA
, 1 },
76 { " ", TOK_WHITE_SPACE
, 1 },
77 { "\t ", TOK_WHITE_SPACE
, 1 },
82 static struct test_entry test_table
[];
84 static struct action_entry action_table
[];
86 static struct expr
*parse_expr(int subexp
);
88 extern char *pathname(struct dir_ent
*);
90 extern char *subpathname(struct dir_ent
*);
92 extern int read_file(char *filename
, char *type
, int (parse_line
)(char *));
99 static int get_token(char **string
)
102 static char *str
= NULL
;
106 int cur_size
, i
, quoted
;
109 if (*cur_ptr
== '\0')
111 for (i
= 0; token_table
[i
].token
!= -1; i
++)
112 if (strncmp(cur_ptr
, token_table
[i
].string
,
113 token_table
[i
].size
) == 0)
115 if (token_table
[i
].token
!= TOK_WHITE_SPACE
)
120 if (token_table
[i
].token
!= -1) {
121 cur_ptr
+= token_table
[i
].size
;
122 return token_table
[i
].token
;
127 str
= malloc(STR_SIZE
);
133 /* Initialise string being read */
139 while(*cur_ptr
== '"') {
144 if(*cur_ptr
== '\0') {
145 /* inside quoted string EOF, otherwise end of string */
153 for(i
= 0; token_table
[i
].token
!= -1; i
++)
154 if (strncmp(cur_ptr
, token_table
[i
].string
,
155 token_table
[i
].size
) == 0)
157 if (token_table
[i
].token
!= -1)
161 if(*cur_ptr
== '\\') {
167 if(cur_size
+ 2 > size
) {
170 size
= (cur_size
+ 1 + STR_SIZE
) & ~(STR_SIZE
- 1);
172 tmp
= realloc(str
, size
);
176 str_ptr
= str_ptr
- str
+ tmp
;
180 *str_ptr
++ = *cur_ptr
++;
190 static int peek_token(char **string
)
192 char *saved
= cur_ptr
;
193 int token
= get_token(string
);
204 static void free_parse_tree(struct expr
*expr
)
206 if(expr
->type
== ATOM_TYPE
) {
209 for(i
= 0; i
< expr
->atom
.test
->args
; i
++)
210 free(expr
->atom
.argv
[i
]);
212 free(expr
->atom
.argv
);
213 } else if (expr
->type
== UNARY_TYPE
)
214 free_parse_tree(expr
->unary_op
.expr
);
216 free_parse_tree(expr
->expr_op
.lhs
);
217 free_parse_tree(expr
->expr_op
.rhs
);
224 static struct expr
*create_expr(struct expr
*lhs
, int op
, struct expr
*rhs
)
229 free_parse_tree(lhs
);
233 expr
= malloc(sizeof(*expr
));
237 expr
->type
= OP_TYPE
;
238 expr
->expr_op
.lhs
= lhs
;
239 expr
->expr_op
.rhs
= rhs
;
240 expr
->expr_op
.op
= op
;
246 static struct expr
*create_unary_op(struct expr
*lhs
, int op
)
253 expr
= malloc(sizeof(*expr
));
257 expr
->type
= UNARY_TYPE
;
258 expr
->unary_op
.expr
= lhs
;
259 expr
->unary_op
.op
= op
;
265 static struct expr
*parse_test(char *name
)
267 char *string
, **argv
= NULL
;
270 struct test_entry
*test
;
273 for (i
= 0; test_table
[i
].args
!= -1; i
++)
274 if (strcmp(name
, test_table
[i
].name
) == 0)
277 test
= &test_table
[i
];
279 if (test
->args
== -1) {
280 SYNTAX_ERROR("Non-existent test \"%s\"\n", name
);
284 if(parsing_action
->type
== EXCLUDE_ACTION
&& !test
->exclude_ok
) {
285 fprintf(stderr
, "Failed to parse action \"%s\"\n", source
);
286 fprintf(stderr
, "Test \"%s\" cannot be used in exclude "
288 fprintf(stderr
, "Use prune action instead ...\n");
292 expr
= malloc(sizeof(*expr
));
296 expr
->type
= ATOM_TYPE
;
298 expr
->atom
.test
= test
;
299 expr
->atom
.data
= NULL
;
302 * If the test has no arguments, then go straight to checking if there's
305 token
= peek_token(&string
);
307 if (token
!= TOK_OPEN_BRACKET
)
313 * speculatively read all the arguments, and then see if the
314 * number of arguments read is the number expected, this handles
315 * tests with a variable number of arguments
317 token
= get_token(&string
);
318 if (token
== TOK_CLOSE_BRACKET
)
322 if (token
!= TOK_STRING
) {
323 SYNTAX_ERROR("Unexpected token \"%s\", expected "
324 "argument\n", TOK_TO_STR(token
, string
));
328 argv
= realloc(argv
, (args
+ 1) * sizeof(char *));
332 argv
[args
++ ] = strdup(string
);
334 token
= get_token(&string
);
336 if (token
== TOK_CLOSE_BRACKET
)
339 if (token
!= TOK_COMMA
) {
340 SYNTAX_ERROR("Unexpected token \"%s\", expected "
341 "\",\" or \")\"\n", TOK_TO_STR(token
, string
));
344 token
= get_token(&string
);
349 * expected number of arguments?
351 if(test
->args
!= -2 && args
!= test
->args
) {
352 SYNTAX_ERROR("Unexpected number of arguments, expected %d, "
353 "got %d\n", test
->args
, args
);
357 expr
->atom
.args
= args
;
358 expr
->atom
.argv
= argv
;
360 if (test
->parse_args
) {
361 int res
= test
->parse_args(test
, &expr
->atom
);
376 static struct expr
*get_atom()
379 int token
= get_token(&string
);
383 return create_unary_op(get_atom(), token
);
384 case TOK_OPEN_BRACKET
:
385 return parse_expr(1);
387 return parse_test(string
);
389 SYNTAX_ERROR("Unexpected token \"%s\", expected test "
390 "operation, \"!\", or \"(\"\n",
391 TOK_TO_STR(token
, string
));
397 static struct expr
*parse_expr(int subexp
)
399 struct expr
*expr
= get_atom();
403 int op
= get_token(&string
);
407 free_parse_tree(expr
);
408 SYNTAX_ERROR("Expected \"&&\", \"||\" or "
415 if (op
== TOK_CLOSE_BRACKET
) {
417 free_parse_tree(expr
);
418 SYNTAX_ERROR("Unexpected \")\", expected "
419 "\"&&\", \"!!\" or EOF\n");
425 if (op
!= TOK_AND
&& op
!= TOK_OR
) {
426 free_parse_tree(expr
);
427 SYNTAX_ERROR("Unexpected token \"%s\", expected "
428 "\"&&\" or \"||\"\n", TOK_TO_STR(op
, string
));
432 expr
= create_expr(expr
, op
, get_atom());
442 int parse_action(char *s
, int verbose
)
444 char *string
, **argv
= NULL
;
445 int i
, token
, args
= 0;
447 struct action_entry
*action
;
449 struct action
**spec_list
;
452 cur_ptr
= source
= s
;
453 token
= get_token(&string
);
455 if (token
!= TOK_STRING
) {
456 SYNTAX_ERROR("Unexpected token \"%s\", expected name\n",
457 TOK_TO_STR(token
, string
));
461 for (i
= 0; action_table
[i
].args
!= -1; i
++)
462 if (strcmp(string
, action_table
[i
].name
) == 0)
465 if (action_table
[i
].args
== -1) {
466 SYNTAX_ERROR("Non-existent action \"%s\"\n", string
);
470 action
= &action_table
[i
];
472 token
= get_token(&string
);
477 if (token
!= TOK_OPEN_BRACKET
) {
478 SYNTAX_ERROR("Unexpected token \"%s\", expected \"(\"\n",
479 TOK_TO_STR(token
, string
));
484 * speculatively read all the arguments, and then see if the
485 * number of arguments read is the number expected, this handles
486 * actions with a variable number of arguments
488 token
= get_token(&string
);
489 if (token
== TOK_CLOSE_BRACKET
)
493 if (token
!= TOK_STRING
) {
494 SYNTAX_ERROR("Unexpected token \"%s\", expected "
495 "argument\n", TOK_TO_STR(token
, string
));
499 argv
= realloc(argv
, (args
+ 1) * sizeof(char *));
503 argv
[args
++] = strdup(string
);
505 token
= get_token(&string
);
507 if (token
== TOK_CLOSE_BRACKET
)
510 if (token
!= TOK_COMMA
) {
511 SYNTAX_ERROR("Unexpected token \"%s\", expected "
512 "\",\" or \")\"\n", TOK_TO_STR(token
, string
));
515 token
= get_token(&string
);
520 * expected number of arguments?
522 if(action
->args
!= -2 && args
!= action
->args
) {
523 SYNTAX_ERROR("Unexpected number of arguments, expected %d, "
524 "got %d\n", action
->args
, args
);
528 if (action
->parse_args
) {
529 int res
= action
->parse_args(action
, args
, argv
, &data
);
535 if (token
== TOK_CLOSE_BRACKET
)
536 token
= get_token(&string
);
538 if (token
!= TOK_AT
) {
539 SYNTAX_ERROR("Unexpected token \"%s\", expected \"@\"\n",
540 TOK_TO_STR(token
, string
));
544 parsing_action
= action
;
545 expr
= parse_expr(0);
551 * choose action list and increment action counter
553 switch(action
->type
) {
554 case FRAGMENT_ACTION
:
555 spec_count
= fragment_count
++;
556 spec_list
= &fragment_spec
;
559 spec_count
= exclude_count
++;
560 spec_list
= &exclude_spec
;
563 spec_count
= empty_count
++;
564 spec_list
= &empty_spec
;
567 spec_count
= move_count
++;
568 spec_list
= &move_spec
;
571 spec_count
= prune_count
++;
572 spec_list
= &prune_spec
;
575 spec_count
= other_count
++;
576 spec_list
= &other_spec
;
579 *spec_list
= realloc(*spec_list
, (spec_count
+ 1) *
580 sizeof(struct action
));
581 if (*spec_list
== NULL
)
584 (*spec_list
)[spec_count
].type
= action
->type
;
585 (*spec_list
)[spec_count
].action
= action
;
586 (*spec_list
)[spec_count
].args
= args
;
587 (*spec_list
)[spec_count
].argv
= argv
;
588 (*spec_list
)[spec_count
].expr
= expr
;
589 (*spec_list
)[spec_count
].data
= data
;
590 (*spec_list
)[spec_count
].verbose
= verbose
;
601 * Evaluate expressions
607 #define LOG_DISABLE 1
609 #define LOG_ENABLED 3
611 char *_expr_log(char *string
, int cmnd
)
613 static char *expr_msg
= NULL
;
614 static int cur_size
= 0, alloc_size
= 0;
619 expr_msg
= malloc(ALLOC_SZ
);
620 alloc_size
= ALLOC_SZ
;
625 alloc_size
= cur_size
= 0;
626 return expr_msg
= NULL
;
635 /* if string is empty append '\0' */
636 size
= strlen(string
) ? : 1;
638 if(alloc_size
- cur_size
< size
) {
639 /* buffer too small, expand */
640 alloc_size
= (cur_size
+ size
+ ALLOC_SZ
- 1) & ~(ALLOC_SZ
- 1);
642 expr_msg
= realloc(expr_msg
, alloc_size
);
647 memcpy(expr_msg
+ cur_size
, string
, size
);
654 char *expr_log_cmnd(int cmnd
)
656 return _expr_log(NULL
, cmnd
);
660 char *expr_log(char *string
)
662 return _expr_log(string
, LOG_PRINT
);
666 void expr_log_atom(struct atom
*atom
)
670 if(atom
->test
->handle_logging
)
673 expr_log(atom
->test
->name
);
677 for(i
= 0; i
< atom
->args
; i
++) {
678 expr_log(atom
->argv
[i
]);
679 if (i
+ 1 < atom
->args
)
687 void expr_log_match(int match
)
696 static int eval_expr_log(struct expr
*expr
, struct action_data
*action_data
)
700 switch (expr
->type
) {
702 expr_log_atom(&expr
->atom
);
703 match
= expr
->atom
.test
->fn(&expr
->atom
, action_data
);
704 expr_log_match(match
);
708 match
= !eval_expr_log(expr
->unary_op
.expr
, action_data
);
712 match
= eval_expr_log(expr
->expr_op
.lhs
, action_data
);
714 if ((expr
->expr_op
.op
== TOK_AND
&& match
) ||
715 (expr
->expr_op
.op
== TOK_OR
&& !match
)) {
716 expr_log(token_table
[expr
->expr_op
.op
].string
);
717 match
= eval_expr_log(expr
->expr_op
.rhs
, action_data
);
727 static int eval_expr(struct expr
*expr
, struct action_data
*action_data
)
731 switch (expr
->type
) {
733 match
= expr
->atom
.test
->fn(&expr
->atom
, action_data
);
736 match
= !eval_expr(expr
->unary_op
.expr
, action_data
);
739 match
= eval_expr(expr
->expr_op
.lhs
, action_data
);
741 if ((expr
->expr_op
.op
== TOK_AND
&& match
) ||
742 (expr
->expr_op
.op
== TOK_OR
&& !match
))
743 match
= eval_expr(expr
->expr_op
.rhs
, action_data
);
751 static int eval_expr_top(struct action
*action
, struct action_data
*action_data
)
753 if(action
->verbose
) {
756 expr_log_cmnd(LOG_ENABLE
);
758 if(action_data
->subpath
)
759 expr_log(action_data
->subpath
);
762 expr_log(action
->action
->name
);
766 for (n
= 0; n
< action
->args
; n
++) {
767 expr_log(action
->argv
[n
]);
768 if(n
+ 1 < action
->args
)
776 match
= eval_expr_log(action
->expr
, action_data
);
779 * Print the evaluated expression log, if the
780 * result matches the logging specified
782 if((match
&& (action
->verbose
& ACTION_LOG_TRUE
)) || (!match
783 && (action
->verbose
& ACTION_LOG_FALSE
)))
784 progressbar_info("%s\n", expr_log(""));
786 expr_log_cmnd(LOG_DISABLE
);
790 return eval_expr(action
->expr
, action_data
);
795 * Read action file, passing each line to parse_action() for
798 * One action per line, of the form
799 * action(arg1,arg2)@expr(arg1,arg2)....
801 * Actions can be split across multiple lines using "\".
803 * Blank lines and comment lines indicated by # are supported.
805 int parse_action_true(char *s
)
807 return parse_action(s
, ACTION_LOG_TRUE
);
811 int parse_action_false(char *s
)
813 return parse_action(s
, ACTION_LOG_FALSE
);
817 int parse_action_verbose(char *s
)
819 return parse_action(s
, ACTION_LOG_VERBOSE
);
823 int parse_action_nonverbose(char *s
)
825 return parse_action(s
, ACTION_LOG_NONE
);
829 int read_action_file(char *filename
, int verbose
)
832 case ACTION_LOG_TRUE
:
833 return read_file(filename
, "action", parse_action_true
);
834 case ACTION_LOG_FALSE
:
835 return read_file(filename
, "action", parse_action_false
);
836 case ACTION_LOG_VERBOSE
:
837 return read_file(filename
, "action", parse_action_verbose
);
839 return read_file(filename
, "action", parse_action_nonverbose
);
845 * helper to evaluate whether action/test acts on this file type
847 static int file_type_match(int st_mode
, int type
)
851 return S_ISDIR(st_mode
);
853 return S_ISREG(st_mode
);
855 return S_ISREG(st_mode
) || S_ISDIR(st_mode
) ||
856 S_ISCHR(st_mode
) || S_ISBLK(st_mode
) ||
857 S_ISFIFO(st_mode
) || S_ISSOCK(st_mode
);
859 return S_ISLNK(st_mode
);
868 * General action evaluation code
876 void eval_actions(struct dir_info
*root
, struct dir_ent
*dir_ent
)
879 struct action_data action_data
;
880 int st_mode
= dir_ent
->inode
->buf
.st_mode
;
882 action_data
.name
= dir_ent
->name
;
883 action_data
.pathname
= strdup(pathname(dir_ent
));
884 action_data
.subpath
= strdup(subpathname(dir_ent
));
885 action_data
.buf
= &dir_ent
->inode
->buf
;
886 action_data
.depth
= dir_ent
->our_dir
->depth
;
887 action_data
.dir_ent
= dir_ent
;
888 action_data
.root
= root
;
890 for (i
= 0; i
< other_count
; i
++) {
891 struct action
*action
= &other_spec
[i
];
893 if (!file_type_match(st_mode
, action
->action
->file_types
))
894 /* action does not operate on this file type */
897 match
= eval_expr_top(action
, &action_data
);
900 action
->action
->run_action(action
, dir_ent
);
903 free(action_data
.pathname
);
904 free(action_data
.subpath
);
909 * Fragment specific action code
911 void *eval_frag_actions(struct dir_info
*root
, struct dir_ent
*dir_ent
)
914 struct action_data action_data
;
916 action_data
.name
= dir_ent
->name
;
917 action_data
.pathname
= strdup(pathname(dir_ent
));
918 action_data
.subpath
= strdup(subpathname(dir_ent
));
919 action_data
.buf
= &dir_ent
->inode
->buf
;
920 action_data
.depth
= dir_ent
->our_dir
->depth
;
921 action_data
.dir_ent
= dir_ent
;
922 action_data
.root
= root
;
924 for (i
= 0; i
< fragment_count
; i
++) {
925 match
= eval_expr_top(&fragment_spec
[i
], &action_data
);
927 free(action_data
.pathname
);
928 free(action_data
.subpath
);
929 return &fragment_spec
[i
].data
;
933 free(action_data
.pathname
);
934 free(action_data
.subpath
);
935 return &def_fragment
;
939 void *get_frag_action(void *fragment
)
941 struct action
*spec_list_end
= &fragment_spec
[fragment_count
];
942 struct action
*action
;
944 if (fragment
== NULL
)
945 return &def_fragment
;
947 if (fragment_count
== 0)
950 if (fragment
== &def_fragment
)
951 action
= &fragment_spec
[0] - 1;
953 action
= fragment
- offsetof(struct action
, data
);
955 if (++action
== spec_list_end
)
958 return &action
->data
;
963 * Exclude specific action code
965 int exclude_actions()
967 return exclude_count
;
971 int eval_exclude_actions(char *name
, char *pathname
, char *subpath
,
972 struct stat
*buf
, int depth
, struct dir_ent
*dir_ent
)
975 struct action_data action_data
;
977 action_data
.name
= name
;
978 action_data
.pathname
= pathname
;
979 action_data
.subpath
= subpath
;
980 action_data
.buf
= buf
;
981 action_data
.depth
= depth
;
982 action_data
.dir_ent
= dir_ent
;
984 for (i
= 0; i
< exclude_count
&& !match
; i
++)
985 match
= eval_expr_top(&exclude_spec
[i
], &action_data
);
992 * Fragment specific action code
994 static void frag_action(struct action
*action
, struct dir_ent
*dir_ent
)
996 struct inode_info
*inode
= dir_ent
->inode
;
998 inode
->no_fragments
= 0;
1001 static void no_frag_action(struct action
*action
, struct dir_ent
*dir_ent
)
1003 struct inode_info
*inode
= dir_ent
->inode
;
1005 inode
->no_fragments
= 1;
1008 static void always_frag_action(struct action
*action
, struct dir_ent
*dir_ent
)
1010 struct inode_info
*inode
= dir_ent
->inode
;
1012 inode
->always_use_fragments
= 1;
1015 static void no_always_frag_action(struct action
*action
, struct dir_ent
*dir_ent
)
1017 struct inode_info
*inode
= dir_ent
->inode
;
1019 inode
->always_use_fragments
= 0;
1024 * Compression specific action code
1026 static void comp_action(struct action
*action
, struct dir_ent
*dir_ent
)
1028 struct inode_info
*inode
= dir_ent
->inode
;
1030 inode
->noD
= inode
->noF
= 0;
1033 static void uncomp_action(struct action
*action
, struct dir_ent
*dir_ent
)
1035 struct inode_info
*inode
= dir_ent
->inode
;
1037 inode
->noD
= inode
->noF
= 1;
1042 * Uid/gid specific action code
1044 static long long parse_uid(char *arg
) {
1046 long long uid
= strtoll(arg
, &b
, 10);
1049 if (uid
< 0 || uid
>= (1LL << 32)) {
1050 SYNTAX_ERROR("Uid out of range\n");
1054 struct passwd
*passwd
= getpwnam(arg
);
1057 uid
= passwd
->pw_uid
;
1059 SYNTAX_ERROR("Invalid uid or unknown user\n");
1068 static long long parse_gid(char *arg
) {
1070 long long gid
= strtoll(arg
, &b
, 10);
1073 if (gid
< 0 || gid
>= (1LL << 32)) {
1074 SYNTAX_ERROR("Gid out of range\n");
1078 struct group
*group
= getgrnam(arg
);
1081 gid
= group
->gr_gid
;
1083 SYNTAX_ERROR("Invalid gid or unknown group\n");
1092 static int parse_uid_args(struct action_entry
*action
, int args
, char **argv
,
1096 struct uid_info
*uid_info
;
1098 uid
= parse_uid(argv
[0]);
1102 uid_info
= malloc(sizeof(struct uid_info
));
1103 if (uid_info
== NULL
)
1106 uid_info
->uid
= uid
;
1113 static int parse_gid_args(struct action_entry
*action
, int args
, char **argv
,
1117 struct gid_info
*gid_info
;
1119 gid
= parse_gid(argv
[0]);
1123 gid_info
= malloc(sizeof(struct gid_info
));
1124 if (gid_info
== NULL
)
1127 gid_info
->gid
= gid
;
1134 static int parse_guid_args(struct action_entry
*action
, int args
, char **argv
,
1138 struct guid_info
*guid_info
;
1140 uid
= parse_uid(argv
[0]);
1144 gid
= parse_gid(argv
[1]);
1148 guid_info
= malloc(sizeof(struct guid_info
));
1149 if (guid_info
== NULL
)
1152 guid_info
->uid
= uid
;
1153 guid_info
->gid
= gid
;
1160 static void uid_action(struct action
*action
, struct dir_ent
*dir_ent
)
1162 struct inode_info
*inode
= dir_ent
->inode
;
1163 struct uid_info
*uid_info
= action
->data
;
1165 inode
->buf
.st_uid
= uid_info
->uid
;
1168 static void gid_action(struct action
*action
, struct dir_ent
*dir_ent
)
1170 struct inode_info
*inode
= dir_ent
->inode
;
1171 struct gid_info
*gid_info
= action
->data
;
1173 inode
->buf
.st_gid
= gid_info
->gid
;
1176 static void guid_action(struct action
*action
, struct dir_ent
*dir_ent
)
1178 struct inode_info
*inode
= dir_ent
->inode
;
1179 struct guid_info
*guid_info
= action
->data
;
1181 inode
->buf
.st_uid
= guid_info
->uid
;
1182 inode
->buf
.st_gid
= guid_info
->gid
;
1188 * Mode specific action code
1190 static int parse_octal_mode_args(int args
, char **argv
,
1195 struct mode_data
*mode_data
;
1197 /* octal mode number? */
1198 n
= sscanf(argv
[0], "%o%n", &mode
, &bytes
);
1200 return -1; /* not an octal number arg */
1203 /* check there's no trailing junk */
1204 if (argv
[0][bytes
] != '\0') {
1205 SYNTAX_ERROR("Unexpected trailing bytes after octal "
1207 return 0; /* bad octal number arg */
1210 /* check there's only one argument */
1212 SYNTAX_ERROR("Octal mode number is first argument, "
1213 "expected one argument, got %d\n", args
);
1214 return 0; /* bad octal number arg */
1217 /* check mode is within range */
1219 SYNTAX_ERROR("Octal mode %o is out of range\n", mode
);
1220 return 0; /* bad octal number arg */
1223 mode_data
= malloc(sizeof(struct mode_data
));
1224 if (mode_data
== NULL
)
1227 mode_data
->operation
= ACTION_MODE_OCT
;
1228 mode_data
->mode
= mode
;
1229 mode_data
->next
= NULL
;
1237 * Parse symbolic mode of format [ugoa]*[[+-=]PERMS]+
1238 * PERMS = [rwxXst]+ or [ugo]
1240 static int parse_sym_mode_arg(char *arg
, struct mode_data
**head
,
1241 struct mode_data
**cur
)
1243 struct mode_data
*mode_data
;
1249 if (arg
[0] != 'u' && arg
[0] != 'g' && arg
[0] != 'o' && arg
[0] != 'a') {
1250 /* no ownership specifiers, default to a */
1252 goto parse_operation
;
1255 /* parse ownership specifiers */
1271 goto parse_operation
;
1277 /* trap a symbolic mode with just an ownership specification */
1279 SYNTAX_ERROR("Expected one of '+', '-' or '=', got EOF\n");
1283 while(*arg
!= '\0') {
1289 op
= ACTION_MODE_ADD
;
1292 op
= ACTION_MODE_REM
;
1295 op
= ACTION_MODE_SET
;
1298 SYNTAX_ERROR("Expected one of '+', '-' or '=', got "
1306 if (*arg
== 'u' || *arg
== 'g' || *arg
== 'o') {
1311 /* PERMS = [rwxXst]* */
1339 SYNTAX_ERROR("Unrecognised permission "
1349 mode_data
= malloc(sizeof(*mode_data
));
1350 if (mode_data
== NULL
)
1353 mode_data
->operation
= op
;
1354 mode_data
->mode
= mode
;
1355 mode_data
->mask
= mask
;
1357 mode_data
->next
= NULL
;
1360 (*cur
)->next
= mode_data
;
1363 *head
= *cur
= mode_data
;
1373 static int parse_sym_mode_args(struct action_entry
*action
, int args
,
1374 char **argv
, void **data
)
1377 struct mode_data
*head
= NULL
, *cur
= NULL
;
1379 for (i
= 0; i
< args
&& res
; i
++)
1380 res
= parse_sym_mode_arg(argv
[i
], &head
, &cur
);
1388 static int parse_mode_args(struct action_entry
*action
, int args
,
1389 char **argv
, void **data
)
1394 SYNTAX_ERROR("Mode action expects one or more arguments\n");
1398 res
= parse_octal_mode_args(args
, argv
, data
);
1400 /* Got an octal mode argument */
1402 else /* not an octal mode argument */
1403 return parse_sym_mode_args(action
, args
, argv
, data
);
1407 static int mode_execute(struct mode_data
*mode_data
, int st_mode
)
1411 for (;mode_data
; mode_data
= mode_data
->next
) {
1412 if (mode_data
->mode
< 0) {
1413 /* 'u', 'g' or 'o' */
1414 switch(-mode_data
->mode
) {
1416 mode
= (st_mode
>> 6) & 07;
1419 mode
= (st_mode
>> 3) & 07;
1422 mode
= st_mode
& 07;
1425 mode
= ((mode
<< 6) | (mode
<< 3) | mode
) &
1427 } else if (mode_data
->X
&&
1428 ((st_mode
& S_IFMT
) == S_IFDIR
||
1430 /* X permission, only takes effect if inode is a
1431 * directory or x is set for some owner */
1432 mode
= mode_data
->mode
| (0111 & mode_data
->mask
);
1434 mode
= mode_data
->mode
;
1436 switch(mode_data
->operation
) {
1437 case ACTION_MODE_OCT
:
1438 st_mode
= (st_mode
& S_IFMT
) | mode
;
1440 case ACTION_MODE_SET
:
1441 st_mode
= (st_mode
& ~mode_data
->mask
) | mode
;
1443 case ACTION_MODE_ADD
:
1446 case ACTION_MODE_REM
:
1455 static void mode_action(struct action
*action
, struct dir_ent
*dir_ent
)
1457 dir_ent
->inode
->buf
.st_mode
= mode_execute(action
->data
,
1458 dir_ent
->inode
->buf
.st_mode
);
1463 * Empty specific action code
1471 static int parse_empty_args(struct action_entry
*action
, int args
,
1472 char **argv
, void **data
)
1474 struct empty_data
*empty_data
;
1478 SYNTAX_ERROR("Empty action expects zero or one argument\n");
1482 if (args
== 0 || strcmp(argv
[0], "all") == 0)
1484 else if (strcmp(argv
[0], "source") == 0)
1486 else if (strcmp(argv
[0], "excluded") == 0)
1487 val
= EMPTY_EXCLUDED
;
1489 SYNTAX_ERROR("Empty action expects zero arguments, or one"
1490 "argument containing \"all\", \"source\", or \"excluded\""
1495 empty_data
= malloc(sizeof(*empty_data
));
1496 if (empty_data
== NULL
)
1499 empty_data
->val
= val
;
1506 int eval_empty_actions(struct dir_info
*root
, struct dir_ent
*dir_ent
)
1509 struct action_data action_data
;
1510 struct empty_data
*data
;
1511 struct dir_info
*dir
= dir_ent
->dir
;
1514 * Empty action only works on empty directories
1516 if (dir
->count
!= 0)
1519 action_data
.name
= dir_ent
->name
;
1520 action_data
.pathname
= strdup(pathname(dir_ent
));
1521 action_data
.subpath
= strdup(subpathname(dir_ent
));
1522 action_data
.buf
= &dir_ent
->inode
->buf
;
1523 action_data
.depth
= dir_ent
->our_dir
->depth
;
1524 action_data
.dir_ent
= dir_ent
;
1525 action_data
.root
= root
;
1527 for (i
= 0; i
< empty_count
&& !match
; i
++) {
1528 data
= empty_spec
[i
].data
;
1531 * determine the cause of the empty directory and evaluate
1532 * the empty action specified. Three empty actions:
1533 * - EMPTY_SOURCE: empty action triggers only if the directory
1534 * was originally empty, i.e directories that are empty
1535 * only due to excluding are ignored.
1536 * - EMPTY_EXCLUDED: empty action triggers only if the directory
1537 * is empty because of excluding, i.e. directories that
1538 * were originally empty are ignored.
1539 * - EMPTY_ALL (the default): empty action triggers if the
1540 * directory is empty, irrespective of the reason, i.e.
1541 * the directory could have been originally empty or could
1542 * be empty due to excluding.
1544 if ((data
->val
== EMPTY_EXCLUDED
&& !dir
->excluded
) ||
1545 (data
->val
== EMPTY_SOURCE
&& dir
->excluded
))
1548 match
= eval_expr_top(&empty_spec
[i
], &action_data
);
1551 free(action_data
.pathname
);
1552 free(action_data
.subpath
);
1559 * Move specific action code
1561 static struct move_ent
*move_list
= NULL
;
1570 static char *move_pathname(struct move_ent
*move
)
1572 struct dir_info
*dest
;
1573 char *name
, *pathname
;
1576 dest
= (move
->ops
& ACTION_MOVE_MOVE
) ?
1577 move
->dest
: move
->dir_ent
->our_dir
;
1578 name
= (move
->ops
& ACTION_MOVE_RENAME
) ?
1579 move
->name
: move
->dir_ent
->name
;
1581 if(dest
->subpath
[0] != '\0')
1582 res
= asprintf(&pathname
, "%s/%s", dest
->subpath
, name
);
1584 res
= asprintf(&pathname
, "/%s", name
);
1587 BAD_ERROR("asprintf failed in move_pathname\n");
1593 static char *get_comp(char **pathname
)
1595 char *path
= *pathname
, *start
;
1604 while(*path
!= '/' && *path
!= '\0')
1608 return strndup(start
, path
- start
);
1612 static struct dir_ent
*lookup_comp(char *comp
, struct dir_info
*dest
)
1614 struct dir_ent
*dir_ent
;
1616 for(dir_ent
= dest
->list
; dir_ent
; dir_ent
= dir_ent
->next
)
1617 if(strcmp(comp
, dir_ent
->name
) == 0)
1624 void eval_move(struct action_data
*action_data
, struct move_ent
*move
,
1625 struct dir_info
*root
, struct dir_ent
*dir_ent
, char *pathname
)
1627 struct dir_info
*dest
, *source
= dir_ent
->our_dir
;
1628 struct dir_ent
*comp_ent
;
1629 char *comp
, *path
= pathname
;
1632 * Walk pathname to get the destination directory
1634 * Like the mv command, if the last component exists and it
1635 * is a directory, then move the file into that directory,
1636 * otherwise, move the file into parent directory of the last
1637 * component and rename to the last component.
1639 if (pathname
[0] == '/')
1640 /* absolute pathname, walk from root directory */
1643 /* relative pathname, walk from current directory */
1646 for(comp
= get_comp(&pathname
); comp
; free(comp
),
1647 comp
= get_comp(&pathname
)) {
1649 if (strcmp(comp
, ".") == 0)
1652 if (strcmp(comp
, "..") == 0) {
1653 /* if we're in the root directory then ignore */
1655 dest
= dest
->dir_ent
->our_dir
;
1660 * Look up comp in current directory, if it exists and it is a
1661 * directory continue walking the pathname, otherwise exit,
1662 * we've walked as far as we can go, normally this is because
1663 * we've arrived at the leaf component which we are going to
1666 comp_ent
= lookup_comp(comp
, dest
);
1667 if (comp_ent
== NULL
|| (comp_ent
->inode
->buf
.st_mode
& S_IFMT
)
1671 dest
= comp_ent
->dir
;
1675 /* Leaf component? If so we're renaming to this */
1676 char *remainder
= get_comp(&pathname
);
1681 * trying to move source to a subdirectory of
1682 * comp, but comp either doesn't exist, or it isn't
1683 * a directory, which is impossible
1685 if (comp_ent
== NULL
)
1686 ERROR("Move action: cannot move %s to %s, no "
1687 "such directory %s\n",
1688 action_data
->subpath
, path
, comp
);
1690 ERROR("Move action: cannot move %s to %s, %s "
1691 "is not a directory\n",
1692 action_data
->subpath
, path
, comp
);
1698 * Multiple move actions triggering on one file can be merged
1699 * if one is a RENAME and the other is a MOVE. Multiple RENAMEs
1700 * can only merge if they're doing the same thing
1702 if(move
->ops
& ACTION_MOVE_RENAME
) {
1703 if(strcmp(comp
, move
->name
) != 0) {
1704 char *conf_path
= move_pathname(move
);
1705 ERROR("Move action: Cannot move %s to %s, "
1706 "conflicting move, already moving "
1707 "to %s via another move action!\n",
1708 action_data
->subpath
, path
, conf_path
);
1716 move
->ops
|= ACTION_MOVE_RENAME
;
1720 if(dest
!= source
) {
1722 * Multiple move actions triggering on one file can be merged
1723 * if one is a RENAME and the other is a MOVE. Multiple MOVEs
1724 * can only merge if they're doing the same thing
1726 if(move
->ops
& ACTION_MOVE_MOVE
) {
1727 if(dest
!= move
->dest
) {
1728 char *conf_path
= move_pathname(move
);
1729 ERROR("Move action: Cannot move %s to %s, "
1730 "conflicting move, already moving "
1731 "to %s via another move action!\n",
1732 action_data
->subpath
, path
, conf_path
);
1738 move
->ops
|= ACTION_MOVE_MOVE
;
1744 static int subdirectory(struct dir_info
*source
, struct dir_info
*dest
)
1749 return strlen(source
->subpath
) <= strlen(dest
->subpath
) &&
1750 (dest
->subpath
[strlen(source
->subpath
)] == '/' ||
1751 dest
->subpath
[strlen(source
->subpath
)] == '\0') &&
1752 strncmp(source
->subpath
, dest
->subpath
,
1753 strlen(source
->subpath
)) == 0;
1757 void eval_move_actions(struct dir_info
*root
, struct dir_ent
*dir_ent
)
1760 struct action_data action_data
;
1761 struct move_ent
*move
= NULL
;
1763 action_data
.name
= dir_ent
->name
;
1764 action_data
.pathname
= strdup(pathname(dir_ent
));
1765 action_data
.subpath
= strdup(subpathname(dir_ent
));
1766 action_data
.buf
= &dir_ent
->inode
->buf
;
1767 action_data
.depth
= dir_ent
->our_dir
->depth
;
1768 action_data
.dir_ent
= dir_ent
;
1769 action_data
.root
= root
;
1772 * Evaluate each move action against the current file. For any
1773 * move actions that match don't actually perform the move now, but,
1774 * store it, and execute all the stored move actions together once the
1775 * directory scan is complete. This is done to ensure each separate
1776 * move action does not nondeterministically interfere with other move
1777 * actions. Each move action is considered to act independently, and
1778 * each move action sees the directory tree in the same state.
1780 for (i
= 0; i
< move_count
; i
++) {
1781 struct action
*action
= &move_spec
[i
];
1782 int match
= eval_expr_top(action
, &action_data
);
1786 move
= malloc(sizeof(*move
));
1791 move
->dir_ent
= dir_ent
;
1793 eval_move(&action_data
, move
, root
, dir_ent
,
1799 struct dir_ent
*comp_ent
;
1800 struct dir_info
*dest
;
1804 * Move contains the result of all triggered move actions.
1805 * Check the destination doesn't already exist
1807 if(move
->ops
== 0) {
1812 dest
= (move
->ops
& ACTION_MOVE_MOVE
) ?
1813 move
->dest
: dir_ent
->our_dir
;
1814 name
= (move
->ops
& ACTION_MOVE_RENAME
) ?
1815 move
->name
: dir_ent
->name
;
1816 comp_ent
= lookup_comp(name
, dest
);
1818 char *conf_path
= move_pathname(move
);
1819 ERROR("Move action: Cannot move %s to %s, "
1820 "destination already exists\n",
1821 action_data
.subpath
, conf_path
);
1828 * If we're moving a directory, check we're not moving it to a
1829 * subdirectory of itself
1831 if(subdirectory(dir_ent
->dir
, dest
)) {
1832 char *conf_path
= move_pathname(move
);
1833 ERROR("Move action: Cannot move %s to %s, this is a "
1834 "subdirectory of itself\n",
1835 action_data
.subpath
, conf_path
);
1840 move
->next
= move_list
;
1845 free(action_data
.pathname
);
1846 free(action_data
.subpath
);
1850 static void move_dir(struct dir_ent
*dir_ent
)
1852 struct dir_info
*dir
= dir_ent
->dir
;
1853 struct dir_ent
*comp_ent
;
1855 /* update our directory's subpath name */
1857 dir
->subpath
= strdup(subpathname(dir_ent
));
1859 /* recursively update the subpaths of any sub-directories */
1860 for(comp_ent
= dir
->list
; comp_ent
; comp_ent
= comp_ent
->next
)
1866 static void move_file(struct move_ent
*move_ent
)
1868 struct dir_ent
*dir_ent
= move_ent
->dir_ent
;
1870 if(move_ent
->ops
& ACTION_MOVE_MOVE
) {
1871 struct dir_ent
*comp_ent
, *prev
= NULL
;
1872 struct dir_info
*source
= dir_ent
->our_dir
,
1873 *dest
= move_ent
->dest
;
1874 char *filename
= pathname(dir_ent
);
1877 * If we're moving a directory, check we're not moving it to a
1878 * subdirectory of itself
1880 if(subdirectory(dir_ent
->dir
, dest
)) {
1881 char *conf_path
= move_pathname(move_ent
);
1882 ERROR("Move action: Cannot move %s to %s, this is a "
1883 "subdirectory of itself\n",
1884 subpathname(dir_ent
), conf_path
);
1889 /* Remove the file from source directory */
1890 for(comp_ent
= source
->list
; comp_ent
!= dir_ent
;
1891 prev
= comp_ent
, comp_ent
= comp_ent
->next
);
1894 prev
->next
= comp_ent
->next
;
1896 source
->list
= comp_ent
->next
;
1899 if((comp_ent
->inode
->buf
.st_mode
& S_IFMT
) == S_IFDIR
)
1900 source
->directory_count
--;
1902 /* Add the file to dest directory */
1903 comp_ent
->next
= dest
->list
;
1904 dest
->list
= comp_ent
;
1905 comp_ent
->our_dir
= dest
;
1908 if((comp_ent
->inode
->buf
.st_mode
& S_IFMT
) == S_IFDIR
)
1909 dest
->directory_count
++;
1912 * We've moved the file, and so we can't now use the
1913 * parent directory's pathname to calculate the pathname
1915 if(dir_ent
->nonstandard_pathname
== NULL
) {
1916 dir_ent
->nonstandard_pathname
= strdup(filename
);
1917 if(dir_ent
->source_name
) {
1918 free(dir_ent
->source_name
);
1919 dir_ent
->source_name
= NULL
;
1924 if(move_ent
->ops
& ACTION_MOVE_RENAME
) {
1926 * If we're using name in conjunction with the parent
1927 * directory's pathname to calculate the pathname, we need
1928 * to use source_name to override. Otherwise it's already being
1931 if(dir_ent
->nonstandard_pathname
== NULL
&&
1932 dir_ent
->source_name
== NULL
)
1933 dir_ent
->source_name
= dir_ent
->name
;
1935 free(dir_ent
->name
);
1937 dir_ent
->name
= move_ent
->name
;
1942 * dir_ent is a directory, and we have to recursively fix-up
1943 * its subpath, and the subpaths of all of its sub-directories
1949 void do_move_actions()
1952 struct move_ent
*temp
= move_list
;
1953 struct dir_info
*dest
= (move_list
->ops
& ACTION_MOVE_MOVE
) ?
1954 move_list
->dest
: move_list
->dir_ent
->our_dir
;
1955 char *name
= (move_list
->ops
& ACTION_MOVE_RENAME
) ?
1956 move_list
->name
: move_list
->dir_ent
->name
;
1957 struct dir_ent
*comp_ent
= lookup_comp(name
, dest
);
1959 char *conf_path
= move_pathname(move_list
);
1960 ERROR("Move action: Cannot move %s to %s, "
1961 "destination already exists\n",
1962 subpathname(move_list
->dir_ent
), conf_path
);
1965 move_file(move_list
);
1967 move_list
= move_list
->next
;
1974 * Prune specific action code
1982 int eval_prune_actions(struct dir_info
*root
, struct dir_ent
*dir_ent
)
1985 struct action_data action_data
;
1987 action_data
.name
= dir_ent
->name
;
1988 action_data
.pathname
= strdup(pathname(dir_ent
));
1989 action_data
.subpath
= strdup(subpathname(dir_ent
));
1990 action_data
.buf
= &dir_ent
->inode
->buf
;
1991 action_data
.depth
= dir_ent
->our_dir
->depth
;
1992 action_data
.dir_ent
= dir_ent
;
1993 action_data
.root
= root
;
1995 for (i
= 0; i
< prune_count
&& !match
; i
++)
1996 match
= eval_expr_top(&prune_spec
[i
], &action_data
);
1998 free(action_data
.pathname
);
1999 free(action_data
.subpath
);
2006 * Noop specific action code
2008 static void noop_action(struct action
*action
, struct dir_ent
*dir_ent
)
2014 * General test evaluation code
2018 * A number can be of the form [range]number[size]
2019 * [range] is either:
2020 * '<' or '-', match on less than number
2021 * '>' or '+', match on greater than number
2022 * '' (nothing), match on exactly number
2024 * '' (nothing), number
2025 * 'k' or 'K', number * 2^10
2026 * 'm' or 'M', number * 2^20
2027 * 'g' or 'G', number * 2^30
2029 static int parse_number(char *start
, long long *size
, int *range
, char **error
)
2034 if (*start
== '>' || *start
== '+') {
2035 *range
= NUM_GREATER
;
2037 } else if (*start
== '<' || *start
== '-') {
2043 errno
= 0; /* To enable failure after call to be determined */
2044 number
= strtoll(start
, &end
, 10);
2046 if((errno
== ERANGE
&& (number
== LLONG_MAX
|| number
== LLONG_MIN
))
2047 || (errno
!= 0 && number
== 0)) {
2048 /* long long underflow or overflow in conversion, or other
2050 * Note: we don't check for LLONG_MIN and LLONG_MAX only
2051 * because strtoll can validly return that if the
2052 * user used these values
2054 *error
= "Long long underflow, overflow or other conversion "
2060 /* Couldn't read any number */
2061 *error
= "Number expected";
2076 if (end
[1] != '\0') {
2077 *error
= "Trailing junk after size specifier";
2085 *error
= "Trailing junk after number";
2095 static int parse_number_arg(struct test_entry
*test
, struct atom
*atom
)
2097 struct test_number_arg
*number
;
2101 int res
= parse_number(atom
->argv
[0], &size
, &range
, &error
);
2104 TEST_SYNTAX_ERROR(test
, 0, "%s\n", error
);
2108 number
= malloc(sizeof(*number
));
2112 number
->range
= range
;
2113 number
->size
= size
;
2115 atom
->data
= number
;
2121 static int parse_range_args(struct test_entry
*test
, struct atom
*atom
)
2123 struct test_range_args
*range
;
2124 long long start
, end
;
2129 res
= parse_number(atom
->argv
[0], &start
, &type
, &error
);
2131 TEST_SYNTAX_ERROR(test
, 0, "%s\n", error
);
2135 if (type
!= NUM_EQ
) {
2136 TEST_SYNTAX_ERROR(test
, 0, "Range specifier (<, >, -, +) not "
2141 res
= parse_number(atom
->argv
[1], &end
, &type
, &error
);
2143 TEST_SYNTAX_ERROR(test
, 1, "%s\n", error
);
2147 if (type
!= NUM_EQ
) {
2148 TEST_SYNTAX_ERROR(test
, 1, "Range specifier (<, >, -, +) not "
2153 range
= malloc(sizeof(*range
));
2157 range
->start
= start
;
2167 * Generic test code macro
2169 #define TEST_FN(NAME, MATCH, CODE) \
2170 static int NAME##_fn(struct atom *atom, struct action_data *action_data) \
2172 /* test operates on MATCH file types only */ \
2173 if (!file_type_match(action_data->buf->st_mode, MATCH)) \
2180 * Generic test code macro testing VAR for size (eq, less than, greater than)
2182 #define TEST_VAR_FN(NAME, MATCH, VAR) TEST_FN(NAME, MATCH, \
2185 struct test_number_arg *number = atom->data; \
2187 switch (number->range) { \
2189 match = VAR == number->size; \
2192 match = VAR < number->size; \
2195 match = VAR > number->size; \
2204 * Generic test code macro testing VAR for range [x, y] (value between x and y
2207 #define TEST_VAR_RANGE_FN(NAME, MATCH, VAR) TEST_FN(NAME##_range, MATCH, \
2209 struct test_range_args *range = atom->data; \
2211 return range->start <= VAR && VAR <= range->end; \
2216 * Name, Pathname and Subpathname test specific code
2220 * Add a leading "/" if subpathname and pathname lacks it
2222 static int check_pathname(struct test_entry
*test
, struct atom
*atom
)
2227 if(atom
->argv
[0][0] != '/') {
2228 res
= asprintf(&name
, "/%s", atom
->argv
[0]);
2230 BAD_ERROR("asprintf failed in check_pathname\n");
2232 free(atom
->argv
[0]);
2233 atom
->argv
[0] = name
;
2240 TEST_FN(name
, ACTION_ALL_LNK
, \
2241 return fnmatch(atom
->argv
[0], action_data
->name
,
2242 FNM_PATHNAME
|FNM_PERIOD
|FNM_EXTMATCH
) == 0;)
2244 TEST_FN(pathname
, ACTION_ALL_LNK
, \
2245 return fnmatch(atom
->argv
[0], action_data
->subpath
,
2246 FNM_PATHNAME
|FNM_PERIOD
|FNM_EXTMATCH
) == 0;)
2249 static int count_components(char *path
)
2253 for (count
= 0; *path
!= '\0'; count
++) {
2254 while (*path
== '/')
2257 while (*path
!= '\0' && *path
!= '/')
2265 static char *get_start(char *s
, int n
)
2270 for (count
= 0; *path
!= '\0' && count
< n
; count
++) {
2271 while (*path
== '/')
2274 while (*path
!= '\0' && *path
!= '/')
2285 static int subpathname_fn(struct atom
*atom
, struct action_data
*action_data
)
2287 return fnmatch(atom
->argv
[0], get_start(strdupa(action_data
->subpath
),
2288 count_components(atom
->argv
[0])),
2289 FNM_PATHNAME
|FNM_PERIOD
|FNM_EXTMATCH
) == 0;
2293 * Inode attribute test operations using generic
2294 * TEST_VAR_FN(test name, file scope, attribute name) macro.
2295 * This is for tests that do not need to be specially handled in any way.
2296 * They just take a variable and compare it against a number.
2298 TEST_VAR_FN(filesize
, ACTION_REG
, action_data
->buf
->st_size
)
2300 TEST_VAR_FN(dirsize
, ACTION_DIR
, action_data
->buf
->st_size
)
2302 TEST_VAR_FN(size
, ACTION_ALL_LNK
, action_data
->buf
->st_size
)
2304 TEST_VAR_FN(inode
, ACTION_ALL_LNK
, action_data
->buf
->st_ino
)
2306 TEST_VAR_FN(nlink
, ACTION_ALL_LNK
, action_data
->buf
->st_nlink
)
2308 TEST_VAR_FN(fileblocks
, ACTION_REG
, action_data
->buf
->st_blocks
)
2310 TEST_VAR_FN(dirblocks
, ACTION_DIR
, action_data
->buf
->st_blocks
)
2312 TEST_VAR_FN(blocks
, ACTION_ALL_LNK
, action_data
->buf
->st_blocks
)
2314 TEST_VAR_FN(dircount
, ACTION_DIR
, action_data
->dir_ent
->dir
->count
)
2316 TEST_VAR_FN(depth
, ACTION_ALL_LNK
, action_data
->depth
)
2318 TEST_VAR_RANGE_FN(filesize
, ACTION_REG
, action_data
->buf
->st_size
)
2320 TEST_VAR_RANGE_FN(dirsize
, ACTION_DIR
, action_data
->buf
->st_size
)
2322 TEST_VAR_RANGE_FN(size
, ACTION_ALL_LNK
, action_data
->buf
->st_size
)
2324 TEST_VAR_RANGE_FN(inode
, ACTION_ALL_LNK
, action_data
->buf
->st_ino
)
2326 TEST_VAR_RANGE_FN(nlink
, ACTION_ALL_LNK
, action_data
->buf
->st_nlink
)
2328 TEST_VAR_RANGE_FN(fileblocks
, ACTION_REG
, action_data
->buf
->st_blocks
)
2330 TEST_VAR_RANGE_FN(dirblocks
, ACTION_DIR
, action_data
->buf
->st_blocks
)
2332 TEST_VAR_RANGE_FN(blocks
, ACTION_ALL_LNK
, action_data
->buf
->st_blocks
)
2334 TEST_VAR_RANGE_FN(gid
, ACTION_ALL_LNK
, action_data
->buf
->st_gid
)
2336 TEST_VAR_RANGE_FN(uid
, ACTION_ALL_LNK
, action_data
->buf
->st_uid
)
2338 TEST_VAR_RANGE_FN(depth
, ACTION_ALL_LNK
, action_data
->depth
)
2340 TEST_VAR_RANGE_FN(dircount
, ACTION_DIR
, action_data
->dir_ent
->dir
->count
)
2343 * uid specific test code
2345 TEST_VAR_FN(uid
, ACTION_ALL_LNK
, action_data
->buf
->st_uid
)
2347 static int parse_uid_arg(struct test_entry
*test
, struct atom
*atom
)
2349 struct test_number_arg
*number
;
2354 if(parse_number(atom
->argv
[0], &size
, &range
, &error
)) {
2355 /* managed to fully parse argument as a number */
2356 if(size
< 0 || size
> (((long long) 1 << 32) - 1)) {
2357 TEST_SYNTAX_ERROR(test
, 1, "Numeric uid out of "
2362 /* couldn't parse (fully) as a number, is it a user name? */
2363 struct passwd
*uid
= getpwnam(atom
->argv
[0]);
2368 TEST_SYNTAX_ERROR(test
, 1, "Invalid uid or unknown "
2374 number
= malloc(sizeof(*number
));
2378 number
->range
= range
;
2381 atom
->data
= number
;
2388 * gid specific test code
2390 TEST_VAR_FN(gid
, ACTION_ALL_LNK
, action_data
->buf
->st_gid
)
2392 static int parse_gid_arg(struct test_entry
*test
, struct atom
*atom
)
2394 struct test_number_arg
*number
;
2399 if(parse_number(atom
->argv
[0], &size
, &range
, &error
)) {
2400 /* managed to fully parse argument as a number */
2401 if(size
< 0 || size
> (((long long) 1 << 32) - 1)) {
2402 TEST_SYNTAX_ERROR(test
, 1, "Numeric gid out of "
2407 /* couldn't parse (fully) as a number, is it a group name? */
2408 struct group
*gid
= getgrnam(atom
->argv
[0]);
2413 TEST_SYNTAX_ERROR(test
, 1, "Invalid gid or unknown "
2419 number
= malloc(sizeof(*number
));
2423 number
->range
= range
;
2426 atom
->data
= number
;
2433 * Type test specific code
2435 struct type_entry type_table
[] = {
2447 static int parse_type_arg(struct test_entry
*test
, struct atom
*atom
)
2451 if (strlen(atom
->argv
[0]) != 1)
2454 for(i
= 0; type_table
[i
].type
!= 0; i
++)
2455 if (type_table
[i
].type
== atom
->argv
[0][0])
2458 atom
->data
= &type_table
[i
];
2460 if(type_table
[i
].type
!= 0)
2464 TEST_SYNTAX_ERROR(test
, 0, "Unexpected file type, expected 'f', 'd', "
2465 "'c', 'b', 'l', 's' or 'p'\n");
2470 static int type_fn(struct atom
*atom
, struct action_data
*action_data
)
2472 struct type_entry
*type
= atom
->data
;
2474 return (action_data
->buf
->st_mode
& S_IFMT
) == type
->value
;
2479 * True test specific code
2481 static int true_fn(struct atom
*atom
, struct action_data
*action_data
)
2488 * False test specific code
2490 static int false_fn(struct atom
*atom
, struct action_data
*action_data
)
2497 * File test specific code
2499 static int parse_file_arg(struct test_entry
*test
, struct atom
*atom
)
2502 regex_t
*preg
= malloc(sizeof(regex_t
));
2507 res
= regcomp(preg
, atom
->argv
[0], REG_EXTENDED
);
2509 char str
[1024]; /* overflow safe */
2511 regerror(res
, preg
, str
, 1024);
2513 TEST_SYNTAX_ERROR(test
, 0, "invalid regex \"%s\" because "
2514 "\"%s\"\n", atom
->argv
[0], str
);
2524 static int file_fn(struct atom
*atom
, struct action_data
*action_data
)
2526 int child
, res
, size
= 0, status
;
2528 char *buffer
= NULL
;
2529 regex_t
*preg
= atom
->data
;
2533 BAD_ERROR("file_fn pipe failed\n");
2537 BAD_ERROR("file_fn fork_failed\n");
2542 * Connect stdout to pipefd[1] and execute file command
2544 close(STDOUT_FILENO
);
2545 res
= dup(pipefd
[1]);
2549 execlp("file", "file", "-b", action_data
->pathname
,
2555 * Parent process. Read stdout from file command
2560 buffer
= realloc(buffer
, size
+ 512);
2564 res
= read_bytes(pipefd
[0], buffer
+ size
, 512);
2567 BAD_ERROR("file_fn pipe read error\n");
2571 } while (res
== 512);
2573 size
= size
+ res
- 512;
2575 buffer
[size
] = '\0';
2577 res
= waitpid(child
, &status
, 0);
2580 BAD_ERROR("file_fn waitpid failed\n");
2582 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0)
2583 BAD_ERROR("file_fn file returned error\n");
2587 res
= regexec(preg
, buffer
, (size_t) 0, NULL
, 0);
2596 * Exec test specific code
2598 static int exec_fn(struct atom
*atom
, struct action_data
*action_data
)
2600 int child
, i
, res
, status
;
2604 BAD_ERROR("exec_fn fork_failed\n");
2609 * redirect stdin, stdout & stderr to /dev/null and
2610 * execute atom->argv[0]
2612 int fd
= open("/dev/null", O_RDWR
);
2616 close(STDIN_FILENO
);
2617 close(STDOUT_FILENO
);
2618 close(STDERR_FILENO
);
2619 for(i
= 0; i
< 3; i
++) {
2627 * Create environment variables
2628 * NAME: name of file
2629 * PATHNAME: pathname of file relative to squashfs root
2630 * SOURCE_PATHNAME: the pathname of the file in the source
2633 res
= setenv("NAME", action_data
->name
, 1);
2637 res
= setenv("PATHNAME", action_data
->subpath
, 1);
2641 res
= setenv("SOURCE_PATHNAME", action_data
->pathname
, 1);
2645 execl("/bin/sh", "sh", "-c", atom
->argv
[0], (char *) NULL
);
2653 res
= waitpid(child
, &status
, 0);
2656 BAD_ERROR("exec_fn waitpid failed\n");
2658 return WIFEXITED(status
) ? WEXITSTATUS(status
) == 0 : 0;
2663 * Symbolic link specific test code
2667 * Walk the supplied pathname and return the directory entry corresponding
2668 * to the pathname. If any symlinks are encountered whilst walking the
2669 * pathname, then recursively walk these, to obtain the fully
2670 * dereferenced canonicalised directory entry.
2672 * If follow_path fails to walk a pathname either because a component
2673 * doesn't exist, it is a non directory component when a directory
2674 * component is expected, a symlink with an absolute path is encountered,
2675 * or a symlink is encountered which cannot be recursively walked due to
2676 * the above failures, then return NULL.
2678 static struct dir_ent
*follow_path(struct dir_info
*dir
, char *pathname
)
2680 char *comp
, *path
= pathname
;
2681 struct dir_ent
*dir_ent
= NULL
;
2683 /* We cannot follow absolute paths */
2684 if(pathname
[0] == '/')
2687 for(comp
= get_comp(&path
); comp
; free(comp
), comp
= get_comp(&path
)) {
2688 if(strcmp(comp
, ".") == 0)
2691 if(strcmp(comp
, "..") == 0) {
2692 /* Move to parent if we're not in the root directory */
2693 if(dir
->depth
> 1) {
2694 dir
= dir
->dir_ent
->our_dir
;
2695 dir_ent
= NULL
; /* lazily eval at loop exit */
2698 /* Failed to walk pathname */
2702 /* Lookup comp in current directory */
2703 dir_ent
= lookup_comp(comp
, dir
);
2705 /* Doesn't exist, failed to walk pathname */
2708 if((dir_ent
->inode
->buf
.st_mode
& S_IFMT
) == S_IFLNK
) {
2709 /* Symbolic link, try to walk it */
2710 dir_ent
= follow_path(dir
, dir_ent
->inode
->symlink
);
2712 /* Failed to follow symlink */
2716 if((dir_ent
->inode
->buf
.st_mode
& S_IFMT
) != S_IFDIR
)
2717 /* Cannot walk further */
2723 /* We will have exited the loop either because we've processed
2724 * all the components, which means we've successfully walked the
2725 * pathname, or because we've hit a non-directory, in which case
2726 * it's success if this is the leaf component */
2729 comp
= get_comp(&path
);
2732 /* Not a leaf component */
2735 /* Fully walked pathname, dir_ent contains correct value unless
2736 * we've walked to the parent ("..") in which case we need
2737 * to resolve it here */
2739 dir_ent
= dir
->dir_ent
;
2746 static int exists_fn(struct atom
*atom
, struct action_data
*action_data
)
2749 * Test if a symlink exists within the output filesystem, that is,
2750 * the symlink has a relative path, and the relative path refers
2751 * to an entry within the output filesystem.
2753 * This test function evaluates the path for symlinks - that is it
2754 * follows any symlinks in the path (and any symlinks that it contains
2755 * etc.), to discover the fully dereferenced canonicalised relative
2758 * If any symlinks within the path do not exist or are absolute
2759 * then the symlink is considered to not exist, as it cannot be
2760 * fully dereferenced.
2762 * exists operates on symlinks only, other files by definition
2765 if (!file_type_match(action_data
->buf
->st_mode
, ACTION_LNK
))
2768 /* dereference the symlink, and return TRUE if it exists */
2769 return follow_path(action_data
->dir_ent
->our_dir
,
2770 action_data
->dir_ent
->inode
->symlink
) ? 1 : 0;
2774 static int absolute_fn(struct atom
*atom
, struct action_data
*action_data
)
2777 * Test if a symlink has an absolute path, which by definition
2778 * means the symbolic link may be broken (even if the absolute path
2779 * does point into the filesystem being squashed, because the resultant
2780 * filesystem can be mounted/unsquashed anywhere, it is unlikely the
2781 * absolute path will still point to the right place). If you know that
2782 * an absolute symlink will point to the right place then you don't need
2783 * to use this function, and/or these symlinks can be excluded by
2784 * use of other test operators.
2786 * absolute operates on symlinks only, other files by definition
2787 * don't have problems
2789 if (!file_type_match(action_data
->buf
->st_mode
, ACTION_LNK
))
2792 return action_data
->dir_ent
->inode
->symlink
[0] == '/';
2796 static int parse_expr_argX(struct test_entry
*test
, struct atom
*atom
,
2799 /* Call parse_expr to parse argument, which should be an expression */
2801 /* save the current parser state */
2802 char *save_cur_ptr
= cur_ptr
;
2803 char *save_source
= source
;
2805 cur_ptr
= source
= atom
->argv
[argno
];
2806 atom
->data
= parse_expr(0);
2808 cur_ptr
= save_cur_ptr
;
2809 source
= save_source
;
2811 if(atom
->data
== NULL
) {
2812 /* parse_expr(0) will have reported the exact syntax error,
2813 * but, because we recursively evaluated the expression, it
2814 * will have been reported without the context of the stat
2815 * test(). So here additionally report our failure to parse
2816 * the expression in the stat() test to give context */
2817 TEST_SYNTAX_ERROR(test
, 0, "Failed to parse expression\n");
2825 static int parse_expr_arg0(struct test_entry
*test
, struct atom
*atom
)
2827 return parse_expr_argX(test
, atom
, 0);
2831 static int parse_expr_arg1(struct test_entry
*test
, struct atom
*atom
)
2833 return parse_expr_argX(test
, atom
, 1);
2837 static int stat_fn(struct atom
*atom
, struct action_data
*action_data
)
2840 struct action_data eval_action
;
2843 /* evaluate the expression using the context of the inode
2844 * pointed to by the symlink. This allows the inode attributes
2845 * of the file pointed to by the symlink to be evaluated, rather
2846 * than the symlink itself.
2848 * Note, stat() deliberately does not evaluate the pathname, name or
2849 * depth of the symlink, these are left with the symlink values.
2850 * This allows stat() to be used on any symlink, rather than
2851 * just symlinks which are contained (if the symlink is *not*
2852 * contained then pathname, name and depth are meaningless as they
2853 * are relative to the filesystem being squashed). */
2855 /* if this isn't a symlink then stat will just return the current
2856 * information, i.e. stat(expr) == expr. This is harmless and
2857 * is better than returning TRUE or FALSE in a non symlink case */
2858 res
= stat(action_data
->pathname
, &buf
);
2860 if(expr_log_cmnd(LOG_ENABLED
)) {
2861 expr_log(atom
->test
->name
);
2869 /* fill in the inode values of the file pointed to by the
2870 * symlink, but, leave everything else the same */
2871 memcpy(&eval_action
, action_data
, sizeof(struct action_data
));
2872 eval_action
.buf
= &buf
;
2874 if(expr_log_cmnd(LOG_ENABLED
)) {
2875 expr_log(atom
->test
->name
);
2877 match
= eval_expr_log(atom
->data
, &eval_action
);
2880 match
= eval_expr(atom
->data
, &eval_action
);
2886 static int readlink_fn(struct atom
*atom
, struct action_data
*action_data
)
2889 struct dir_ent
*dir_ent
;
2890 struct action_data eval_action
;
2892 /* Dereference the symlink and evaluate the expression in the
2893 * context of the file pointed to by the symlink.
2894 * All attributes are updated to refer to the file that is pointed to.
2895 * Thus the inode attributes, pathname, name and depth all refer to
2896 * the dereferenced file, and not the symlink.
2898 * If the symlink cannot be dereferenced because it doesn't exist in
2899 * the output filesystem, or due to some other failure to
2900 * walk the pathname (see follow_path above), then FALSE is returned.
2902 * If you wish to evaluate the inode attributes of symlinks which
2903 * exist in the source filestem (but not in the output filesystem then
2904 * use stat instead (see above).
2906 * readlink operates on symlinks only */
2907 if (!file_type_match(action_data
->buf
->st_mode
, ACTION_LNK
))
2910 /* dereference the symlink, and get the directory entry it points to */
2911 dir_ent
= follow_path(action_data
->dir_ent
->our_dir
,
2912 action_data
->dir_ent
->inode
->symlink
);
2916 eval_action
.name
= dir_ent
->name
;
2917 eval_action
.pathname
= strdup(pathname(dir_ent
));
2918 eval_action
.subpath
= strdup(subpathname(dir_ent
));
2919 eval_action
.buf
= &dir_ent
->inode
->buf
;
2920 eval_action
.depth
= dir_ent
->our_dir
->depth
;
2921 eval_action
.dir_ent
= dir_ent
;
2922 eval_action
.root
= action_data
->root
;
2924 if(expr_log_cmnd(LOG_ENABLED
)) {
2925 expr_log(atom
->test
->name
);
2927 match
= eval_expr_log(atom
->data
, &eval_action
);
2930 match
= eval_expr(atom
->data
, &eval_action
);
2932 free(eval_action
.pathname
);
2933 free(eval_action
.subpath
);
2938 if(expr_log_cmnd(LOG_ENABLED
)) {
2939 expr_log(atom
->test
->name
);
2949 static int eval_fn(struct atom
*atom
, struct action_data
*action_data
)
2952 char *path
= atom
->argv
[0];
2953 struct dir_ent
*dir_ent
= action_data
->dir_ent
;
2954 struct stat
*buf
= action_data
->buf
;
2955 struct action_data eval_action
;
2957 /* Follow path (arg1) and evaluate the expression (arg2)
2958 * in the context of the file discovered. All attributes are updated
2959 * to refer to the file that is pointed to.
2961 * This test operation allows you to add additional context to the
2962 * evaluation of the file being scanned, such as "if current file is
2963 * XXX and the parent is YYY, then ..." Often times you need or
2964 * want to test a combination of file status
2966 * If the file referenced by the path does not exist in
2967 * the output filesystem, or some other failure is experienced in
2968 * walking the path (see follow_path above), then FALSE is returned.
2970 * If you wish to evaluate the inode attributes of files which
2971 * exist in the source filestem (but not in the output filesystem then
2972 * use stat instead (see above). */
2974 /* try to follow path, and get the directory entry it points to */
2975 if(path
[0] == '/') {
2976 /* absolute, walk from root - first skip the leading / */
2977 while(path
[0] == '/')
2980 dir_ent
= action_data
->root
->dir_ent
;
2982 dir_ent
= follow_path(action_data
->root
, path
);
2984 /* relative, if first component is ".." walk from parent,
2985 * otherwise walk from dir_ent.
2986 * Note: this has to be handled here because follow_path
2987 * will quite correctly refuse to execute ".." on anything
2988 * which isn't a directory */
2989 if(strncmp(path
, "..", 2) == 0 && (path
[2] == '\0' ||
2991 /* walk from parent */
2993 while(path
[0] == '/')
2996 dir_ent
= dir_ent
->our_dir
->dir_ent
;
2998 dir_ent
= follow_path(dir_ent
->our_dir
, path
);
2999 } else if(!file_type_match(buf
->st_mode
, ACTION_DIR
))
3002 dir_ent
= follow_path(dir_ent
->dir
, path
);
3005 if(dir_ent
== NULL
) {
3006 if(expr_log_cmnd(LOG_ENABLED
)) {
3007 expr_log(atom
->test
->name
);
3009 expr_log(atom
->argv
[0]);
3018 eval_action
.name
= dir_ent
->name
;
3019 eval_action
.pathname
= strdup(pathname(dir_ent
));
3020 eval_action
.subpath
= strdup(subpathname(dir_ent
));
3021 eval_action
.buf
= &dir_ent
->inode
->buf
;
3022 eval_action
.depth
= dir_ent
->our_dir
->depth
;
3023 eval_action
.dir_ent
= dir_ent
;
3024 eval_action
.root
= action_data
->root
;
3026 if(expr_log_cmnd(LOG_ENABLED
)) {
3027 expr_log(atom
->test
->name
);
3029 expr_log(eval_action
.subpath
);
3031 match
= eval_expr_log(atom
->data
, &eval_action
);
3034 match
= eval_expr(atom
->data
, &eval_action
);
3036 free(eval_action
.pathname
);
3037 free(eval_action
.subpath
);
3044 * Perm specific test code
3046 static int parse_perm_args(struct test_entry
*test
, struct atom
*atom
)
3048 int res
= 1, mode
, op
, i
;
3050 struct mode_data
*head
= NULL
, *cur
= NULL
;
3051 struct perm_data
*perm_data
;
3053 if(atom
->args
== 0) {
3054 TEST_SYNTAX_ERROR(test
, 0, "One or more arguments expected\n");
3058 switch(atom
->argv
[0][0]) {
3061 arg
= atom
->argv
[0] + 1;
3065 arg
= atom
->argv
[0] + 1;
3069 arg
= atom
->argv
[0];
3073 /* try to parse as an octal number */
3074 res
= parse_octal_mode_args(atom
->args
, atom
->argv
, (void **) &head
);
3076 /* parse as sym mode argument */
3077 for(i
= 0; i
< atom
->args
&& res
; i
++, arg
= atom
->argv
[i
])
3078 res
= parse_sym_mode_arg(arg
, &head
, &cur
);
3085 * Evaluate the symbolic mode against a permission of 0000 octal
3087 mode
= mode_execute(head
, 0);
3089 perm_data
= malloc(sizeof(struct perm_data
));
3090 if (perm_data
== NULL
)
3094 perm_data
->mode
= mode
;
3096 atom
->data
= perm_data
;
3100 struct mode_data
*tmp
= head
;
3109 static int perm_fn(struct atom
*atom
, struct action_data
*action_data
)
3111 struct perm_data
*perm_data
= atom
->data
;
3112 struct stat
*buf
= action_data
->buf
;
3114 switch(perm_data
->op
) {
3116 return (buf
->st_mode
& ~S_IFMT
) == perm_data
->mode
;
3118 return (buf
->st_mode
& perm_data
->mode
) == perm_data
->mode
;
3122 * if no permission bits are set in perm_data->mode match
3123 * on any file, this is to be consistent with find, which
3124 * does this to be consistent with the behaviour of
3127 return perm_data
->mode
== 0 || (buf
->st_mode
& perm_data
->mode
);
3132 #ifdef SQUASHFS_TRACE
3133 static void dump_parse_tree(struct expr
*expr
)
3137 if(expr
->type
== ATOM_TYPE
) {
3138 printf("%s", expr
->atom
.test
->name
);
3139 if(expr
->atom
.args
) {
3141 for(i
= 0; i
< expr
->atom
.args
; i
++) {
3142 printf("%s", expr
->atom
.argv
[i
]);
3143 if (i
+ 1 < expr
->atom
.args
)
3148 } else if (expr
->type
== UNARY_TYPE
) {
3149 printf("%s", token_table
[expr
->unary_op
.op
].string
);
3150 dump_parse_tree(expr
->unary_op
.expr
);
3153 dump_parse_tree(expr
->expr_op
.lhs
);
3154 printf("%s", token_table
[expr
->expr_op
.op
].string
);
3155 dump_parse_tree(expr
->expr_op
.rhs
);
3161 void dump_action_list(struct action
*spec_list
, int spec_count
)
3165 for (i
= 0; i
< spec_count
; i
++) {
3166 printf("%s", spec_list
[i
].action
->name
);
3167 if (spec_list
[i
].args
) {
3171 for (n
= 0; n
< spec_list
[i
].args
; n
++) {
3172 printf("%s", spec_list
[i
].argv
[n
]);
3173 if (n
+ 1 < spec_list
[i
].args
)
3179 dump_parse_tree(spec_list
[i
].expr
);
3187 dump_action_list(exclude_spec
, exclude_count
);
3188 dump_action_list(fragment_spec
, fragment_count
);
3189 dump_action_list(other_spec
, other_count
);
3190 dump_action_list(move_spec
, move_count
);
3191 dump_action_list(empty_spec
, empty_count
);
3200 static struct test_entry test_table
[] = {
3201 { "name", 1, name_fn
, NULL
, 1},
3202 { "pathname", 1, pathname_fn
, check_pathname
, 1, 0},
3203 { "subpathname", 1, subpathname_fn
, check_pathname
, 1, 0},
3204 { "filesize", 1, filesize_fn
, parse_number_arg
, 1, 0},
3205 { "dirsize", 1, dirsize_fn
, parse_number_arg
, 1, 0},
3206 { "size", 1, size_fn
, parse_number_arg
, 1, 0},
3207 { "inode", 1, inode_fn
, parse_number_arg
, 1, 0},
3208 { "nlink", 1, nlink_fn
, parse_number_arg
, 1, 0},
3209 { "fileblocks", 1, fileblocks_fn
, parse_number_arg
, 1, 0},
3210 { "dirblocks", 1, dirblocks_fn
, parse_number_arg
, 1, 0},
3211 { "blocks", 1, blocks_fn
, parse_number_arg
, 1, 0},
3212 { "gid", 1, gid_fn
, parse_gid_arg
, 1, 0},
3213 { "uid", 1, uid_fn
, parse_uid_arg
, 1, 0},
3214 { "depth", 1, depth_fn
, parse_number_arg
, 1, 0},
3215 { "dircount", 1, dircount_fn
, parse_number_arg
, 0, 0},
3216 { "filesize_range", 2, filesize_range_fn
, parse_range_args
, 1, 0},
3217 { "dirsize_range", 2, dirsize_range_fn
, parse_range_args
, 1, 0},
3218 { "size_range", 2, size_range_fn
, parse_range_args
, 1, 0},
3219 { "inode_range", 2, inode_range_fn
, parse_range_args
, 1, 0},
3220 { "nlink_range", 2, nlink_range_fn
, parse_range_args
, 1, 0},
3221 { "fileblocks_range", 2, fileblocks_range_fn
, parse_range_args
, 1, 0},
3222 { "dirblocks_range", 2, dirblocks_range_fn
, parse_range_args
, 1, 0},
3223 { "blocks_range", 2, blocks_range_fn
, parse_range_args
, 1, 0},
3224 { "gid_range", 2, gid_range_fn
, parse_range_args
, 1, 0},
3225 { "uid_range", 2, uid_range_fn
, parse_range_args
, 1, 0},
3226 { "depth_range", 2, depth_range_fn
, parse_range_args
, 1, 0},
3227 { "dircount_range", 2, dircount_range_fn
, parse_range_args
, 0, 0},
3228 { "type", 1, type_fn
, parse_type_arg
, 1, 0},
3229 { "true", 0, true_fn
, NULL
, 1, 0},
3230 { "false", 0, false_fn
, NULL
, 1, 0},
3231 { "file", 1, file_fn
, parse_file_arg
, 1, 0},
3232 { "exec", 1, exec_fn
, NULL
, 1, 0},
3233 { "exists", 0, exists_fn
, NULL
, 0, 0},
3234 { "absolute", 0, absolute_fn
, NULL
, 0, 0},
3235 { "stat", 1, stat_fn
, parse_expr_arg0
, 1, 1},
3236 { "readlink", 1, readlink_fn
, parse_expr_arg0
, 0, 1},
3237 { "eval", 2, eval_fn
, parse_expr_arg1
, 0, 1},
3238 { "perm", -2, perm_fn
, parse_perm_args
, 1, 0},
3243 static struct action_entry action_table
[] = {
3244 { "fragment", FRAGMENT_ACTION
, 1, ACTION_REG
, NULL
, NULL
},
3245 { "exclude", EXCLUDE_ACTION
, 0, ACTION_ALL_LNK
, NULL
, NULL
},
3246 { "fragments", FRAGMENTS_ACTION
, 0, ACTION_REG
, NULL
, frag_action
},
3247 { "no-fragments", NO_FRAGMENTS_ACTION
, 0, ACTION_REG
, NULL
,
3249 { "always-use-fragments", ALWAYS_FRAGS_ACTION
, 0, ACTION_REG
, NULL
,
3250 always_frag_action
},
3251 { "dont-always-use-fragments", NO_ALWAYS_FRAGS_ACTION
, 0, ACTION_REG
,
3252 NULL
, no_always_frag_action
},
3253 { "compressed", COMPRESSED_ACTION
, 0, ACTION_REG
, NULL
, comp_action
},
3254 { "uncompressed", UNCOMPRESSED_ACTION
, 0, ACTION_REG
, NULL
,
3256 { "uid", UID_ACTION
, 1, ACTION_ALL_LNK
, parse_uid_args
, uid_action
},
3257 { "gid", GID_ACTION
, 1, ACTION_ALL_LNK
, parse_gid_args
, gid_action
},
3258 { "guid", GUID_ACTION
, 2, ACTION_ALL_LNK
, parse_guid_args
, guid_action
},
3259 { "mode", MODE_ACTION
, -2, ACTION_ALL
, parse_mode_args
, mode_action
},
3260 { "empty", EMPTY_ACTION
, -2, ACTION_DIR
, parse_empty_args
, NULL
},
3261 { "move", MOVE_ACTION
, 1, ACTION_ALL_LNK
, NULL
, NULL
},
3262 { "prune", PRUNE_ACTION
, 0, ACTION_ALL_LNK
, NULL
, NULL
},
3263 { "chmod", MODE_ACTION
, -2, ACTION_ALL
, parse_mode_args
, mode_action
},
3264 { "noop", NOOP_ACTION
, 0, ACTION_ALL
, NULL
, noop_action
},
3265 { "", 0, -1, 0, NULL
, NULL
}