diff options
Diffstat (limited to 'ACTIONS-README')
-rw-r--r-- | ACTIONS-README | 774 |
1 files changed, 774 insertions, 0 deletions
diff --git a/ACTIONS-README b/ACTIONS-README new file mode 100644 index 0000000..ede4f76 --- /dev/null +++ b/ACTIONS-README @@ -0,0 +1,774 @@ + MKSQUASHFS ACTIONS + ================== + +The new Mksquashfs Actions code allows an "action" to be executed +on a file if one or more "tests" succeed. If you're familiar +with the "find" command, then an action is similar to "-print", +and a test is similar to say "-name" or "-type". + +Actions add greater flexibility when building images from sources. +They can be used to optimise compression, I/O performance, and they +also allow more control on the exclusion of files from the source, and +allow uid/gid and mode to be changed on a file basis. + +1. Specification +================ + +Actions can be specified on the command line with the -action option. +They can also be put into a file, and added with the -action-file +option. If put into a file, there is one action per line. But, lines +can be extended over many lines with continuation (\). + +If you want to get a log of what actions were performed, and the values +returned by the tests for each file, you can use the -log-action option +for the command line and -log-action-file for action files. + +Similarly there are -true-action (-true-action-file) and -false-action +(-false-action-file) options which log if the tests evaluated to TRUE, +and vice-versa: + +2. Syntax +========= + +An action consists of two parts, separated by an "@". The action to +be executed is placed before the @, and one or more tests are +placed afer the @. If the action or tests has an argument, it is +given in brackets. Brackets are optional if no argument is needed, +e.g. + +compressed()@name("filename") + +compressed@name("filename") + +do exactly the same thing. + +Arguments can be either numeric or string, depending on the +action and test. + +String arguments can be enclosed in double-quotes ("), to prevent the +parser from treating characters within it specially. Within double-quotes +only '\' is treatedly specially, and only at the end of a line. Special +characters can also be backslashed (\) to prevent interpretation by the +parser, e.g. the following is equivalent: + +compressed@name(file\ name\ with\ \&&\ and\ spaces) + +compressed@name("file name with && and spaces") + +Numeric arguments are of the form [range]number[size], where +[range] is either + + '<' or '-', match on less than number + '>' or '+', match on greater than number + "" (nothing), match on exactly number + +[size] is either: + "" (nothing), number + 'k' or 'K', number * 2^10 + 'm' or 'M', number * 2^20 + 'g' or 'G', number * 2^30 + +e.g. the following is equivalent: + +compressed@filesize(-81920) +compressed@filesize(<80K) + +Both will match on files less than 80K in size. + +Characters which are treated specially by the parser are * ( ) && || +! , @. Plus whitespace (spaces and tabs). + +Note: if the action is typed on the command line, then many special +characters will be evaluated by the shell, and you should always +check what is actually being passed to Mksquashfs. If in doubt use +-action-file where the additional complexities of shell evaluation is +avoided. + +For example this action line will work in an action file + +compressed()@name("file name") + +But, if typed on the command line, it will need to be: + +% mksquashfs source image -action "compressed()@name(\"file name\")" + + +3. Logical operators +==================== + +Tests can be combined with the logical operators && (and), || (or) and +can be negated with the unary ! (not). Expressions thus formed can also +be bracketed with "(" and ")", to create nested expressions. + +Operators do not have precedence and are evaluated strictly left to +right. To enforce precedence use brackets, e.g. + +test1 && test2 || test3 + +will be evaluated as + +(test1 && test2) || test3 + +&& and || are short-circuit operators, where the rhs (right hand side) +is only evaluated if the lhs (left hand side) has been insufficient +to determine the value. For example in the above, test3 will only be +evaluated if (test1 && test2) evaluates to FALSE. + +4. Test operators +================= + +The following test operators are supported: + +4.1 name(pattern) + +Returns TRUE if the filename (basename without leading directory components) +matches pattern. Pattern can have wildcards. + +4.2 pathname(pattern) +--------------------- + +Returns TRUE if the full pathname of the file matches pattern. +Pattern can have wildcards. + +4.3 subpathname(pattern) +------------------------ + +Returns TRUE if the <n> directory components of pattern match the first <n> +directory components of the pathname. + +For example, if pattern has one component: + +subpathname(dir1) will match "dir1/somefile", "dir1/dir2/somefile" etc. + +If pattern had two components: + +subpathname(dir1/dir2) will match ""dir1/dir2/somefile" etc. + +Pattern can have wildcards. + +4.4 filesize(value) +------------------- + +Return TRUE if the size of the file is less than, equal to, or larger than +<value>, where <value> can be [<-]number, number, [>+]number. Returns FALSE +on anything not a file. + +4.5 dirsize(value) +------------------ + +Return TRUE if the size of the directory is less than, equal to, or larger than +<value>, where <value> can be [<-]number, number, [>+]number. Returns FALSE +on anything not a directory. + +4.6 size(value) +--------------- + +Return TRUE if the size of the file is less than, equal to, or larger than +<value>, where <value> can be [<-]number, number, [>+]number. Works on any +file type. + +4.7 inode(value) +---------------- + +Return TRUE if the inode number is less than, equal to, or larger than +<value>, where <value> can be [<-]number, number, [>+]number. + +4.8 nlink(value) +---------------- + +Return TRUE if the nlink count is less than, equal to, or larger than +<value>, where <value> can be [<-]number, number, [>+]number. + +4.9 fileblocks(value) +--------------------- + +Return TRUE if the size of the file in blocks (512 bytes) is less than, equal +to, or larger than <value>, where <value> can be [<-]number, number, [>+]number. +Returns FALSE on anything not a file. + +4.10 dirblocks(value) +--------------------- + +Return TRUE if the size of the directory in blocks (512 bytes) is less than, +equal to, or larger than <value>, where <value> can be [<-]number, number, +[>+]number. Returns FALSE on anything not a directory. + +4.11 blocks(value) +------------------ + +Return TRUE if the size of the file in blocks (512 bytes) is less than, equal +to, or larger than <value>, where <value> can be [<-]number, number, [>+]number. +Works on any file type. + +4.12 uid(value) +--------------- +Return TRUE if the uid value is less than, equal to, or larger than +<value>, where <value> can be [<-]number, number, [>+]number. + +4.13 gid(value) +--------------- + +Return TRUE if the gid value is less than, equal to, or larger than +<value>, where <value> can be [<-]number, number, [>+]number. + +4.14 user(string) +----------------- + +Return TRUE if the file owner matches <string>. + +4.15 group(string) +------------------ + +Return TRUE if the file group matches <string>. + +4.16 depth(value) +----------------- + +Return TRUE if file is at depth less than, equal to, or larger than <value>, +where <value> can be [<-]number, number, [>+]number. Top level directory is +depth 1. + +4.17 dircount(value) +-------------------- + +Return TRUE if the number of files in the directory is less than, equal to, or +larger than <value>, where <value> can be [<-]number, number, [>+]number. +Returns FALSE on anything not a directory. + +4.18 filesize_range(minimum, maximum) +------------------------------------- + +Return TRUE if the size of the file is within the range [<minimum>, <maximum>] +inclusive. Returns FALSE on anything not a file. + +4.19 dirsize_range(minimum, maximum) +------------------------------------ + +Return TRUE if the size of the directory is within the rang +[<minimum>, <maximum>] inclusive. Returns FALSE on anything not a directory. + +4.20 size_range(minimum, maximum) +--------------------------------- + +Return TRUE if the size of the file is within the range [<minimum>, <maximum>] +inclusive. Works on any file type. + +4.21 inode_range(minimum, maximum) +---------------------------------- + +Return TRUE if the inode number is within the range [<minimum>, <maximum>] +inclusive. + +4.22 fileblocks_range(minimum, maximum) +--------------------------------------- + +Return TRUE if the size of the file in blocks (512 bytes) is within the range +[<minimum>, <maximum>] inclusive. Returns FALSE on anything not a file. + +4.23 dirblocks_range(minimum, maximum) +-------------------------------------- + +Return TRUE if the size of the directory in blocks (512 bytes) is within the +range [<minimum>, <maximum>] inclusive. Returns FALSE on anything not a +directory. + +4.24 blocks_range(minimum, maximum) +----------------------------------- + +Return TRUE if the size of the file in blocks (512 bytes) is within the range +[<minimum>, <maximum>] inclusive. Works on any file type. + +4.25 uid_range(minimum, maximum) +-------------------------------- + +Return TRUE if the file uid is within the range [<minimum>, <maximum>] +inclusive. + +4.26 gid_range(minimum, maximum) +-------------------------------- + +Return TRUE if the file gid is within the range [<minimum>, <maximum>] +inclusive. + +4.27 depth_range(minimum, maximum) +---------------------------------- + +Return TRUE if file is at depth within the range [<minimum>, <maximum>]. +Top level directory is depth 1. + +4.28 dircount_range(minimum, maximum) +------------------------------------- + +Returns TRUE is the number of files in the directory is within the range +[<minimum>, <maximum>]. Returns FALSE on anything not a directory. + +4.29 type(c) +------------ + +Returns TRUE if the file matches type <c>. <c> can be + f - regular file + d - directory + l - symbolic link + c - character device + b - block device + p - Named Pipe / FIFO + s - socket + + +4.30 perm(mode) +--------------- + +Return TRUE if file permissions match <mode>. <Mode> is the same as +find's -perm option: + + perm(mode) - TRUE if file's permission bits are exactly <mode>. + <mode> can be octal or symbolic. + + perm(-mode) - TRUE if all <mode> permission bits are set for this file. + <mode> can be octal or symbolic. + + perm(/mode) - TRUE if any <mode> permission bits are set for this file. + <mode> can be octal or symbolic. + + The symbolic mode is of the format [ugoa]*[[+-=]PERMS]+ + PERMS = [rwxXst]+ or [ugo] + and can be repeated separated with commas. + +Examples: + +perm(0644) match on a file with permissions exactly rw-r--r--. +perm(u=rw,go=r) as above, but expressed symbolically. + +perm(/222) match on a file which is writable for any of user, group, other, +perm(/u=w,g=w,o=w) as above but expressed symbolically, +perm(/ugo=w) as above but specified more concisely. + +4.31 file(string) +----------------- + +Execute "file command" on file, and return TRUE if the output +matches the substring <string>, for example + +file(ASCII text) will return TRUE if the file is ASCII text. + +Note, this is an expensive test, and should only be run if the file +has matched a number of other short-circuit tests. + +4.32 exists() +------------- + +Test if the file pointed to by the symbolic link exists within the +output filesystem, that is, whether the symbolic link has a relative +path and the relative path can be resolved to an entry within the +output filesystem. + +If the file isn't a symbolic link then the test always returns TRUE. + +4.33 absolute() +--------------- + +Test if the symbolic link is absolute, which by definition means +it points outside of the output filesystem (unless it is to be mounted +as root). If the file isn't a symbolic link then the test always returns +FALSE. + +4.34 readlink(expression) +------------------------- + +Follow or dereference the symbolic link, and evaluate <expression> in +the context of the file pointed to by the symbolic link. All inode +attributes, pathname, name and depth all refer to the dereferenced +file. + +If the symbolic link cannot be dereferenced because it points to something +not in the output filesystem (see exists() function above), then FALSE is +returned. If the file is not a symbolic link, the result is the same as +<expression>, i.e. readlink(<expression>) == <expression>. + +Examples: + +readlink("name(*.[ch])") returns TRUE if the file referenced by the symbolic +link matches *.[ch]. + +Obviously, expressions created with && || etc. can be specified. + +readlink("depth(1) && filesize(<20K)") returns TRUE if the file referenced +by the symbolic link is a regular file less than 20K in size and in the +top level directory. + +Note: in the above tests the embedded expression to be evaluated is enclosed +in double-quotes ("), this is to prevent the special characters being +evaluated by the parser when parsed at the top-level. Readlink causes +re-evaluation of the embedded string. + +4.36 eval(path, expression) +--------------------------- + +Follow <path> (arg1), and evaluate the <expression> (arg2) in the +context of the file discovered by following <path>. All inode attributes, +pathname, name and depth all refer to the file discovered by following +<path>. + +This test operation allows you to add additional context to the evaluation +of the file being scanned, such as "if the current file is XXX, test if the +parent is YYY, and then do ...". Often times you need or want to test +a combination of file status. + +The <path> can be absolute (in which case it is from the root directory of the +output filesystem), or it can be relative to the current file. Obviously +relative paths are more useful. + +If the file referenced by <path> does not exist in the output filesystem, +then FALSE is returned. + +Examples of usage: + +1. If a directory matches pattern, check that it contains a ".git" directory. + This allows you to exclude git repositories, with a double check that it is + a git repository by checking for the .git subdirectory. + + prune@name(*linux*) && type(d) && eval(.git, "type(d)") + + This action will match on any directory named *linux*, and exclude it if + it contains a .git subdirectory. + + +2. If a file matches a pattern, check that the parent directory matches + another pattern. This allows you to delete files if and only if they + are in a particular directory. + + prune@name(*.[ch]) && eval(.., "name(*linux*)") + + This action will delete *.[ch] files, but, only if they are in a directory + matching *linux*. + +4.37 false +---------- + +Always returns FALSE. + +4.38 true +--------- + +Always returns TRUE. + +5. Actions +========== + +An action is something which is done (or applied) to a file if the expression +(made up of the above test operators) returns TRUE. + +Different actions are applied in separate phases or gated, rather than being +applied all at once. This is to ensure that you know what the overall +state of the filesystem is when an action is applied. Or to put it another +way, if you have an action that depends on another action having already been +processed (for the entire filesystem), you'll want to know that is how +they will be applied. + +5.1 Actions applied at source filesystem reading (stage 1) +---------------------------------------------------------- + +5.1.1 exclude() +--------------- + +This action excludes all files and directories where the expression +returns TRUE. + +Obviously this action allows much greater control over which files are +excluded than the current name/pathname matching. + +Examples: + +1. Exclude any files/directories belonging to user phillip + +exclude@user(phillip) + +2. Exclude any regular files larger than 1M + +exclude@filesize(>1M) + +3. Only archive files/directories to a depth of 3 + +exclude@depth(>3) + +4. As above but also exclude directories at the depth of 3 + (which will be empty due to the above exclusion) + +exclude@depth(>3) || (depth(3) && type(d)) + +Which obviously reduces to + +exclude@depth(3) && type(d) + +Note: the following tests do not work in stage 1, and so they can't be +used in the exclude() action (see prune() action for explanation and +alternative). + + dircount() + dircount_range() + exists() + absolute() + readlink() + eval() + +5.2 Actions applied at directory scanning (stage 2) +--------------------------------------------------- + +5.2.1 fragment(name) +-------------------- + +Place all files matching the expression into a specialised fragment +named <name>. This can increase compression and/or improve +I/O by placing similar fragments together. + +Examples: + +1. fragment(cfiles)@name(*.[ch]) + +Place all C files into special fragments reserved for them. + +2. fragment(phillip)@user(phillip) + +Place all files owned by user Phillip into special fragments. + +5.2.2 fragments() +----------------- + +Tell Mksquashfs to use fragment packing for the files matching the +expression. + +For obvious reasons this should be used in conjunction with the global +Mksquashfs option -no-fragments. By default all files are packed into +fragments if they're less than the block size. + +5.2.3 no-fragments() +-------------------- + +Tell Mksquashfs to not pack the files matching the expression into +fragments. + +This can be used where you want to optimise I/O latency by not packing +certain files into fragments. + +5.2.4 tailend() +--------------- + +Tell Mksquashfs to use tail-end packing for the files matching the +expression. Normally Mksquashfs does not pack tail-ends into fragments, +as it may affect I/O performance because it may produce more disk head +seeking. + +But tail-end packing can increase compression. Additionally with modern +solid state media, seeking is not such a major issue anymore. + +5.2.5. no-tailend() +------------------- + +Tell Mksquashfs not to use tail-end packing for the files matching the +exppression. + +For obvious reasons this should be used in conjuction with the global +Mksquashfs option -always-use-fragments. By default tail-ends are not +packed into fragments. + +5.2.6 compressed() +------------------ + +Tell Mksquashfs to compress the fies matching the expression. + +For obvious reasons this should be used in conjunction with the global +Mksquashfs options -noD and -noF. File are by default compressed. + +5.2.7 uncompressed() +-------------------- + +Tell Mksquashfs to not compress the files matching the expression. + +This action obviously can be used to avoid compressing already compressed +files (XZ, GZIP etc.). + +5.2.8 uid(uid or user) +---------------------- + +Set the ownership of the files matching the expression to uid (if arg1 +is a number) or user (if arg1 is a string). + +5.2.9 gid(gid or group) +----------------------- + +Set the group of the files matching the expression to gid (if arg1 +is a number) or group (if arg1 is a string). + +5.2.10 guid(uid/user, gid/group) +-------------------------------- + +Set the uid/user and gid/group of the files matching the expression. + +5.2.11 chmod(mode) +------------------ + +Mode can be octal, or symbolic. + +If Mode is Octal, the permission bits are set to the octal value. + +If Mode is Symbolic, permissions can be Set, Added or Removed. + +The symbolic mode is of the format [ugoa]*[[+-=]PERMS]+ + PERMS = [rwxXst]+ or [ugo] + and the above sequence can be repeated separated with commas. + +A combination of the letters ugoa, specify which permission bits will +be affected, u means user, g means group, o means other, and a +means all or ugo. + +The next letter is +, - or =. The letter + means add to the existing +permission bits, - means remove the bits from the existing permission +bits, and = means set the permission bits. + +The permission bits (PERMS) are a combination of [rwxXst] which +sets/adds/removes those bits for the specified ugoa combination. They +can alternatively be u, g or o, which takes the permission bits from the +user, group or other of the file respectively. + +Examples: + +1. chmod(u+r) + +Adds the read permission to user. + +2. chmod(ug+rw) + +Adds the read and write permissions to both user and group. + +3. chmod(u=rw,go=r) + +Sets the permissions to rw-r--r--, which is eqivalent to + +4. chmod(644) + +5. cgmod(ug=o) + +Sets the user and group permissions to the permissions for other. + +5.3 Actions applied at second directory scan (stage 3) +------------------------------------------------------ + +5.3.1 prune() + +The prune() action deletes the file or directory (and everything +underneath it) that matches the expression. In that respect it is +identical to the exclude() action, except that it takes place in the +third stage, rather than the first stage. There are a number of +reasons to have a prune() action in addition to an exclude() +action. + +1. In the first stage Mksquashfs is building an in-memory representation + of the filesystem to be compressed. At that point some of the tests + don't work because they rely on an in-memory representation having been + built. + + So the following tests don't work in stage 1, and so they can't be + used in the exclude() action. + + dircount() + dircount_range() + exists() + absolute() + readlink() + eval() + + If you want to use these tests, you have to use the prune() action. + +2. Many exclusion/pruning operations may only be easily applied after + transformation actions have been applied in stages 1 & 2. + + For example, you may change the ownership and permissions of + matching files in stage 2, and then want to delete files based on + some criteria which relies on this having taken place. + +5.4. Actions applied at third directory scan (stage 4) +------------------------------------------------------ + +5.4.1 empty(reason) + +The empty() action deletes any directory which matches the expression, +and which is also empty for <reason>. <reason> is one of "excluded", +"source" and "all". If no argument is given, empty() defaults to "all". + +The reason "excluded" means the directory has become empty due to +the exclude() or prune() actions or by exclusion on the command line. +The reason "source" means the directory was empty in the source filesystem. +The reason "all" means it is empty for either one of the above two reasons. + +This action is often useful when exclusion has produced an empty +directory, or a hierarchy of directories which are empty but for a +sub-directory which is empty but for a sub-directory until an +empty directory is reached. + +Example + +1. Exclude any file which isn't a directory, and then clean-up + any directories which are empty as a result. + + exclude@!type(d) + empty(excluded)@true + +This will produce an empty filesystem, unless there were some +directories that were originally empty. + +Changing the empty action to + + exclude@!type(d) + empty@true + +Will produce an empty filesystem. + +5.5 Actions performed at filesystem creation (stage 6) +------------------------------------------------------ + +5.5.1 xattrs-exclude(regex) + +The xattrs-exclude action excludes any xattr names matching <regex>. <regex> is +a POSIX regular expression, e.g. xattrs-exclude("^user.") excludes xattrs from +the user namespace. + +5.5.2 xattrs-include(regex) + +The xattrs-include action includes any xattr names matching <regex>. <regex> is +a POSIX regular expression, e.g. -xattrs-include("^user.") includes xattrs from +the user namespace. + +5.5.3 xattrs-add(name=val) + +The xattrs-add action adds the xattr <name> with contents <val>. If an user +xattr it can be added to regular files and directories (see man 7 xattr). +Otherwise it can be added to all files. + +The extended attribute value by default will be treated as binary (i.e. an +uninterpreted byte sequence), but it can be prefixed with 0s, where it will be +treated as base64 encoded, or prefixed with 0x, where it will be treated as +hexidecimal. + +Obviously using base64 or hexidecimal allows values to be used that cannot be +entered on the command line such as non-printable characters etc. But it +renders the string non-human readable. To keep readability and to allow +non-printable characters to be entered, the 0t prefix is supported. This +encoding is similar to binary encoding, except backslashes are specially +treated, and a backslash followed by three octal digits can be used to encode +any ASCII character, which obviously can be used to encode non-printable values. + +The following four actions are equivalent + +-xattrs-add("user.comment=hello world") +-xattrs-add("user.comment=0saGVsbG8gd29ybGQ=") +-xattrs-add("user.comment=0x68656c6c6f20776f726c64") +-xattrs-add("user.comment=0thello world") + +Obviously in the above example there are no non-printable characters and so +the 0t prefixed string is identical to the first line. The following three +actions are identical, but where the space has been replaced by the +non-printable NUL '\0' (null character). + +-xattrs-add("user.comment=0thello\000world") +-xattrs-add("user.comment=0saGVsbG8Ad29ybGQ=") +-xattrs-add("user.comment=0x68656c6c6f00776f726c64") |