RAWHIDE.CONF(5)
๐ RAWHIDE.CONF(5) ๐
okay bestie, gather round: this is the manual page for /etc/rawhide.conf, aka the config file for rh(1). It is giving โtiny language, big main character energy,โ and honestly? once you get the vibe it is so good. ๐ซถ
โจ NAME โจ
/etc/rawhide.conf โ configuration file for rh(1).
๐ DESCRIPTION ๐
The /etc/rawhide.conf file (or something like it) is a standard library of functions that every rh(1) user can use. It is the first file rh(1) reads. Then any files in the /etc/rawhide.conf.d directory (or similar) whose names do not start with a dot (.) get read next, in lexicographic order โ those can add more system-wide function definitions. ๐
After that, user-specific configuration is read from ~/.rhrc and ~/.rhrc.d/* files in the same manner.
Then come any files specified by rh(1)'s -f option, followed by the contents of rh(1)'s -e option argument. That -e argument can also contain additional function definitions and a trailing file test expression. All of these share the same syntax. โจ
btw, the system-wide config might live somewhere else depending on operating system preferences โ think /usr/local/etc, /opt/local/etc, or /usr/pkg/etc. The output of rh --help will tell you where the system-wide configuration files are on the local system. ๐ฆ
๐ธ FILE FORMAT ๐ธ
The following subsections describe the syntax and semantics of rawhide search criteria source/configuration files.
๐ File structure ๐
Every rawhide source/configuration file consists of zero or more function definitions, optionally followed by a file test expression, which is optionally terminated by a semicolon (;).
If a source file does contain a trailing file test expression, that expression becomes the default file test expression โ unless another file read later also contains a trailing file test expression, in which case that later expression becomes the default file test expression. It is not expected that any system-wide or user-specific configuration files will contain a trailing file test expression, but they can.
Files specified with the -f option are more likely to contain a trailing file test expression, in which case there is no need for the -e option (explicit or implicit). But if the -e option is also supplied, then any file test expression that it specifies takes precedence.
Technically, even the -e option argument does not require a file test expression (because there is a default which matches everything), but it will usually supply one.
๐ฌ Comments ๐ฌ
Search criteria can include explanations in the form of comments. There are three comment styles:
/* C-style comments */โ these start with/*, end with*/, and can span multiple lines.// C++-style commentsโ these start with//and end at the end of the line.# Shell-style commentsโ these start with#and end at the end of the line.
๐ง Grammar ๐ง
The rawhide search criteria language is like a tiny subset of the C language's expression syntax, with a few domain-specific additions. All of C's conditional, logical, relational, equality, arithmetic, and bit operators are available. But the only type is integer. There are special tokens to represent various things, some built-in symbols, and user-defined functions.
Here is the grammar of the search criteria language (BNF with a few liberties taken):
<program> ::=
<function-list> <expression> ";" EOF
| <function-list> <expression> EOF
| <function-list> EOF
<function-list> ::=
<function> <function-list>
| EMPTY
<function> ::=
IDENTIFIER <parameters> "{" <return> <expression> <eos> "}"
<return> ::=
"return"
| EMPTY
<eos> == >
";"
| EMPTY
<parameters> ::=
"(" <id-list> ")"
| "(" ")"
| EMPTY
<id-list> ::=
IDENTIFIER <id-tail>
<id-tail> ::=
"," <id-list>
| EMPTY
<expression> ::= <or> "?" <expression> ":" <expression> | <or>
<or> ::= <and> "||" <or> | <and>
<and> ::= <bitor> "&&" <and> | <bitor>
<bitor> ::= <bitxor> "|" <bitor> | <bitxor>
<bitxor> ::= <bitand> "^" <bitxor> | <bitand>
<bitand> ::= <eq> "&" <bitand> | <eq>
<eq> ::= <rel> <eq-op> <rel> | <rel>
<eq-op> ::= "==" | "!="
<rel> ::= <shift> <rel-op> <shift> | <shift>
<rel-op> ::= "<" | ">" | "<=" | ">="
<shift> ::= <add> <shift-op> <shift> | <add>
<shift-op> ::= "<<" | ">>"
<add> ::= <mul> <add-op> <add> | <mul>
<add-op> ::= "+" | "-"
<mul> ::= <unary> <mul-op> <mul> | <unary>
<mul-op> ::= "*" | "/" | "%"
<unary> ::= <unary-op> <unary> | <factor>
<unary-op> ::= "-" | "~" | "!"
<factor> ::=
<number>
| <user-id>
| <group-id>
| "[" <date-time> "]"
| <pattern>
| <reference-file>
| <built-in>
| <function-call>
| <parameter>
| "(" <expression> ")"
<number> ::=
DECIMAL
| DECIMAL NOSPACE <scale>
| "0" NOSPACE OCTAL
| "0x" NOSPACE HEXADECIMAL
<scale> ::=
"K" | "M" | "G" | "T" | "P" | "E"
| "k" | "m" | "g" | "t" | "p" | "e"
<user-id> ::=
"$" NOSPACE USERNAME
| "$$"
<group-id> ::=
"@" NOSPACE GROUPNAME
| "@@"
<date-time> ::=
DECIMAL "/" DECIMAL "/" DECIMAL
| DECIMAL "/" DECIMAL "/" DECIMAL DECIMAL
| DECIMAL "/" DECIMAL "/" DECIMAL DECIMAL ":" DECIMAL
| DECIMAL "/" DECIMAL "/" DECIMAL DECIMAL ":" DECIMAL ":" DECIMAL
<pattern> ::=
STRING
| STRING NOSPACE "." NOSPACE <pattern-modifier>
<pattern-modifier> ::=
"i" | "re" | "rei"
| "path" | "ipath" | "repath" | "reipath"
| "link" | "ilink | "relink" | "reilink"
| "body" | "ibody | "rebody" | "reibody"
| "what" | "iwhat | "rewhat" | "reiwhat"
| "mime" | "imime | "remime" | "reimime"
| "acl" | "iacl" | "reacl" | "reiacl"
| "ea" | "iea" | "reea" | "reiea"
| "sh"
<reference-file> ::=
STRING NOSPACE "." NOSPACE <reference-file-field>
<reference-file-field> ::=
"exists" | "dev" | "major" | "minor" | "ino"
| "mode" | "type" | "perm" | "nlink" | "uid"
| "gid" | "rdev" | "rmajor" | "rminor" | "size"
| "blksize" | "blocks" | "atime" | "mtime" | "ctime"
| "attr" | "proj" | "gen" | "strlen" | "inode"
| "nlinks" | "user" | "group" | "sz" | "accessed"
| "modified" | "changed" | "attribute" | "project" | "generation"
| "len"
<built-in> ::=
"dev" | "major" | "minor" | "ino" | "mode"
| "nlink" | "uid" | "gid" | "rdev" | "rmajor"
| "rminor" | "size" | "blksize" | "blocks" | "atime"
| "mtime" | "ctime" | "attr" | "proj" | "gen"
| "nouser" | "nogroup" | "readable" | "writable" | "executable"
| "strlen" | "depth" | "prune" | "trim" | "exit"
| "now" | "today" | "second" | "minute" | "hour"
| "day" | "week" | "month" | "year" | "IFREG"
| "IFDIR" | "IFLNK" | "IFCHR" | "IFBLK" | "IFSOCK"
| "IFIFO" | "IFDOOR" | "IFMT" | "ISUID" | "ISGID"
| "ISVTX" | "IRWXU" | "IRUSR" | "IWUSR" | "IXUSR"
| "IRWXG" | "IRGRP" | "IWGRP" | "IXGRP" | "IRWXO"
| "IROTH" | "IWOTH" | "IXOTH" | "texists" | "tdev"
| "tmajor" | "tminor" | "tino" | "tmode" | "tnlink"
| "tuid" | "tgid" | "trdev" | "trmajor" | "trminor"
| "tsize" | "tblksize" | "tblocks" | "tatime" | "tmtime"
| "tctime" | "tstrlen"
<function-call> ::=
IDENTIFIER <arguments>
<arguments> ::=
"(" <expr-list> ")"
| "(" ")"
| EMPTY
<expr-list> ::=
<expression> <expr-tail>
<expr-tail> ::=
"," <expr-list>
| EMPTY
<parameter> ::=
IDENTIFIER
๐ Operators ๐
The following C operators are available (presented in groups of increasing precedence):
?: Conditional (i.e., condition-expr ? if-expr : else-expr)
|| Logical or
&& Logical and
| Bit or
^ Bit exclusive or
& Bit and
== Equals
!= Not equals
< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to
<< Bit shift left
>> Bit shift right
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulo (remainder)
- Minus (unary)
~ Bit not (unary)
! Logical not (unary)
Parentheses override operator precedence (e.g., (1 + 2) * 3).
Like in C, the ?: and || and && operators use โshort-circuitโ evaluation. ๐
With the ternary conditional operator (?:), the second operand is only evaluated when the first operand evaluates to true (i.e., non-zero), and the third operand is only evaluated when the first operand evaluates to false (i.e., zero).
With the logical or operator (||), the second operand is only evaluated when the first operand evaluates to false. Otherwise, it is not necessary.
With the logical and operator (&&), the second operand is only evaluated when the first operand evaluates to true. Otherwise, it is not necessary.
This matters when using the prune, trim, or exit built-ins (see below), because they have control flow side-effects when they are evaluated. It is also important when using the texists built-in, the sh "pattern" modifier, and the exists reference file field (see below).
All the other binary operators always evaluate both operands.
๐ Numbers ๐
Numeric constants can be decimal, octal (starting with 0), or hexadecimal (starting with 0x). All numbers are integers. And everything is a number. ๐
Decimal numbers can have a suffix letter that indicates the scale (e.g., 10K), in units based on 1024 (upper case), or based on 1000 (lower case):
K = Kibibytes (KiB, units of 1024)
M = Mebibytes (MiB, units of 1024^2)
G = Gibibytes (GiB, units of 1024^3)
T = Tebibytes (TiB, units of 1024^4)
P = Pebibytes (PiB, units of 1024^5)
E = Exbibytes (EiB, units of 1024^6)
k = Kilobytes (KB, units of 1000)
m = Megabytes (MB, units of 1000^2)
g = Gigabytes (GB, units of 1000^3)
t = Terabytes (TB, units of 1000^4)
p = Petabytes (PB, units of 1000^5)
e = Exabytes (EB, units of 1000^6)
๐ฌ Strings
ok so string literals live inside double quotes (""") โ iconic, simple. Any double quote characters inside your string have to be quoted with a preceding backslash character ("\"). Backslashes can also be quoted with a preceding backslash, which is lowkey the same energy. And any backslashes that don't precede a double quote or another backslash? They're just treated as normal characters and get included in the string. no drama, they're just vibing there.
Strings usually contain a pattern to match against file names (or certain other information associated with files). The value of a pattern string is whether or not the pattern match succeeded. Strings can also contain a shell command to execute โ and the value of a shell command string is the exit success status of that command. See the Pattern matching and Pattern modifiers sections below for details. Strings can also contain the path of a reference file to use for comparison purposes โ see the Reference file fields section below. versatile queen ๐
๐ค User IDs
A token starting with a dollar sign ($) immediately followed by a user name evaluates to that user's user ID. It's assumed that user names consist entirely of letters, digits, and dot (.), dash (-), and underscore characters (_). All non-ASCII characters (UTF-8 or ISO-8859-*) are considered to be "letters" โ yes, all of them, she's inclusive like that ๐ซถ
The token $$ evaluates to the current user's user ID. it's giving selfie energy tbh.
๐ฅ Group IDs
A token starting with an at sign (@) immediately followed by a group name evaluates to that group's group ID. It's assumed that group names consist entirely of letters, digits, and dot (.), dash (-), and underscore characters (_). All non-ASCII characters (UTF-8 or ISO-8859-*) are considered to be "letters". same rules, different symbol, we love consistency โจ
The token @@ evaluates to the current user's primary group ID.
๐ Dates and date/times
Dates and date/times can be specified between square brackets ([]) โ specifically [YYYY/MM/DD] and [YYYY/MM/DD hh:mm:ss]. They're interpreted as being in the local time zone. If the year is specified as a number below 100, then it's interpreted as being a year in the current century. Hours must be in 24-hour time, not 12-hour time โ we're not doing AM/PM here bestie.
The seconds component is optional if it is zero (i.e., [YYYY/MM/DD hh:mm]). The minutes component is also optional if both it and the seconds are zero (i.e., [YYYY/MM/DD hh]). The hours component is also optional if it and the minutes and seconds are all zero (i.e., midnight) โ then it's just a date. Dates and date/times evaluate to the corresponding number of seconds since the UNIX epoch. iconic math moment ๐งฎ
โ ๏ธ Note that if the month, day, hours, minutes, or seconds are outside their valid ranges, the date or date/time is normalized โ so like, the 40th of October is interpreted as the 9th of November, and the time25:90:90is interpreted as2:31:30the following day. it's not an error, she just fixes it for you ๐ญ Seemktime(3)for details.
๐งฎ Functions
Functions can be defined to give names to expressions, and to make those names available for use in subsequent expressions. Function names can't be the same as the names of any existing functions or built-in symbols. (no name-stealing, it's rude โ)
f() { return expr; }
Functions can only contain a return statement or expression. The return keyword and semicolon (;) are optional โ so this is equally valid:
f() { expr }
Functions can have parameters. Parameter names can't be the same as the names of any existing functions or built-in symbols either. same rule, bestie.
f(x, y, z) { (x + y) * z }
Functions with no parameters can be defined and called with or without parentheses. queen of flexibility:
f() { expr }
g { f }
g()
A function can only be called if its definition has already been encountered by the parser. So recursive functions are possible, but mutually recursive functions are not. sad but true ๐
The names of functions and parameters must start with a letter or underscore character (_), which can be followed by letters, underscores, and digits. All non-ASCII characters (UTF-8 or ISO-8859-*) are considered to be "letters".
๐ฎ Built-in symbols
There are various built-in symbols representing inode metadata (i.e., stat(2) structure fields), constants, and other useful information. these are the main characters of the whole operation, honestly ๐
devโ The device number of the device/filesystem that the current candidate file resides on. This is thest_devfield of the correspondingstat(2)structure. See the relatedmajorandminorbuilt-ins (next) for extracting the major and minor device numbers fromdev.majorโ The major device number of the device/filesystem that the current candidate file resides on. This is part of thest_devfield of the correspondingstat(2)structure.minorโ The minor device number of the device/filesystem that the current candidate file resides on. This is part of thest_devfield of the correspondingstat(2)structure.inoโ The inode number of the current candidate file. This is thest_inofield of the correspondingstat(2)structure.modeโ The mode of the current candidate file. This is thest_modefield of the correspondingstat(2)structure. This contains the file type and permissions. The standard library provides thetypeandpermfunctions (among others) for extracting the file type and permissions frommode.nlinkโ The number of hard links to the current candidate file. This is thest_nlinkfield of the correspondingstat(2)structure.uidโ The user ID of the owner of the current candidate file. This is thest_uidfield of the correspondingstat(2)structure.gidโ The group ID of the group of the current candidate file. This is thest_gidfield of the correspondingstat(2)structure.rdevโ The device number of the current candidate file. This is thest_rdevfield of the correspondingstat(2)structure. This is only meaningful for character devices and block devices. See the relatedrmajorandrminorbuilt-ins (next) for extracting the major and minor device numbers fromrdev.rmajorโ The major device number of the current candidate file. This is part of thest_rdevfield of the correspondingstat(2)structure. This is only meaningful for character devices and block devices.rminorโ The minor device number of the current candidate file. This is part of thest_rdevfield of the correspondingstat(2)structure. This is only meaningful for character devices and block devices.sizeโ The size in bytes of the current candidate file. This is thest_sizefield of the correspondingstat(2)structure.- For candidate symlinks (that are not followed with the
-yor-Yoption), this is the length in bytes of the target path. - For candidate directories that are readable, this is not the
st_sizefield of the correspondingstat(2)structure. Instead, this is the number of entries it contains (excluding.and..). - For candidate directories that are unreadable (and everything else), this is the usual (undocumented)
st_sizefield of the correspondingstat(2)structure.
- For candidate symlinks (that are not followed with the
blksizeโ The preferred block size for efficient I/O on the current candidate file's filesystem. This is thest_blksizefield of the correspondingstat(2)structure. On some filesystems (e.g.,zfs), this is specific to each file, rather than to the whole filesystem.- Note that this is unrelated to the
blocksbuilt-in (see next). don't get them confused bestie ๐
- Note that this is unrelated to the
blocksโ The number of 512-byte blocks occupied by the current candidate file. This is thest_blocksfield of the correspondingstat(2)structure.atimeโ The time that the current candidate file was last accessed. This is thest_atimefield of the correspondingstat(2)structure.mtimeโ The time that the current candidate file's contents were last modified. This is thest_mtimefield of the correspondingstat(2)structure.ctimeโ The time that the current candidate file's inode was last changed. This is thest_ctimefield of the correspondingstat(2)structure.attrโ On Linux, the current candidate file's ext2-style file attribute bit mask. Not all file systems support all file attributes. Seechattr(1)andlsattr(1)for details. See/etc/rawhide.conf.d/attributesfor all the related predicate functions (e.g.,immutable,append,nodump,nocow,dax, ...).- Note: If the current candidate file is a symlink, it is never followed for the purpose of obtaining the file attributes. This is a decision made by
libe2p. This is not affected by the-yor-Yoptions. Also note that symlinks do not have their own file attributes (i.e.,attris zero). - On Linux, this is only available on systems with
libe2p. On Linux systems withoutlibe2p, this is not a built-in symbol. Instead, this is a place-holder function that returns zero. - This is also available on FreeBSD, OpenBSD, NetBSD, and macOS. The attributes/flags that are available vary from system to system. See
chflags(1)for details. See/etc/rawhide.conf.d/attributesfor all the related predicate functions (e.g.,uimmutable,uappend,nodump,opaque, ...). - On other systems, this doesn't exist at all. ๐
- Note: If the current candidate file is a symlink, it is never followed for the purpose of obtaining the file attributes. This is a decision made by
projโ On Linux, the current candidate file's ext2-style file project number. Not all file systems support all file attributes. Seechattr(1)andlsattr(1)for details.- Note: If the current candidate file is a symlink, it is always followed for the purpose of obtaining the file project. This is not affected by the
-yor-Yoptions. - Note: This is only available on Linux systems with
libe2p. On Linux systems withoutlibe2p, this is not a built-in symbol. Instead, this is a place-holder function that returns zero. On other systems, this doesn't exist at all.
- Note: If the current candidate file is a symlink, it is always followed for the purpose of obtaining the file project. This is not affected by the
genโ On Linux, the current candidate file's ext2-style version/generation number. Not all file systems support all file attributes. Seechattr(1)andlsattr(1)for details.- Note: If the current candidate file is a symlink, it is always followed for the purpose of obtaining the file version/generation. This is not affected by the
-yor-Yoptions. - Note: This is only available on Linux systems with
libe2p. On Linux systems withoutlibe2p, this is not a built-in symbol. Instead, this is a place-holder function that returns zero. On other systems, this doesn't exist at all.
- Note: If the current candidate file is a symlink, it is always followed for the purpose of obtaining the file version/generation. This is not affected by the
nouserโ This is true (i.e., non-zero) when the current candidate file's uid does not correspond to any user in the user database (e.g., the local password file/etc/passwd, NIS, and LDAP).nogroupโ This is true (i.e., non-zero) when the current candidate file's gid does not correspond to any group in the group database (e.g., the local group file/etc/group, NIS, and LDAP).
๐ readable
True (like, non-zero true) when the current candidate file is readable by the current user. Bestie, listen: this uses the access(2) system call, not the file permissions. So it's giving "can I actually read this rn", not "what do the mode bits say". ๐ซถ
๐ writable
True (i.e., non-zero) when the current candidate file is writable by the current user. Again โ access(2) system call, not the file permissions. Same vibe, different permission. โจ
๐ executable
True (i.e., non-zero) when the current candidate file is executable by the current user. Yep, access(2) system call, not the file permissions. It's the trifecta bestie ๐
๐ strlen
This is the length in bytes of the base name of the current candidate file. Heads up though: this is zero for the root directory (/), because root literally has no base name. Not me defending root's name situation ๐ญ
๐ depth
How deep the current candidate file is, relative to the starting search directory. The starting search directory itself is depth 0, its children are depth 1, and so on down the tree. ๐ฆ
๐ prune
This one always evaluates to true (non-zero), and as a side-effect it makes the directory tree being searched get "pruned". Translation: the current candidate file will not match, and if it's a directory, it will not be searched. It's a speed-up move for your search. ๐ฅ
prune needs to be used with the ?: or || or && operator (see above) to conditionally skip part of a directory tree and search the rest.
prune and the -D (depth-first) option are incompatible. When -D is used, prune will not work โ it will not prevent searching below the current candidate path. Same deal with the -U (unlink) option, which implies -D. ๐ซ
Note: this is counter-intuitive, and I need you to trust me here.pruneevaluates to true, even though it effectively causes the file test expression as a whole to evaluate to false (i.e., zero), in order to prevent the current candidate file from matching. The reasonpruneevaluates to true rather than false is to make expressions like(bad && prune || good)possible as a syntactic alternative to(bad ? prune : good). iykyk ๐
Note:pruneandtrimare very similar (see next). They both prevent searching below the current candidate path. The only difference between them is whether or not the current candidate path itself is also prevented from matching. Useprunewhen the current candidate path needs to be excluded. Usetrimwhen it needs to be included. Think ofpruneas a heavytrim. ๐
๐ trim
Always evaluates to true (non-zero), and as a side-effect it makes the directory tree being searched get "trimmed". Meaning: if the current candidate file is a directory, it will not be searched (exactly like prune). But unlike prune, the current candidate file itself is not prevented from matching. So when the current candidate file isn't a directory, this does literally nothing. Still a speed-up move tho โจ
trim needs to be used with the ?: or || or && operator (see above) to conditionally skip part of a directory tree and search the rest.
trim and the -D (depth-first) option are incompatible. When -D is used, trim will not work โ it will not prevent searching below the current candidate path. Same applies to -U (unlink), which implies -D. ๐ซ
Note:trimandpruneare very similar (see above). They both prevent searching below the current candidate path. The only difference is whether or not the current candidate path itself is also prevented from matching. Usetrimwhen the current candidate path needs to be included. Useprunewhen it needs to be excluded. Think oftrimas a lightprune. ๐ฆ
๐ exit
Always evaluates to true (non-zero), and as a side-effect it terminates the search immediately after the current candidate file. This is the "find the first matching file and then dip" builtin. ๐
exit needs to be used with the ?: or || or && operator (see above) to conditionally terminate the search.
exit can be used in combination with prune and/or trim (see above), e.g. bad && prune || good && exit. Slay.
๐ now
The current time (when rh(1) started), in seconds since the UNIX epoch. โฐ
๐ today
The time last midnight (local time), in seconds since the UNIX epoch. ๐
๐ second
The value 1. That's it. That's the builtin. ๐
๐ minute
The number of seconds in a minute.
๐ hour
The number of seconds in an hour.
๐ day
The number of seconds in a day.
๐ week
The number of seconds in a week.
๐ month
The average number of seconds in a month. Yes, average. Months are not all the same length, bestie, that's just how it is ๐ญ
๐ year
The average number of seconds in a year.
๐ IFMT
Same as the S_IFMT bit mask from C's <sys/stat.h> header file. This bit mask is the bits in the mode that represent the file type. So the file type is (mode & IFMT) (see next), and the file permissions are (mode & ~IFMT) (see below). Bit math girlies rise ๐ง
๐ IFREG, IFDIR, IFLNK, IFCHR, IFBLK, IFSOCK, IFIFO, IFDOOR
Same as the corresponding S_ values from C's <sys/stat.h> header file. These correspond to the different types of filesystem entry โ that's regular file, directory, symbolic link, character device, block device, socket, fifo/pipe, and door, respectively, in that exact order. IFDOOR only applies to Solaris. ๐ช
๐ ISUID, ISGID, ISVTX
Same as the corresponding S_ bit masks from C's <sys/stat.h> header file. These bit masks correspond to the setuid, setgid, and sticky bits in file permissions โ i.e. --S------, -----S---, and --------T, respectively (aka 04000, 02000, and 01000). ๐
๐ IRWXU, IRUSR, IWUSR, IXUSR
Same as the corresponding S_ bit masks from C's <sys/stat.h> header file. These correspond to the user/owner file permissions โ i.e. rwx------, r--------, -w-------, and --x------, respectively (aka 0700, 0400, 0200, and 0100). ๐ธ
๐ IRWXG, IRGRP, IWGRP, IXGRP
Same as the corresponding S_ bit masks from C's <sys/stat.h> header file. These correspond to the group file permissions โ i.e. ---rwx---, ---r-----, ----w----, and -----x---, respectively (aka 0070, 0040, 0020, and 0010). ๐
๐ IRWXO, IROTH, IWOTH, IXOTH
Same as the corresponding S_ bit masks from C's <sys/stat.h> header file. These correspond to the other/world file permissions โ i.e. ------rwx, ------r--, -------w-, and --------x, respectively (aka 0007, 0004, 0002, and 0001). ๐
๐ texists
True (non-zero) when the current candidate file is a symlink whose ultimate target exists โ that's when rh(1) can actually obtain its stat(2) structure information. Important caveat: a false value (zero) might be because of permissions, not because the thing doesn't exist. Don't let it gaslight you ๐
Use it with the ?: or || or && operator (see above) to conditionally use any of the following stat(2) structure fields relating to symlink targets. Unless the target exists, their values are all zero and meaningless.
Note: the -Y option is incompatible with this built-in. The only symlinks seen will be broken ones, and this built-in will return zero. ๐
Note: even without the-yor-Yoption (so symlinks aren't followed for the purpose of searching), symlinks are followed for the purpose of obtaining thestat(2)structure information of the current candidate symlink's ultimate target โ all so the following target-related built-in symbols can work. ๐ซถ
๐ tdev
The device number of the device/filesystem that the current candidate symlink's ultimate target resides on. This is the st_dev field of the corresponding stat(2) structure. See the related tmajor and tminor built-ins (next) for extracting the major and minor device numbers out of tdev. ๐
Only use this when the current candidate file is a symlink and its ultimate target exists (i.e., when texists is true). Otherwise, this is zero.
Note: the -Y option is incompatible with this built-in. The only symlinks seen will be broken ones, and this built-in will return zero.
๐ tmajor
The major device number of the device/filesystem that the current candidate symlink's ultimate target resides on. This is part of the st_dev field of the corresponding stat(2) structure.
Only use this when the current candidate file is a symlink and its ultimate target exists (i.e., when texists is true). Otherwise, this is zero.
Note: the -Y option is incompatible with this built-in. The only symlinks seen will be broken ones, and this built-in will return zero.
๐ tminor
The minor device number of the device/filesystem that the current candidate symlink's ultimate target resides on. This is part of the st_dev field of the corresponding stat(2) structure.
Only use this when the current candidate file is a symlink and its ultimate target exists (i.e., when texists is true). Otherwise, this is zero.
Note: the -Y option is incompatible with this built-in. The only symlinks seen will be broken ones, and this built-in will return zero.
๐ tino
The inode number of the current candidate symlink's ultimate target. This is the st_ino field of the corresponding stat(2) structure. ๐
Only use this when the current candidate file is a symlink and its ultimate target exists (i.e., when texists is true). Otherwise, this is zero.
Note: the -Y option is incompatible with this built-in. The only symlinks seen will be broken ones, and this built-in will return zero.
๐ tmode
The mode of the current candidate symlink's ultimate target. This is the st_mode field of the corresponding stat(2) structure, and it holds the file type and the permissions. The standard library provides the ttype and tperm functions (among others) for extracting the file type and permissions from tmode. Combo meal energy ๐
Only use this when the current candidate file is a symlink and its ultimate target exists (i.e., when texists is true). Otherwise, this is zero.
Note: the -Y option is incompatible with this built-in. The only symlinks seen will be broken ones, and this built-in will return zero.
๐ tnlink
The number of hard links to the current candidate symlink's ultimate target. This is the st_nlink field of the corresponding stat(2) structure. ๐
This one's only meant for when the current candidate file is a symlink and its ultimate target actually exists (i.e. when texists is true). Any other situation? It's zero. ๐ซถ
โ ๏ธ Real talk: the -Y option does not play nice with this built-in. The only symlinks you'll ever see are broken ones, so this built-in just returns zero. Every time. ๐ญ
๐ซ tuid
The user ID of whoever owns the current candidate symlink's ultimate target โ literally the st_uid field of the corresponding stat(2) structure. ๐
Same rule as always: only use it when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise it's zero.
โ ๏ธ And the -Y option is incompatible with this built-in โ you'll only see broken symlinks, and it'll return zero.
๐ซ tgid
The group ID of the group of the current candidate symlink's ultimate target. That's the st_gid field of the corresponding stat(2) structure. ๐ซ
Only use it when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise: zero, zero, zero.
โ ๏ธ -Y is incompatible with this built-in too โ only broken symlinks show up, and it returns zero.
๐ซ trdev
The device number of the current candidate symlink's ultimate target, aka the st_rdev field of the corresponding stat(2) structure. This one only actually means something for character devices and block devices, so keep that in mind. ๐ If you want the major and minor device numbers pulled out of trdev, that's what the related trmajor and trminor built-ins (right below) are for.
Still only valid when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise, zero.
โ ๏ธ -Y claps back: incompatible with this built-in, broken symlinks only, returns zero.
๐ซ trmajor
The major device number of the current candidate symlink's ultimate target โ it's part of the st_rdev field of the corresponding stat(2) structure. Again: only meaningful for character devices and block devices. ๐๏ธ
Only usable when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise it's zero.
โ ๏ธ The -Y option is incompatible with this built-in. Broken symlinks only, and zero comes back.
๐ซ trminor
The minor device number of the current candidate symlink's ultimate target. Also part of the st_rdev field of the corresponding stat(2) structure, and also only meaningful for character devices and block devices. ๐๏ธ
Only for when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise: zero.
โ ๏ธ -Y is incompatible with this built-in. You'll only see broken symlinks and you'll get zero. No cap.
๐ซ tsize
The size, in bytes, of the current candidate symlink's ultimate target file โ the st_size field of the corresponding stat(2) structure. But bestie, there are layers here: ๐ฐ
- For an ultimate target that's a readable directory, this is not the
st_sizefield of the correspondingstat(2)structure. Instead it's the number of entries the directory contains (not counting.and..). - For an ultimate target that's an unreadable directory (and literally everything else), it's the usual (undocumented)
st_sizefield of the correspondingstat(2)structure.
Only use it when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise it's zero.
โ ๏ธ -Y is incompatible with this built-in. You'll only see broken symlinks, and it returns zero.
๐ซ tblksize
The preferred block size for efficient I/O on the current candidate symlink's ultimate target's filesystem โ the st_blksize field of the corresponding stat(2) structure. ๐พ On some filesystems (e.g. zfs) this is per-file rather than per-whole-filesystem, which is kind of iconic of them tbh.
๐ Heads up: this is unrelated to the tblocks built-in (next one down). Don't mix them up, iykyk.
Only used when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise, zero.
โ ๏ธ -Y is incompatible with this built-in โ broken symlinks only, and you get zero.
๐ซ tblocks
How many 512-byte blocks the current candidate symlink's ultimate target occupies โ the st_blocks field of the corresponding stat(2) structure. ๐งฑ
Only when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise it's zero.
โ ๏ธ -Y is incompatible with this built-in. Only broken symlinks, only zero.
๐ซ tatime
When the current candidate symlink's ultimate target was last accessed โ the st_atime field of the corresponding stat(2) structure. ๐
Only when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise, zero.
โ ๏ธ -Y is incompatible with this built-in. Broken symlinks only, and zero.
๐ซ tmtime
When the current candidate symlink's ultimate target's contents were last modified โ the st_mtime field of the corresponding stat(2) structure. โ๏ธ
Only when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise, zero.
โ ๏ธ -Y is incompatible with this built-in. Broken symlinks only, zero only.
๐ซ tctime
When the current candidate symlink's ultimate target's inode was last changed โ the st_ctime field of the corresponding stat(2) structure. ๐ฐ๏ธ
Only when the current candidate file is a symlink and its ultimate target exists (i.e. texists is true). Otherwise, zero.
โ ๏ธ -Y is incompatible with this built-in. Broken symlinks only, and zero.
๐ซ tstrlen
The length in bytes of the base name of the current candidate symlink's immediate target path. ๐ Lowkey important detail: this is zero if the target path is the root directory (/), because root has no base name.
This one's only used when the current candidate file is a symlink โ otherwise it's zero. But here's the slay part: the ultimate target does not need to exist. โจ
โ ๏ธ And unlike its friends above, the -Y option affects this built-in: the only symlinks you'll see are broken ones, but this built-in still returns the correct length. Main character behaviour fr fr.
๐ Pattern matching ๐
By default, string literals ("pattern") hold shell-style file glob patterns that get matched against each candidate file's base name. Want variations? Scroll down to the Pattern modifiers section, bestie. ๐
Pattern strings evaluate to true (i.e. non-zero) if the pattern match succeeds, or false (i.e. zero) otherwise.
The following POSIX glob pattern notation is supported on all platforms:
?โ Matches any single character. A leading dot character (.) is not treated as a special character, so for example?profilewould match.profile. This is unlike/bin/shbehaviour, but it's like POSIXfind(1)behaviour. ๐คฏ*โ Matches any string of characters, including the empty string. A leading dot character (.) is not treated as a special character here either โ for example*would match.profile. Again: unlike/bin/sh, like POSIXfind(1).[abc]โ Matches any single character in the given set. Ranges work too (e.g.[a-z0-9]). ๐ค[!abc]โ Matches any single character not in the given set. Ranges work here too (e.g.[!A-Z]).
๐ธ And although it's non-standard (i.e., officially undefined), on most systems you can use the more familiar^instead of!to complement the set in character classes (e.g.[^abc]) โ but not on Solaris. ๐
Locale-specific character class notation should also be available on all platforms (i.e. named character classes like [[:lower:]], collating symbols like [[.a-acute.]], and equivalence class expressions like [[=a=]]), but not all locales support all of them. ๐บ๏ธ
The special meanings of ?, * and [ can be removed by quoting them with a preceding backslash character (\).
The following Ksh extended glob pattern notation is supported on platforms with GNU glibc (i.e. Linux):
?(a|b|c)โ Matches if zero or one occurrences of any of the sub-patterns match the text.*(a|b|c)โ Matches if zero or more occurrences of any of the sub-patterns match the text.+(a|b|c)โ Matches if one or more occurrences of any of the sub-patterns match the text.@(a|b|c)โ Matches if exactly one occurrence of any of the sub-patterns matches the text.!(a|b|c)โ Matches if the text cannot be matched by any of the sub-patterns. ๐ โโ๏ธ
The special meanings of ?, *, +, @, !, (, | and ) can be removed by quoting them with a preceding backslash character (\).
The output of rh --help states if Ksh extended glob pattern notation is available on the local system. ๐ฅ๏ธ
See fnmatch(3) and glob(7) for more details.
๐ Pattern modifiers ๐
Pattern modifiers ("pattern".modifier) are suffixes you tack onto string literals โ they change how the string is interpreted and what actually gets done with it. ๐
There must be no spaces around the dot between the string literal and the modifier name.
You can give modifier names in full (e.g. "pattern".path), but a unique prefix is enough (e.g. "pattern".pat, "pattern".pa, or "pattern".p). For every modifier below, both the full name and the shortest unique prefix are shown. ๐
The following modifiers exist, but not all are available on all systems.
path (or p)
Apply the glob pattern to each candidate file's full path starting from the search directory, not just its base name. Slash characters ("/") are not treated as special characters. For example, "./sr*sc".path would match ./src/misc.
Note: since a slash character can never appear in a file's base name, if a glob pattern string with no pattern modifier does contain a slash character (e.g.,"/"), then instead of attempting (and failing ๐) to match it against the file's base name, an implicit path pattern modifier is assumed (e.g.,"/".path), and it gets matched against the file's full path starting from the search directory instead. iykyk.
link (or l)
Apply the glob pattern to each candidate symlink's target path, rather than its base name. Slash characters ("/") are not treated as special characters. For example, "./sr*sc".path would match ./src/misc.
body (or b)
Apply the glob pattern to each candidate file's contents, rather than its base name. Slash characters ("/") are not treated as special characters.
Note that this is an expensive pattern modifier, because each candidate file is read in its entirety to determine whether or not the pattern matches ๐ญ. It can be worthwhile preceding this with other predicates to reduce the number and limit the size of candidate files that this is applied to. fr fr, be smart about it.
This probably shouldn't be used with very large files. It would require a lot of memory or swap, and on 32-bit systems, the possible file size is also limited by the available address space. If this is an issue, you can always use grep(1) (or similar) via the sh "pattern" modifier instead.
Also note that this only works with regular files that are readable to the current user.
Also note that the body and ibody glob pattern modifiers shouldn't be used with binary files that might contain null bytes ๐. For binary files, use the rebody or reibody regular expression pattern modifiers instead (see below).
Note: if the current candidate file is a symlink, its body is unaffected by the-yor-Yoptions. For the purpose of this predicate, the symlink is always followed.
what (or w)
Apply the glob pattern to each candidate file's file type description (as would be output by the file(1) utility), rather than its base name. Slash characters ("/") are not treated as special characters. This is available on systems with libmagic(3) installed. slay.
Note that this is an expensive pattern modifier because each candidate file is at least partially read to determine its file type. It can be worthwhile preceding this with other predicates to reduce the number of candidate files that this is applied to.
Also note that this only works with files that are readable to the current user.
Also note that any errors encountered result in an error message taking the place of the file type description being matched ๐. To see these error messages, you can use the -L option with its %w format conversion.
Note: if the current candidate file is a symlink, its file type description is affected by the-yor-Yoptions.
mime (or m)
Apply the glob pattern to each candidate file's MIME type (including the character set), rather than its base name. Slash characters ("/") are not treated as special characters. This is available on systems with libmagic(3) installed.
Note that this is an expensive pattern modifier because each candidate file is at least partially read to determine its MIME type. It can be worthwhile preceding this with other predicates to reduce the number of candidate files that this is applied to.
Also note that this only works with files that are readable to the current user.
Also note that any errors encountered result in an error message taking the place of the MIME type being matched. To see these error messages, you can use the -L option with its %W format conversion.
Note: if the current candidate file is a symlink, its MIME type is affected by the-yor-Yoptions.
i
Apply the glob pattern without case-sensitivity โจ. This is available on most systems, but maybe not all.
The output of rh --help states if case-insensitive glob matching is available on the local system.
ipath (or ip)
Like the path modifier, but apply the glob pattern without case-sensitivity. This is available on most systems, but maybe not all.
Note: since a slash character can never appear in a file's base name, if a glob pattern string with theipattern modifier does contain a slash character (e.g.,"/".i), then instead of attempting (and failing) to match it against the file's base name, an implicitipathpattern modifier is assumed (e.g.,"/".ipath), and it will be matched against the file's full path starting from the search directory instead.
ilink (or il)
Like the link modifier, but apply the glob pattern without case-sensitivity. This is available on most systems, but maybe not all.
ibody (or ib)
Like the body modifier, but apply the glob pattern without case-sensitivity.
iwhat (or iw)
Like the what modifier, but apply the glob pattern without case-sensitivity. This is available on most systems with libmagic(3) installed, but maybe not all.
imime (or im)
Like the mime modifier, but apply the glob pattern without case-sensitivity. This is available on most systems with libmagic(3) installed, but maybe not all.
re
Match each candidate file's base name against a Perl-compatible regular expression (regex) instead of a glob pattern ๐ฅ. See perlre(1), pcre2pattern(3), and pcre2syntax(3) for details. This is available on systems that have libpcre2-8 installed.
The output of rh --help states whether or not Perl-compatible regular expressions are available on the local system.
Regex patterns are not automatically anchored to the start and end, and so do not have to match the entire text. no cap.
The following PCRE2 options are always enabled:
PCRE2_DOTALLโ the.meta-character matches any character, including the newline character. This prevents surprises when files have newline characters in their names. This is like Perl's/smodifier.PCRE2_MULTILINEโ the^meta-character matches after every internal newline character, not just at the start. The$meta-character matches before every internal newline character, not just at the end. This is useful for access control list (ACL) and extended attribute (EA) searches (see below) where the text can occupy multiple lines. This is like Perl's/mmodifier.PCRE2_EXTENDEDโ ignore (outside character classes) most whitespace characters and everything from a hash character ("#") until the end of the line. Matching a whitespace or hash character requires quoting it with a preceding backslash character ("\"). Complex regex patterns can be made more readable this way, and it enables comments in regex patterns ๐ . This is like Perl's/xmodifier.PCRE2_EXTENDED_MOREโ ignore space and tab characters inside character classes. Matching a space or tab in a character class requires quoting it with a preceding backslash character ("\"). Complex character classes can be made more readable this way. This is like Perl's/xxmodifier.PCRE2_NO_AUTO_CAPTUREโ prevent parentheses from automatically capturing matching text (i.e., always treat(...)as(?:...)). There are no uses for captures inrh(1), and this should make matching ever so slightly smaller and faster, without the explicit?:. This is like Perl's/nmodifier.
Note that the regex pattern and the text being matched are generally assumed to be encoded as UTF-8. If you need to suppress this assumption, set the environment variableRAWHIDE_PCRE2_NOT_UTF8_DEFAULT=1. When this environment variable is set, individual regex patterns can still enable UTF-8 interpretation with a leading(*UTF). This UTF-8 assumption is made when the locale uses UTF-8 (i.e., when the$LANGenvironment variable includes"UTF-8"). When the locale doesn't use UTF-8, and you wantrhto assume that everything is UTF-8 anyway, set the environment variableRAWHIDE_PCRE2_UTF8_DEFAULT=1.
repath (or rep)
Like the re modifier, but apply the regex to each candidate file's full path starting from the search directory, not just its base name.
Note: since a slash character can never appear in a file's base name, if a regex pattern string with therepattern modifier does contain a slash character (e.g.,"/".re), then instead of attempting (and failing) to match it against the file's base name, an implicitrepathpattern modifier is assumed (e.g.,"/".repath), and it will be matched against the file's full path starting from the search directory instead.
relink (or rel)
Like the re modifier, but apply the regex to each candidate symlink's target path, rather than its base name.
rebody (or reb)
Like the re modifier, but apply the regex to each candidate file's contents, rather than its base name. See body above for more details ๐.
rewhat (or rew)
Like the re modifier, but apply the regex to each candidate file's file type description, rather than its base name. This is available on systems that have libpcre2-8 and libmagic installed. See what above for more details.
remime (or rem)
Like the re modifier, but apply the regex to each candidate file's MIME type, rather than its base name. This is available on systems that have libpcre2-8 and libmagic installed. See mime above for more details.
rei
Like the re modifier, but apply the regex without case-sensitivity โจ.
reipath (or reip)
Like the repath modifier, but apply the regex without case-sensitivity.
Note: since a slash character can never appear in a file's base name, if a regex pattern string with thereipattern modifier does contain a slash character (e.g.,"/".rei), then instead of attempting (and failing) to match it against the file's base name, an implicitreipathpattern modifier is assumed (e.g.,"/".reipath), and it will be matched against the file's full path starting from the search directory instead.
reilink(orreil) โ literally therelinkmodifier, but the regex gets applied without case-sensitivity. lowercase bestie hours ๐reibody(orreib) โ same deal asrebody, except the regex is applied without case-sensitivity. ๐ซถreiwhat(orreiw) โ therewhatmodifier's chill twin: same regex, no case-sensitivity. โจreimime(orreim) โ andremime, but the regex is applied without case-sensitivity. that's the whole sentence, slay. ๐acl(ora) โ applies your glob pattern to each candidate file's access control list (ACL) instead of its base name. no cap, it's searching the ACL text itself. ๐
This one's available on systems with "POSIX" ACLs (e.g., Linux, FreeBSD, Solaris (for ufs), and Cygwin), and NFSv4 ACLs (e.g., FreeBSD and Solaris (for zfs)), and macOS with its own Extended ACLs. OpenBSD and NetBSD don't do ACLs at all โ not their era. See acl(2) or acl(3) or acl(5) for more details.
The output of rh --help states if access control lists are available on the local system.
"POSIX" ACL text is multiple lines, each one terminated by a newline character. it's giving:
user::rwx
user:name:rwx
group::rwx
group:name:rwx
mask::rwx
other::rwx
NFSv4 ACL text, though, comes in two forms, because of course it does. In the compact form, the items look like these:
owner@:rwxp--aARWcCos:-------:allow
user:name:rwxp--aARWcCos:-------:allow
group@:r-x---a-R-c--s:-------:allow
group:name:r-x---a-R-c--s:-------:allow
everyone@:r-x---a-R-c--s:-------:allow
In the non-compact form, the items each look something like this:
owner@:read_data/write_data/append_data/read_xattr/write_xattr
/execute/read_attributes/write_attributes/read_acl/write_acl
/write_owner/synchronize:allow
Searches can be made for either form. But โ ๏ธ be warned that the permission names in the non-compact form do not always appear in the same order (at least on Solaris). so don't come crying to me when your glob misses. ๐ญ
On FreeBSD, NFSv4 ACL text has each item on a separate line, terminated by a newline character, and there are leading spaces for vertical alignment before each item. On Solaris, NFSv4 ACL text is a comma-separated list of items with no leading spaces and no newline character. different fonts of the same energy fr fr.
macOS has its own Extended ACLs that look like this:
!#acl 1
user:906E2CAD-E971-12D8-ACB9-000A95DF094B:drew:502:allow:write
An easy way to see what ACLs look like on your system is:
$ rh -L '%p\n%z\n'
But bear in mind that this reformats multiple lines into a comma-separated list. That can be avoided if the locale uses UTF-8 and jq(1) is installed:
$ rh -L %j | jq -r .access_control_list
Note that glob patterns are anchored to the start and end, and so must match the entire text. the whole thing, not just a vibe. ๐ง
On Solaris, ACLs are always present by default, even if they are trivially identical to the file permission bits. This can be convenient, but if it seems like noise, it can be silenced (but only on Solaris) by setting the environment variable RAWHIDE_SOLARIS_ACL_NO_TRIVIAL=1.
iacl(oria) โ like theaclmodifier, but the glob pattern is applied without case-sensitivity. This might not be available on all systems. ๐reacl(orrea) โ like theaclmodifier, but instead of a glob pattern, it matches each candidate file's access control list (ACL) against a Perl-compatible regular expression (regex). This is available on systems that havelibpcre2-8installed, and supported access control lists. See theremodifier above for more information. โจreiacl(orreia) โ like thereaclmodifier, but the regex is applied without case-sensitivity. ๐ea(ore) โ applies the glob pattern to each candidate file's extended attributes (EA), rather than its base name. ๐ฆ
This is available on Linux, FreeBSD, macOS, Solaris, and Cygwin. OpenBSD and NetBSD don't do EAs. See xattr(1) or xattr(7) or extattr(2) or fsattr(7) for more details.
The output of rh --help states if extended attributes are available on the local system.
The extended attributes text, if any, will be possibly multiple lines, one per extended attribute, each terminated by a newline character. Each extended attribute starts with its name. If it also has a value, then the name is followed by colon and space characters (": "), and then the value. Note that on macOS, some extended attribute names contain a colon character, but they aren't typically followed by a space character. iykyk. ๐
Note that any control characters (i.e., ASCII 0-31, 127) in extended attribute names or values, and any non-ASCII bytes (i.e., 128-255) in the values, will be presented as C-like backslash escape sequences such as "\n" for the newline character, and "\0" for the null character, or as hexadecimal escape sequences such as "\x1b" for the escape character. Any backslash characters are quoted with a preceding backslash. Note that commas are not quoted. okay? okay. ๐
This encoding is the text that patterns must be written to match against. But you can still match against any text in extended attribute names, and ASCII-only text in their values, as you normally would. whew. ๐ญ
Note that glob patterns are anchored to the start and end, and so must match the entire text. no partial credit, bestie. โญ
On FreeBSD, extended attributes in the user namespace are presented with "user." as a prefix to their actual name, and those in the system namespace are presented with "system." as a name prefix. On FreeBSD, only the root user may see extended attributes in the system namespace. main character privileges only. ๐
On most systems with extended attributes, the values are typically only up to a few hundred bytes in size. But on Solaris, extended attributes take the form of regular files in a special extended attributes directory "hidden" inside each real file. Entire files can be copied into that special directory, and they become extended attributes. So extended attributes could tend to be larger on Solaris. it's built different. ๐ฅ
The default maximum total size for (encoded) extended attributes is 4KiB on most systems, and 64KiB on Solaris. If this is not enough, extended attributes will be silently truncated. โ ๏ธ This affects extended attribute searching (ea), and the -L %x format conversion. To prevent truncation, set the environment variable RAWHIDE_EA_SIZE to a positive integer value that is large enough for your needs. Note that the value must be the size in bytes. Scale units are not supported. just the number, babes. ๐
On Solaris, every file's extended attributes directory contains the SUNWattr_ro and SUNWattr_rw extended attributes. By default, they are included for every file that has any other extended attributes. They can be excluded by setting the environment variable RAWHIDE_SOLARIS_EA_NO_SUNWATTR=1.
Also on Solaris, since extended attributes are files (of a sort), they each have their own stat(2) information. By default, this information is represented as an artificial extended attribute whose name is the name of the corresponding real extended attribute followed by "/stat". These artificial extended attributes have the following format:
name/stat: -rw-r--r-- nlink user group size mtime atime ctime
The name is the name of the corresponding real extended attribute. The "/stat:" is literal. The nlink is always 1. The user and group are names or numeric IDs. The size is in bytes. The mtime, atime, and ctime are in ISO date/time format ("YYYY-MM-DD HH:MM:SS +HHMM"). ๐ธ
This makes it possible on Solaris to search for files by the stat(2) information of their extended attributes. But it can only be a text-based search (glob or regex). text-based only, ngl. ๐
These artificial extended attributes can be suppressed by setting the environment variable RAWHIDE_SOLARIS_EA_NO_STATINFO=1.
iea(orie) โ like theeamodifier, but the glob pattern is applied without case-sensitivity. This might not be available on all systems. ๐reea(orree) โ like theeamodifier, but matches each candidate file's extended attributes (EA) against a Perl-compatible regular expression (regex) instead of a glob pattern. This is available on systems that havelibpcre2-8installed, and supported extended attributes. See theremodifier above for more information. ๐ฆreiea(orreie) โ like thereeamodifier, but the regex is applied without case-sensitivity. โจsh(ors) โ okay so this one does NOT treat the string literal as a pattern at all. it treats it as an external shell command to execute viasystem(3)(i.e., via/bin/sh). It evaluates to the exit success status of the external shell command. If its exit status is zero, then the value is true (i.e., non-zero). Otherwise, it is false (i.e., zero). iconic logic, honestly. ๐
This enables arbitrary command line utilities to contribute to the search criteria. But โ ๏ธ be warned, this can be slow, because it involves the creation of possibly many other processes. But it makes many things possible. To reduce the number of external shell commands that need to be executed, the sh "pattern" modifier can be used conditionally with the ?: or || or && operator (see above). work smarter, not harder. ๐ง
The string can contain %s which will be replaced with the matching entry's full path starting from the search directory. It can also contain %S which will be replaced with the matching entry's base name (or with "/" when the matching entry is the root directory (/) which has no base name). For example, given the matching file /etc/passwd, %s and %S would be replaced with "/etc/passwd" and "passwd", respectively. To include a literal per cent sign ("%") in the shell command, use %%. It is an error if % is not followed by s, S, or %. ๐ฅ
Any shell meta-characters in the interpolated path or base name are quoted with preceding backslash characters ("\") to prevent shell command injection, so there is no need to place any quote characters around %s or %S. she's safe, she's careful, she ate. ๐
Every shell command is executed after safely changing the current working directory to the directory containing each candidate file. This minimizes the number of path-based race conditions. So the %S interpolation is more likely to be useful than the %s interpolation. ๐ซถ
And if the user's $PATH environment variable includes the current working directory, or any other non-absolute paths, that could be dangerous, so they are automatically removed first. ๐ no cap, that's a real safety thing, don't @ me.
โ ๏ธ Heads up bestie: since the shell commands run from the directory that holds each matching entry, if they actually need the matching entry's full path counted from the search directory (i.e.%s), then it's so much better if your starting search paths are all absolute paths, so%sis always an absolute path. Otherwise the shell command might have to change its current working directory back to the initial working directory. Also,%ssuffers from a whole bunch of path-based race conditions, which is insecure on hosts with malicious local actors who have write access to the directory tree being searched โ so like, don't generally use it, fr fr.
๐ Reference file fields ๐
Reference file fields ("/path".field) are suffixes you tack onto string literals, and they represent the inode metadata of arbitrary reference files โ all for the purpose of comparison. Important: there must be no spaces around the dot between the path string and the field name. None. Zero. Nada. ๐
If the path is the empty string (e.g., "".field), then it refers to the most recent reference file path the parser encountered. This makes multiple references to the same reference file way more concise (e.g., "/path".exists && mtime > "".mtime). Iconic, honestly.
Here's the full lineup of reference file fields available ๐
existsโ This is true (i.e., non-zero) when the reference file exists (i.e., whenrh(1)can obtain itsstat(2)structure information). Watch out though: a false value (i.e., zero) might be caused by permissions, not by the file not existing. ๐
If there's any chance the reference file does not exist, then exists must be used to determine whether the rest of the reference file fields can even be used. If a reference file doesn't exist and any of its stat(2) structure fields below get used in a file test expression, an error message will be output and rh(1) will terminate with a non-zero exit status. So exists is meant to be used with the ?: or || or && operator (see above) to conditionally use any of the following stat(2) structure fields (e.g., "/path".exists && size > "".size). ๐ซถ
devโ The device number of the device/filesystem that the reference file resides on. This is thest_devfield of the correspondingstat(2)structure. Peep the relatedmajorandminorreference file fields (next) for extracting the major and minor device numbers fromdev.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
majorโ The major device number of the device/filesystem that the reference file resides on. This is part of thest_devfield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
minorโ The minor device number of the device/filesystem that the reference file resides on. This is part of thest_devfield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
inoโ The inode number of the reference file. This is thest_inofield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
modeโ The mode of the reference file. This is thest_modefield of the correspondingstat(2)structure. It contains the file type and the permissions. See the relatedtypeandpermreference file fields (next) for extracting the file type and permissions frommode.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
typeโ The file type of the reference file (i.e., an alias formode & IFMT).
It's an error to use this if the reference file doesn't exist. See exists above. ๐
permโ The file permissions of the reference file (i.e., an alias formode & ~IFMT).
It's an error to use this if the reference file doesn't exist. See exists above. ๐
nlinkโ The number of hard links to the reference file. This is thest_nlinkfield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
uidโ The user ID of the owner of the reference file. This is thest_uidfield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
gidโ The group ID of the group of the reference file. This is thest_gidfield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
rdevโ The device number of the reference file. This is thest_rdevfield of the correspondingstat(2)structure. This one's only meaningful for character devices and block devices. See the relatedrmajorandrminorreference file fields (next) for extracting the major and minor device numbers fromrdev.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
rmajorโ The major device number of the reference file. This is part of thest_rdevfield of the correspondingstat(2)structure. Only meaningful for character devices and block devices.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
rminorโ The minor device number of the reference file. This is part of thest_rdevfield of the correspondingstat(2)structure. Only meaningful for character devices and block devices.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
sizeโ The size in bytes of the reference file. This is thest_sizefield of the correspondingstat(2)structure. But okay, plot twist, it depends on what you're looking at ๐- For reference files that are symlinks (that aren't followed with the
-yor-Yoption), this is the length in bytes of the target path. - For reference files that are readable directories, this is not the
st_sizefield of the correspondingstat(2)structure. Instead, it's the number of entries it contains (excluding.and..). - For reference files that are unreadable directories (and everything else), this is the usual (undocumented)
st_sizefield of the correspondingstat(2)structure.
- For reference files that are symlinks (that aren't followed with the
It's an error to use this if the reference file doesn't exist. See exists above. ๐
blksizeโ The preferred block size for efficient I/O on the reference file's filesystem. This is thest_blksizefield of the correspondingstat(2)structure. On some filesystems (e.g., zfs), this is specific to each file, rather than to the whole filesystem.
Note that this is unrelated to the blocks reference file field (see next). Don't get them mixed up bestie ๐
It's an error to use this if the reference file doesn't exist. See exists above. ๐
blocksโ The number of 512-byte blocks occupied by the reference file. This is thest_blocksfield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
atimeโ The time that the reference file was last accessed. This is thest_atimefield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
mtimeโ The time that the reference file's contents were last modified. This is thest_mtimefield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
ctimeโ The time that the reference file's inode was last changed. This is thest_ctimefield of the correspondingstat(2)structure.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
attrโ On Linux, the reference file's ext2-style file attribute bit mask. Not all file systems support all file attributes. Seechattr(1)andlsattr(1)for details. See/etc/rawhide.conf.d/attributesfor all the related constants (e.g.,ATTR_IMMUTABLE,ATTR_APPEND, โฆ).
It's an error to use this if the reference file doesn't exist. See exists above. ๐
Note: If the reference file is a symlink, it is never followed for the purpose of obtaining the file attributes. This is a decision made by libe2p. This is not affected by the-yor-Yoptions. Also note that symlinks don't have their own file attributes (i.e.,attris zero). ๐
On Linux, this is only available on systems with libe2p. On Linux systems without libe2p, this is not a built-in symbol. Instead, it's a place-holder function that returns zero.
This is also available on FreeBSD, OpenBSD, NetBSD, and macOS. The attributes/flags that are available vary from system to system. See chflags(1) for details. See /etc/rawhide.conf.d/attributes for all the related predicate functions (e.g., uimmutable, uappend, nodump, opaque, โฆ).
On other systems, this doesn't exist at all. ๐
projโ On Linux, the reference file's ext2-style file project number. Not all file systems support all file attributes. Seechattr(1)andlsattr(1)for details.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
Note: If the reference file is a symlink, it is always followed for the purpose of obtaining the file project. This is not affected by the-yor-Yoptions.
Note: This is only available on Linux systems with libe2p. On other systems, this doesn't exist at all.
genโ On Linux, the reference file's ext2-style version/generation number. Not all file systems support all file attributes. Seechattr(1)andlsattr(1)for details.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
Note: If the reference file is a symlink, it is always followed for the purpose of obtaining the file version/generation. This is not affected by the-yor-Yoptions.
Note: This is only available on Linux systems with libe2p. On other systems, this doesn't exist at all.
strlenโ The length in bytes of the base name of the reference file. Note that this is zero if the reference file is the root directory (/), which has no base name. ๐inodeโ An alias forino.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
nlinksโ An alias fornlink.
It's an error to use this if the reference file doesn't exist. See exists above. ๐
userโ An alias foruid.groupโ an alias forgid๐
โ ๏ธ It is an error to use this if the reference file does not exist. See exists above.
szโ an alias forsizeโจ
โ ๏ธ It is an error to use this if the reference file does not exist. See exists above.
accessedโ an alias foratime๐
โ ๏ธ It is an error to use this if the reference file does not exist. See exists above.
modifiedโ an alias formtime๐
โ ๏ธ It is an error to use this if the reference file does not exist. See exists above.
changedโ an alias forctime๐
โ ๏ธ It is an error to use this if the reference file does not exist. See exists above.
lenโ an alias forstrlen๐
๐ EXAMPLES ๐
okay bestie, this is the moment. this right here is the default /etc/rawhide.conf standard library, in all its glory. it's long, it's iconic, it ate, and you're gonna read it ๐
# /etc/rawhide.conf: rh system-wide configuration.
# See rh(1) and rawhide.conf(5) for more information.
/*
This file constitutes the rawhide standard library.
On some systems, this file could be somewhere other than /etc
(e.g., /usr/local/etc, /opt/local/etc, /usr/pkg/etc).
You can modify this file, and/or place additional files
in the /etc/rawhide.conf.d directory.
They'll be read after this file, in lexicographic order.
Any files whose names start with dot are skipped.
You can also create your own user-specific rawhide
functions in ~/.rhrc and ~/.rhrc.d/*. They'll be read
by rh in the same manner after these system-wide files.
*/
// File types (canonical, aliases)
type { mode & IFMT }
reg { type == IFREG }
dir { type == IFDIR }
blk { type == IFBLK }
chr { type == IFCHR }
lnk { type == IFLNK }
sock { type == IFSOCK }
fifo { type == IFIFO }
door { type == IFDOOR } # Solaris
file { reg }
directory { dir }
block { blk }
char { chr }
device { blk || chr }
symlink { lnk }
link { lnk }
socket { sock }
namedpipe { fifo }
pipe { fifo }
f { reg }
d { dir }
b { blk }
c { chr }
l { lnk }
s { sock }
p { fifo }
D { door } # Solaris
// File permissions (canonical, aliases, helpers)
perm { mode & ~IFMT }
ur { perm & IRUSR }
uw { perm & IWUSR }
ux { perm & IXUSR }
gr { perm & IRGRP }
gw { perm & IWGRP }
gx { perm & IXGRP }
or { perm & IROTH }
ow { perm & IWOTH }
ox { perm & IXOTH }
wr { perm & IROTH }
ww { perm & IWOTH }
wx { perm & IXOTH }
user_readable { ur }
user_writable { uw }
user_executable { ux }
group_readable { gr }
group_writable { gw }
group_executable { gx }
other_readable { or }
other_writable { ow }
other_executable { ox }
world_readable { wr }
world_writable { ww }
world_executable { wx }
suid { perm & ISUID }
sgid { perm & ISGID }
svtx { perm & ISVTX }
setuid { suid }
setgid { sgid }
sticky { svtx }
all(bitmask) { (perm & bitmask) == bitmask }
any(bitmask) { perm & bitmask }
none(bitmask) { !any(bitmask) }
allr { all(IRUSR | IRGRP | IROTH) }
allw { all(IWUSR | IWGRP | IWOTH) }
allx { all(IXUSR | IXGRP | IXOTH) }
anyr { any(IRUSR | IRGRP | IROTH) }
anyw { any(IWUSR | IWGRP | IWOTH) }
anyx { any(IXUSR | IXGRP | IXOTH) }
noner { !anyr }
nonew { !anyw }
nonex { !anyx }
all_readable { allr }
all_writable { allw }
all_executable { allx }
any_readable { anyr }
any_writable { anyw }
any_executable { anyx }
none_readable { noner }
none_writable { nonew }
none_executable { nonex }
// Aliases for built-ins
inode { ino }
nlinks { nlink }
user { uid }
group { gid }
space { blocks * 512 }
accessed { atime }
modified { mtime } # Refers to the contents
changed { ctime } # Refers to the inode
len { strlen }
sz { size }
seconds { second }
minutes { minute }
hours { hour }
days { day }
weeks { week }
months { month }
years { year }
quit { exit }
imayread { readable } # Uses access(2) not perm
imaywrite { writable } # Uses access(2) not perm
imayexec { executable } # Uses access(2) not perm
ir { readable }
iw { writable }
ix { executable }
// File types for symlink targets (canonical, aliases)
ttype { tmode & IFMT }
treg { ttype == IFREG }
tdir { ttype == IFDIR }
tblk { ttype == IFBLK }
tchr { ttype == IFCHR }
tsock { ttype == IFSOCK }
tfifo { ttype == IFIFO }
tdoor { ttype == IFDOOR } # Solaris
tfile { treg }
tdirectory { tdir }
tblock { tblk }
tchar { tchr }
tdevice { tblk || tchr }
tsocket { tsock }
tnamedpipe { tfifo }
tpipe { tfifo }
tf { treg }
td { tdir }
tb { tblk }
tc { tchr }
ts { tsock }
tp { tfifo }
tD { tdoor } # Solaris
target_type { ttype }
target_reg { treg }
target_dir { tdir }
target_blk { tblk }
target_chr { tchr }
target_sock { tsock }
target_fifo { tfifo }
target_door { tdoor } # Solaris
target_file { treg }
target_directory { tdir }
target_block { tblk }
target_char { tchr }
target_device { tblk || tchr }
target_socket { tsock }
target_namedpipe { tfifo }
target_pipe { tfifo }
target_f { treg }
target_d { tdir }
target_b { tblk }
target_c { tchr }
target_s { tsock }
target_p { tfifo }
target_D { tdoor }
// File permissions for symlink targets (canonical, aliases, helpers)
tperm { tmode & ~IFMT }
tur { tperm & IRUSR }
tuw { tperm & IWUSR }
tux { tperm & IXUSR }
tgr { tperm & IRGRP }
tgw { tperm & IWGRP }
tgx { tperm & IXGRP }
tor { tperm & IROTH }
tow { tperm & IWOTH }
tox { tperm & IXOTH }
twr { tperm & IROTH }
tww { tperm & IWOTH }
twx { tperm & IXOTH }
target_perm { tperm }
target_ur { tur }
target_uw { tuw }
target_ux { tux }
target_gr { tgr }
target_gw { tgw }
target_gx { tgx }
target_or { tor }
target_ow { tow }
target_ox { tox }
target_wr { twr }
target_ww { tww }
target_wx { twx }
target_user_readable { tur }
target_user_writable { tuw }
target_user_executable { tux }
target_group_readable { tgr }
target_group_writable { tgw }
target_group_executable { tgx }
target_other_readable { tor }
target_other_writable { tow }
target_other_executable { tox }
target_world_readable { twr }
target_world_writable { tww }
target_world_executable { twx }
tsuid { tperm & ISUID }
tsgid { tperm & ISGID }
tsvtx { tperm & ISVTX }
tsetuid { tsuid }
tsetgid { tsgid }
tsticky { tsvtx }
target_suid { tsuid }
target_sgid { tsgid }
target_svtx { tsvtx }
target_setuid { tsuid }
target_setgid { tsgid }
target_sticky { tsvtx }
tall(bitmask) { (tperm & bitmask) == bitmask }
tany(bitmask) { tperm & bitmask }
tnone(bitmask) { !tany(bitmask) }
tallr { tall(IRUSR | IRGRP | IROTH) }
tallw { tall(IWUSR | IWGRP | IWOTH) }
tallx { tall(IXUSR | IXGRP | IXOTH) }
tanyr { tany(IRUSR | IRGRP | IROTH) }
tanyw { tany(IWUSR | IWGRP | IWOTH) }
tanyx { tany(IXUSR | IXGRP | IXOTH) }
tnoner { !tanyr }
tnonew { !tanyw }
tnonex { !tanyx }
target_all(bitmask) { tall(bitmask) }
target_any(bitmask) { tany(bitmask) }
target_none(bitmask) { tnone(bitmask) }
target_allr { tallr }
target_allw { tallw }
target_allx { tallx }
target_anyr { tanyr }
target_anyw { tanyw }
target_anyx { tanyx }
target_noner { tnoner }
target_nonew { tnonew }
target_nonex { tnonex }
target_all_readable { tallr }
target_all_writable { tallw }
target_all_executable { tallx }
target_any_readable { tanyr }
target_any_writable { tanyw }
target_any_executable { tanyx }
target_none_readable { tnoner }
target_none_writable { tnonew }
target_none_executable { tnonex }
// Aliases for symlink target built-ins
target_exists { texists }
target_dev { tdev }
target_ino { tino }
target_mode { tmode }
target_nlink { tnlink }
target_uid { tuid }
target_gid { tgid }
target_rdev { trdev }
target_size { tsize }
target_blksize { tblksize }
target_blocks { tblocks }
target_atime { tatime }
target_mtime { tmtime }
target_ctime { tctime }
target_strlen { tstrlen }
tinode { tino }
tnlinks { tnlink }
tuser { tuid }
tgroup { tgid }
tspace { tblocks * 512 }
taccessed { tatime }
tmodified { tmtime } # Refers to the target's contents
tchanged { tctime } # Refers to the target's inode
tlen { tstrlen }
tsz { tsize }
target_inode { tinode }
target_nlinks { tnlinks }
target_user { tuser }
target_group { tgroup }
target_space { tspace }
target_accessed { taccessed }
target_modified { tmodified }
target_changed { tchanged }
target_len { tlen }
target_sz { tsz }
// Aliases for size units
KiB { 1K }
MiB { 1M }
GiB { 1G }
TiB { 1T }
PiB { 1P }
EiB { 1E }
KB { 1k }
MB { 1m }
GB { 1g }
TB { 1t }
PB { 1p }
EB { 1e }
// Miscellaneous helper functions
empty { size == 0 } # Only for files and readable directories
roots { uid == 0 }
mine { uid == $$ }
ours { gid == @@ }
broken { symlink && !texists }
dangling { broken }
gmtoday { now - now % day }
ago(sec) { now - sec }
old(sec) { mtime <= ago(sec) }
past(sec) { mtime >= ago(sec) }
min(x, y) { (x < y) ? x : y }
max(x, y) { (x > y) ? x : y }
abs(x) { (x < 0) ? -x : x }
// Examples
๐ฆ that's the whole standard library bestie, every single alias, every perm helper, every target_* twin, every size unit, every lil miscellaneous function โ no cap, it's all there ๐
and the actual examples are literally about to start, so don't you dare close the tab ๐ซถ
// Complex tests can be very readable (and/or very concise)
// rootshell { setuid && roots && (group_writable | other_writable) }
// rootshell { suid && roots && (gw | ow) }
// csrc { "*.[ch]" || "[Mm]akefile" }
// oldaout { "a.out" && f && old(week) }
// oldcore { "^core(\.\d+)?$".re && f && old(week) }
// bad { oldaout || oldcore || "*.BAK" || "*.CKP" || (gw | ow) }
// Note: Read "<" and ">" as before/after, not as less/more than
// recent { modified >= ago(hour) }
// Silly recursive functions are possible (but not mutual recursion)
// sqrt1(n, odd) { (n <= 0) ? 0 : sqrt1(n - odd, odd + 2) + 1 }
// sqrt(n) { sqrt1(n, 1) }
// prime1(n, i) { (i * i > n) ? 1 : !(n % i) ? 0 : prime1(n, i + 2) }
// prime(n) { (n < 2) ? 0 : !(n % 2) ? n == 2 : prime1(n, 3) }
// factorial(x) { (x > 0) ? x * factorial(x - 1) : 1 }
// ack(x, y) { !x ? y+1 : !y ? ack(x-1, 1) : ack(x-1, ack(x, y-1)) }
okay but these are actually so iconic ๐
The manpage literally says complex tests can be very readable (and/or very concise) โ so like, both is allowed, bestie. Look at rootshell { setuid && roots && (group_writable | other_writable) } โ that's main character energy, so readable. And then the same thing in its little crop-top version: rootshell { suid && roots && (gw | ow) }. The way that brevity ate. ๐ฅ
And there's a note in there you need to clock: read < and > as before/after, not as less/more than. So recent { modified >= ago(hour) } is "modified at-or-after an hour ago", not some number-comparison situation. iykyk. ๐
Then the silly recursive functions โ yes, they're a thing, and the manpage's own phrasing is "Silly recursive functions are possible (but not mutual recursion)". So: recursion slays, mutual recursion is not invited to the group chat. ๐ And ack(x, y) { !x ? y+1 : !y ? ack(x-1, 1) : ack(x-1, ack(x, y-1)) } โ the Ackermann function is just casually sitting in your config file like it pays rent. Obsessed.
(Also notice: those example lines are all sitting behind // in the file. They're there so you can read them, not so they run. ๐ธ)
Now the brevity era:
The following aliases provide greater brevity for some built-ins. Perhaps they could have gone into the standard library, but you might have better uses for these identifiers.
translation: these names are yours, so don't come crying if you wanted w for something else ๐ซถ
// Brevity (aliases)
i { ino }
n { nlink }
u { uid }
g { gid }
a { atime }
m { mtime }
su { suid }
sg { sgid }
nu { nouser }
ng { nogroup }
r { readable }
w { writable }
x { executable }
q { exit }
sec { second }
mn { minute }
hr { hour }
dy { day }
wk { week }
mth { month }
yr { year }
Not q { exit } being one whole letter for exit ๐ญ literally the shortest goodbye ever. And the time units are all lined up so cute: sec, mn, hr, dy, wk, mth, yr. It's giving organized. โจ
๐ฅ๏ธ the Linux attribute library ๐ง
On Linux systems with libe2p, this is the /etc/rawhide.conf.d/attributes library:
# /etc/rawhide.conf.d/attributes (Linux)
# See rh(1) and rawhide.conf(5) for more information.
/*
This file defines aliases for the built-in symbols for the
Linux ext2-style file attributes, and the related constants
and predicates. See <e2p/e2p.h> and <ext2fs/ext2_fs.h>.
*/
// Aliases for the Linux ext2-style attribute built-ins
flag { attr }
flags { attr }
attrs { attr }
attribute { attr }
attributes { attr }
project { proj }
generation { gen }
// Attribute constants from <ext2fs/ext2_fs.h>
ATTR_SECRM { 0x00000001 } # Secure deletion
ATTR_UNRM { 0x00000002 } # Undelete
ATTR_COMPR { 0x00000004 } # Compress file
ATTR_SYNC { 0x00000008 } # Synchronous updates
ATTR_IMMUTABLE { 0x00000010 } # Immutable file
ATTR_APPEND { 0x00000020 } # Writes to file may only append
ATTR_NODUMP { 0x00000040 } # Do not dump file
ATTR_NOATIME { 0x00000080 } # Do not update atime
ATTR_DIRTY { 0x00000100 }
ATTR_COMPRBLK { 0x00000200 } # One or more compressed clusters
ATTR_NOCOMPR { 0x00000400 } # Access raw compressed data
ATTR_ENCRYPT { 0x00000800 } # Encrypted
ATTR_BTREE { 0x00001000 } # Btree format directory
ATTR_INDEX { 0x00001000 } # Hash-indexed directory
ATTR_IMAGIC { 0x00002000 }
ATTR_JOURNAL_DATA { 0x00004000 } # File data should be journaled
ATTR_NOTAIL { 0x00008000 } # File tail should not be merged
ATTR_DIRSYNC { 0x00010000 } # Synchronous dir modifications
ATTR_TOPDIR { 0x00020000 } # Top of directory hierarchies
ATTR_HUGE_FILE { 0x00040000 } # Set to each huge file
ATTR_EXTENTS { 0x00080000 } # Inode uses extents
ATTR_VERITY { 0x00100000 } # Verity protected inode
ATTR_EA_INODE { 0x00200000 } # Inode used for large EA
ATTR_NOCOW { 0x00800000 } # Do not cow file
ATTR_SNAPFILE { 0x01000000 } # Inode is a snapshot
ATTR_DAX { 0x02000000 } # Inode is DAX
ATTR_SNAPFILE_DELETED { 0x04000000 } # Snapshot is being deleted
ATTR_SNAPFILE_SHRUNK { 0x08000000 } # Snapshot shrink has completed
ATTR_INLINE_DATA { 0x10000000 } # Inode has inline data
ATTR_PROJINHERIT { 0x20000000 } # Create with parents projid
ATTR_CASEFOLD { 0x40000000 } # Casefolded file
// Attribute predicates (canonical, aliases)
secrm { attr & ATTR_SECRM }
unrm { attr & ATTR_UNRM }
compr { attr & ATTR_COMPR }
sync { attr & ATTR_SYNC }
immutable { attr & ATTR_IMMUTABLE }
append { attr & ATTR_APPEND }
nodump { attr & ATTR_NODUMP }
noatime { attr & ATTR_NOATIME }
dirty { attr & ATTR_DIRTY }
comprblk { attr & ATTR_COMPRBLK }
nocompr { attr & ATTR_NOCOMPR }
encrypt { attr & ATTR_ENCRYPT }
btree { attr & ATTR_BTREE }
index { attr & ATTR_INDEX }
imagic { attr & ATTR_IMAGIC }
journal_data { attr & ATTR_JOURNAL_DATA }
notail { attr & ATTR_NOTAIL }
dirsync { attr & ATTR_DIRSYNC }
topdir { attr & ATTR_TOPDIR }
huge_file { attr & ATTR_HUGE_FILE }
extents { attr & ATTR_EXTENTS }
verity { attr & ATTR_VERITY }
ea_inode { attr & ATTR_EA_INODE }
nocow { attr & ATTR_NOCOW }
snapfile { attr & ATTR_SNAPFILE }
dax { attr & ATTR_DAX }
snapfile_deleted { attr & ATTR_SNAPFILE_DELETED }
snapfile_shrunk { attr & ATTR_SNAPFILE_SHRUNK }
inline_data { attr & ATTR_INLINE_DATA }
projinherit { attr & ATTR_PROJINHERIT }
casefold { attr & ATTR_CASEFOLD }
secure_deletion { secrm }
undelete { unrm }
compressed { compr }
synchronous { sync }
append_only { append }
nocompression { nocompr }
encrypted { encrypt }
indexed { index }
direct_access { dax }
inherit_project { projinherit }
attr_s { secrm }
attr_u { unrm }
attr_c { compr }
attr_S { sync }
attr_i { immutable }
attr_a { append }
attr_d { nodump }
attr_A { noatime }
attr_m { nocompr }
attr_E { encrypt }
attr_I { index }
attr_j { journal_data }
attr_t { notail }
attr_D { dirsync }
attr_T { topdir }
attr_e { extents }
attr_V { verity }
attr_C { nocow }
attr_x { dax }
attr_N { inline_data }
attr_P { projinherit }
attr_F { casefold }
three layers of aliasing, bestie โ the canonical predicates, the โจfancy long namesโจ like append_only and inherit_project, and then the single-letter attr_* ones for when you're typing with one hand and holding a boba with the other. ๐ง
Real talk: don't retype these from memory, copy-paste exists. The hex values are literally character-for-character facts and one flipped digit is a whole different attribute. ๐ญ
๐ก the FreeBSD attribute library ๐ฆ
On FreeBSD systems, this is the /etc/rawhide.conf.d/attributes library. There is a similar file on OpenBSD, NetBSD, and macOS systems:
# /etc/rawhide.conf.d/attributes (FreeBSD)
# See rh(1) and rawhide.conf(5) for more information.
/*
This file defines aliases for the built-in symbols for FreeBSD file
flags, and the related constants and predicates. See <sys/stat.h>.
*/
// Aliases for the FreeBSD file flags built-ins
flag { attr }
flags { attr }
attrs { attr }
attribute { attr }
attributes { attr }
project { 0 }
generation { 0 }
// Flag constants from <sys/stat.h>
# Super-user and owner changeable flags
UF_SETTABLE { 0x0000ffff } # mask of owner changeable flags
UF_NODUMP { 0x00000001 } # do not dump file
UF_IMMUTABLE { 0x00000002 } # file may not be changed
UF_APPEND { 0x00000004 } # writes to file may only append
UF_OPAQUE { 0x00000008 } # directory is opaque wrt. union
UF_NOUNLINK { 0x00000010 } # file may not be removed or renamed
UF_SYSTEM { 0x00000080 } # Windows system file bit
UF_SPARSE { 0x00000100 } # sparse file
UF_OFFLINE { 0x00000200 } # file is offline
UF_REPARSE { 0x00000400 } # Windows reparse point file bit
UF_ARCHIVE { 0x00000800 } # file needs to be archived
UF_READONLY { 0x00001000 } # Windows readonly file bit
UF_HIDDEN { 0x00008000 } # file is hidden [same as macOS]
# Super-user changeable flags
SF_SETTABLE { 0xffff0000 } # mask of superuser changeable flags
SF_ARCHIVED { 0x00010000 } # file is archived
SF_IMMUTABLE { 0x00020000 } # file may not be changed
SF_APPEND { 0x00040000 } # writes to file may only append
SF_NOUNLINK { 0x00100000 } # file may not be removed or renamed
SF_SNAPSHOT { 0x00200000 } # snapshot inode
// Flag predicates (canonical, aliases)
arch { attr & SF_ARCHIVED }
archived { attr & SF_ARCHIVED }
nodump { attr & UF_NODUMP }
opaque { attr & UF_OPAQUE }
sappnd { attr & SF_APPEND }
sappend { attr & SF_APPEND }
schg { attr & UF_IMMUTABLE }
schange { attr & UF_IMMUTABLE }
simmutable { attr & UF_IMMUTABLE }
snapshot { attr & SF_SNAPSHOT }
sunlnk { attr & SF_NOUNLINK }
sunlink { attr & SF_NOUNLINK }
uappnd { attr & UF_APPEND }
uappend { attr & UF_APPEND }
uarch { attr & UF_ARCHIVE }
uarchive { attr & UF_ARCHIVE }
uchg { attr & SF_IMMUTABLE }
uchange { attr & SF_IMMUTABLE }
uimmutable { attr & SF_IMMUTABLE }
uhidden { attr & UF_HIDDEN }
hidden { attr & UF_HIDDEN }
uoffline { attr & UF_OFFLINE }
offline { attr & UF_OFFLINE }
urdonly { attr & UF_READONLY }
rdonly { attr & UF_READONLY }
readonly { attr & UF_READONLY }
usparse { attr & UF_SPARSE }
sparse { attr & UF_SPARSE }
usystem { attr & UF_SYSTEM }
system { attr & UF_SYSTEM }
ureparse { attr & UF_REPARSE }
reparse { attr & UF_REPARSE }
uunlnk { attr & UF_NOUNLINK }
uunlink { attr & UF_NOUNLINK }
append { uappend | sappend }
immutable { uimmutable | simmutable }
nounlink { uunlink | sunlink }
unlink { uunlink | sunlink }
Not the project { 0 } and generation { 0 } โ FreeBSD said "no projid era for me, have a zero ๐ซถ" and honestly, respect. And at the bottom it does the cute thing where append, immutable, nounlink and unlink just OR both the u and s versions together so you don't have to care which one it is. Convenience queen behavior. ๐
See rh(1) for more examples.
๐ FILES ๐
okay so these are the source/config files that get read by default, bestie:
/etc/rawhide.confโ the main system-wide configuration/etc/rawhide.conf.d/*โ extra system-wide configuration~/.rhrcโ the main user-specific configuration~/.rhrc.d/*โ extra user-specific configuration
plot twist: the system-wide config might live somewhere else depending on your operating systemโs preferences, like /usr/local/etc, /opt/local/etc, or /usr/pkg/etc. very โyour mileage may varyโ of it. ๐
the output of rh --help tells you where the system-wide configuration files are on your local system, so if youโre ever like โwhere did they put it ๐ญโ, thatโs the move.
the location of the main system-wide configuration file (/etc/rawhide.conf, or similar) can be overridden with the environment variable RAWHIDE_CONFIG. heads up though: this is only available to non-root users, as it could be dangerous for root. the directory containing any additional system-wide configuration files is derived from it by appending .d.
same energy for the user side: the location of the main user-specific configuration file (~/.rhrc) can be overridden with the environment variable RAWHIDE_RC. this is only available to non-root users too, as it could be dangerous for root. and the directory containing any additional user-specific configuration files is derived from it by appending .d. consistent queen behavior tbh โจ
๐ SEE ALSO ๐
go off and read these too, bestie: rh(1), stat(2), mktime(3), fnmatch(3), glob(7), perlre(1), pcre2pattern(3), pcre2syntax(3), access(2), acl(2) or acl(3) or acl(5), xattr(1) or xattr(7) or extattr(2) or fsattr(7), chattr(1), lsattr(1), chflags(1), file(1), jq(1), and The C programming language. the lore is deep ๐
๐ AUTHORS ๐
- 1990 โ Ken Stauffer (University of Calgary)
- 2022-2023 โ
raf <raf@raf.org>
and thatโs the whole page, bestie ๐ซถ this lil manual moment is from rawhide-3.3, dated 20231013 โ iconic, documented, and done. ๐
โจ
๐ฆ where this page comes from
- opensuse-leap 16.0: rawhide 3.3-bp160.1.12 ยท GPL-3.0-or-later AND BSD-3-Clause
- opensuse-leap 16.0: rawhide 3.3-bp160.1.12 ยท GPL-3.0-or-later AND BSD-3-Clause
- opensuse-leap 16.0: rawhide 3.3-bp160.1.12 ยท GPL-3.0-or-later AND BSD-3-Clause
- opensuse-leap 16.0: rawhide 3.3-bp160.1.12 ยท GPL-3.0-or-later AND BSD-3-Clause
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms