udev-rules.c revision 91418155ae9034f466d436c314cd136309bc557d
7c66aeba0f28cb82027d6015405ed71afa3b6059Kay Sievers * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
7c66aeba0f28cb82027d6015405ed71afa3b6059Kay Sievers * Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
c904f64d84db8c4eebedf210ba10893f19ba05edLennart Poettering * This program is free software: you can redistribute it and/or modify
f957632b960a0a42999b38ded7089fa602b41745Kay Sievers * it under the terms of the GNU General Public License as published by
f957632b960a0a42999b38ded7089fa602b41745Kay Sievers * the Free Software Foundation, either version 2 of the License, or
f957632b960a0a42999b38ded7089fa602b41745Kay Sievers * (at your option) any later version.
9a36607584bbd1d78775353e022a51794b4e27b1Lennart Poettering * This program is distributed in the hope that it will be useful,
9a36607584bbd1d78775353e022a51794b4e27b1Lennart Poettering * but WITHOUT ANY WARRANTY; without even the implied warranty of
a40593a0d0d740efa387e35411e1e456a6c5aba7Lennart Poettering * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20ffc4c4a9226b0e45cc02ad9c0108981626c0bbKay Sievers * GNU General Public License for more details.
3679d1126bae52e02f6cd60fca196f616b9e660dLennart Poettering * You should have received a copy of the GNU General Public License
a4cc3e5ccc0a3033d764a9eb3ae5ee90db560682Lennart Poettering * along with this program. If not, see <http://www.gnu.org/licenses/>.
ab8e074ce25b9947314c69e17afe1bd2527ee26dLennart Poettering /* this node's first child */
b454b11220e87add6d0f011695c7912b009c853dLennart Poettering /* the next child of our parent node's child list */
b454b11220e87add6d0f011695c7912b009c853dLennart Poettering /* this node's last child (shortcut for append) */
b454b11220e87add6d0f011695c7912b009c853dLennart Poettering unsigned short value_len;
b454b11220e87add6d0f011695c7912b009c853dLennart Poettering unsigned char key;
4a449ed73d2c1cfb91a1c773b70231b3457b3046Lennart Poettering /* every key in the rules file becomes a token */
4ff49cb63075aba646b578f2516b37a8dfd5a65bLennart Poettering /* all key strings are copied to a single string buffer */
4ff49cb63075aba646b578f2516b37a8dfd5a65bLennart Poettering /* during rule parsing, strings are indexed to find duplicates */
a53824ea7466bee2c5e6ac9a11b58b79adceb98bLennart Poettering /* during rule parsing, uid/gid lookup results are cached */
3df82d5a8cdc510f518fd5e234ccb3233b748719Lennart Poettering/* KEY=="", KEY!="", KEY+="", KEY="", KEY:="" */
eece8c6fb5f4d354dcef6fd369e876c4f3a3f163Lennart Poettering GL_SPLIT_GLOB, /* multi-value with glob A*|B* */
356ce9915ab1a4a1e6dc26954df34936a69e7c12Lennart Poettering/* tokens of a rule are sorted/handled in this order */
3679d1126bae52e02f6cd60fca196f616b9e660dLennart Poettering/* we try to pack stuff in a way that we take only 12 bytes per token */
3679d1126bae52e02f6cd60fca196f616b9e660dLennart Poettering unsigned char type; /* same in rule and key */
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poetteringstatic const char *operation_str(enum operation_type type)
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering static const char *operation_strs[] = {
e673ad0415d89c322e5b1a121e411f1b1d8075c0Lennart Poetteringstatic const char *string_glob_str(enum string_glob_type type)
e673ad0415d89c322e5b1a121e411f1b1d8075c0Lennart Poettering static const char *string_glob_strs[] = {
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poetteringstatic const char *token_str(enum token_type type)
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering static const char *token_strs[] = {
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering [TK_M_EVENT_TIMEOUT] = "M EVENT_TIMEOUT",
2e4015f3e73173a4346c03a1ed7962f7d3423ed2Lennart Poettering [TK_M_IMPORT_BUILTIN] = "M IMPORT_BUILTIN",
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering [TK_M_IMPORT_CMDLINE] = "M IMPORT_CMDLINE",
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering [TK_M_IMPORT_PARENT] = "M IMPORT_PARENT",
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering [TK_A_STRING_ESCAPE_NONE] = "A STRING_ESCAPE_NONE",
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering [TK_A_STRING_ESCAPE_REPLACE] = "A STRING_ESCAPE_REPLACE",
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering [TK_A_INOTIFY_WATCH] = "A INOTIFY_WATCH",
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poetteringstatic void dump_token(struct udev_rules *rules, struct token *token)
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering enum string_glob_type glob = token->key.glob;
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering const char *value = &rules->buf[token->key.value_off];
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering const char *attr = &rules->buf[token->key.attr_off];
f6113d42d015ad9f3a9e702a09eb8006511a4424Kay Sievers unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token);
d2e83c23f5f0cdd3b6ec05c5c40209708721e704Kay Sievers dbg(rules->udev, "* RULE %s:%u, token: %u, count: %u, label: '%s'\n",
7a43e910ce00eef22fd42925ae4c85cbea1b1320Kay Sievers &rules->buf[token->rule.filename_off], token->rule.filename_line,
a7a3f28be404875eff20443a0fa8088bcc4c18dfLennart Poettering token_str(type), operation_str(op), value, string_glob_str(glob));
9b27910bb0c23e5225fc1177176e4f9bf9bf787bLennart Poettering dbg(rules->udev, "%s %i '%s'\n", token_str(type), token->key.builtin_cmd, value);
7d8197d1f25c1291855bb6cffc705444978c6d8dKay Sievers token_str(type), operation_str(op), attr, value, string_glob_str(glob));
dcfc4b2e5c1af6375488c00bdc6fb8122f86c4d7Lennart Poettering dbg(rules->udev, "%s %s '%s'\n", token_str(type), operation_str(op), value);
1b89884ba31cbe98f159ce2c7d6fac5f6a57698fLennart Poettering dbg(rules->udev, "%s\n", token_str(type));
15abdb9a6f34628b04b887e0b9649fa582d6cd37Lennart Poettering token_str(type), operation_str(op), value, string_glob_str(glob), token->key.mode);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering dbg(rules->udev, "%s %u\n", token_str(type), token->key.watch);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering dbg(rules->udev, "%s %u\n", token_str(type), token->key.devlink_prio);
eb124a97fb72d076014253b1acde69d428f15ecfLennart Poettering dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.uid);
eb124a97fb72d076014253b1acde69d428f15ecfLennart Poettering dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.gid);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering dbg(rules->udev, "%s %s %#o\n", token_str(type), operation_str(op), token->key.mode);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering dbg(rules->udev, "%s '%s'\n", token_str(type), value);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering dbg(rules->udev, "%s %u\n", token_str(type), token->key.event_timeout);
de34a42bcad31f0648ac0f249801310e0dbf83f9Lennart Poettering dbg(rules->udev, "%s '%s' %u\n", token_str(type), value, token->key.rule_goto);
424a19f8a2061c6b058283228734010b2fa24db4Lennart Poettering dbg(rules->udev, "* %s\n", token_str(type));
d05c556b6b2a680ec8b51ecbbc99a9ab14c28eedZbigniew Jędrzejewski-Szmek dbg(rules->udev, "unknown type %u\n", type);
4a30847b9d71e0381948d68279c8f775b9de7850Lennart Poetteringstatic void dump_rules(struct udev_rules *rules)
5e8b28838e493b59628322b69580097ef7dd9384Lennart Poettering unsigned int i;
d87be9b0af81a6e07d4fb3028e45c4409100dc26Lennart Poettering dbg(rules->udev, "dumping %u (%zu bytes) tokens, %u (%zu bytes) strings\n",
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poetteringstatic inline const char *operation_str(enum operation_type type) { return NULL; }
0790b9fed42eefc4e22dbbe2337cba9713b7848cLennart Poetteringstatic inline const char *token_str(enum token_type type) { return NULL; }
5a7e959984788cf89719dec31999409b63bb802bLennart Poetteringstatic inline void dump_token(struct udev_rules *rules, struct token *token) {}
5a7e959984788cf89719dec31999409b63bb802bLennart Poetteringstatic inline void dump_rules(struct udev_rules *rules) {}
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poettering#endif /* ENABLE_DEBUG */
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poetteringstatic int add_new_string(struct udev_rules *rules, const char *str, size_t bytes)
0790b9fed42eefc4e22dbbe2337cba9713b7848cLennart Poettering /* grow buffer if needed */
5aea932fd54db835b77709ddeba30732648aae53Lennart Poettering if (rules->buf_cur + bytes+1 >= rules->buf_max) {
fd4d89b2c0b31da01d134301e30916931ae3c7d9Lennart Poettering /* double the buffer size */
4d9909c93e9c58789c71b34555a1908307c6849eLennart Poettering buf = realloc(rules->buf, rules->buf_max + add);
88a6c5894c9d3f85d63b87b040c130366b4006ceKay Sievers dbg(rules->udev, "extend buffer from %zu to %zu\n", rules->buf_max, rules->buf_max + add);
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering memcpy(&rules->buf[rules->buf_cur], str, bytes);
9946996cda11a18b44d82344676e5a0e96339408Lennart Poetteringstatic int add_string(struct udev_rules *rules, const char *str)
eeb875144e5a80d0521461a139f13fc8014d77d8Lennart Poettering unsigned char key;
eeb875144e5a80d0521461a139f13fc8014d77d8Lennart Poettering unsigned short len;
7b63bde1ed0d4f30c799c9b4737fa926465929f9Lennart Poettering /* walk trie, start from last character of str to find matching tails */
d3a3f22267a7dac426b07a7ed0baa1632f5daf04Kay Sievers unsigned int child_idx;
d3a3f22267a7dac426b07a7ed0baa1632f5daf04Kay Sievers /* match against current node */
d3a3f22267a7dac426b07a7ed0baa1632f5daf04Kay Sievers if (depth == len || (node->value_len >= len && memcmp(&rules->buf[off], str, len) == 0))
d3a3f22267a7dac426b07a7ed0baa1632f5daf04Kay Sievers /* lookup child node */
068665b6fd9839f27bcace7e8f56c0baa6935272Lennart Poettering /* string not found, add it */
231931ffba1bca9d8759bbd6f797e56f8c6971faLennart Poettering off = add_new_string(rules, str, len + 1);
169c4f65131fbc7bcb51e7d5487a715cdcd0e0ebLennart Poettering /* grow trie nodes if needed */
169c4f65131fbc7bcb51e7d5487a715cdcd0e0ebLennart Poettering if (rules->trie_nodes_cur >= rules->trie_nodes_max) {
fb0864e7b9c6d26269ccea6ec5c0fd921c029781Lennart Poettering /* double the buffer size */
d0e5a33374cee92962af33dfc03873e470b014f6Lennart Poettering nodes = realloc(rules->trie_nodes, (rules->trie_nodes_max + add) * sizeof(struct trie_node));
d0e5a33374cee92962af33dfc03873e470b014f6Lennart Poettering dbg(rules->udev, "extend trie nodes from %u to %u\n",
53ed2eeb2e709a6c0d152d7bdf2d9a4b9f997a16Lennart Poettering rules->trie_nodes_max, rules->trie_nodes_max + add);
88f89a9b6d25dfcb89691727c8cdaf01f4090b72Lennart Poettering /* get a new node */
87a8baa35d6d65ac3b58ae8e26e338e67f8ae8edLennart Poettering new_node = &rules->trie_nodes[new_node_idx];
87a8baa35d6d65ac3b58ae8e26e338e67f8ae8edLennart Poettering memset(new_node, 0x00, sizeof(struct trie_node));
65c0cf7108ae3537a357c74b4586a783baba82f9Lennart Poettering /* join the parent's child list */
de6c78f8795743894431a099d26ec562a8acf3dfLennart Poettering last_child = &rules->trie_nodes[parent->last_child_idx];
7d441ddb5ca090b5a97f58ac4b4d97b3e84fa81eLennart Poettering last_child->next_child_idx = new_node_idx;
72b9ed828bd22f3ddd74b6853c183eebf006d6d8Lennart Poetteringstatic int add_token(struct udev_rules *rules, struct token *token)
1d6702e8d3877c0bebf3ac817dc45ff72f5ecfa9Lennart Poettering /* grow buffer if needed */
1d6702e8d3877c0bebf3ac817dc45ff72f5ecfa9Lennart Poettering if (rules->token_cur+1 >= rules->token_max) {
1258097cd3cdbc5dd3d264850119e553a29c5068Lennart Poettering /* double the buffer size */
253ee27a0c7a410d27d490bb79ea97caed6a2b68Lennart Poettering tokens = realloc(rules->tokens, (rules->token_max + add ) * sizeof(struct token));
f28f1daf754a9a07de90e6fc4ada581bf5de677dLennart Poettering dbg(rules->udev, "extend tokens from %u to %u\n", rules->token_max, rules->token_max + add);
88a07670cfa974a605c7c7b520b8a3135fce37f9Lennart Poettering memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token));
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poetteringstatic uid_t add_uid(struct udev_rules *rules, const char *owner)
b44be3ecf6326c27aa2c6c6d1fe34e22e22592a0Lennart Poettering unsigned int i;
b23de6af893c11da4286bc416455cd0926d1532eLennart Poettering /* lookup, if we know it already */
9534ce54858c67363b841cdbdc315140437bfdb4Lennart Poettering if (strcmp(&rules->buf[off], owner) == 0) {
68c7d001f4117f0c3d0a4582e32cbb03ae5fac57Lennart Poettering dbg(rules->udev, "return existing %u for '%s'\n", uid, owner);
7a2a0b907b5cc60f5d9a871997d7d6e7f62bf4d8Lennart Poettering uid = util_lookup_user(rules->udev, owner);
5d0fcd7c8d29340ac9425c309e8ac436a9af699cLennart Poettering /* grow buffer if needed */
5d0fcd7c8d29340ac9425c309e8ac436a9af699cLennart Poettering if (rules->uids_cur+1 >= rules->uids_max) {
a19554ed92a7460b4e709cc40c558cde827ab85bLennart Poettering /* double the buffer size */
3679d1126bae52e02f6cd60fca196f616b9e660dLennart Poettering uids = realloc(rules->uids, (rules->uids_max + add ) * sizeof(struct uid_gid));
3679d1126bae52e02f6cd60fca196f616b9e660dLennart Poettering dbg(rules->udev, "extend uids from %u to %u\n", rules->uids_max, rules->uids_max + add);