diff options
Diffstat (limited to 'src/basic')
75 files changed, 1568 insertions, 308 deletions
diff --git a/src/basic/barrier.c b/src/basic/barrier.c index 9a78a80eb2..26ae123341 100644 --- a/src/basic/barrier.c +++ b/src/basic/barrier.c @@ -197,6 +197,7 @@ static bool barrier_write(Barrier *b, uint64_t buf) { if (barrier_i_aborted(b)) return false; + assert(b->me >= 0); do { len = write(b->me, &buf, sizeof(buf)); } while (len < 0 && IN_SET(errno, EAGAIN, EINTR)); diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index 95f59e400a..50078822a7 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -140,7 +140,8 @@ bool bitmap_isset(Bitmap *b, unsigned n) { bool bitmap_isclear(Bitmap *b) { unsigned i; - assert(b); + if (!b) + return true; for (i = 0; i < b->n_bitmaps; i++) if (b->bitmaps[i] != 0) @@ -150,7 +151,9 @@ bool bitmap_isclear(Bitmap *b) { } void bitmap_clear(Bitmap *b) { - assert(b); + + if (!b) + return; b->bitmaps = mfree(b->bitmaps); b->n_bitmaps = 0; @@ -197,7 +200,10 @@ bool bitmap_equal(Bitmap *a, Bitmap *b) { Bitmap *c; unsigned i; - if (!a ^ !b) + if (a == b) + return true; + + if (!a != !b) return false; if (!a) diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 1aff9d5329..d07d1df5a8 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -49,9 +49,9 @@ #include "selinux-util.h" #include "smack-util.h" #include "sparse-endian.h" -#include "time-util.h" #include "stat-util.h" #include "string-util.h" +#include "time-util.h" #include "util.h" /* WARNING: Be careful with file system ioctls! When we get an fd, we @@ -2051,7 +2051,7 @@ int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) { args.key.nr_items = 256; if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) - return -errno; + return negative_errno(); if (args.key.nr_items <= 0) break; diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c new file mode 100644 index 0000000000..914d7e5229 --- /dev/null +++ b/src/basic/c-rbtree.c @@ -0,0 +1,679 @@ +/*** + This file is part of systemd. See COPYING for details. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +/* + * RB-Tree Implementation + * This implements the insertion/removal of elements in RB-Trees. You're highly + * recommended to have an RB-Tree documentation at hand when reading this. Both + * insertion and removal can be split into a handful of situations that can + * occur. Those situations are enumerated as "Case 1" to "Case n" here, and + * follow closely the cases described in most RB-Tree documentations. This file + * does not explain why it is enough to handle just those cases, nor does it + * provide a proof of correctness. Dig out your algorithm 101 handbook if + * you're interested. + * + * This implementation is *not* straightforward. Usually, a handful of + * rotation, reparent, swap and link helpers can be used to implement the + * rebalance operations. However, those often perform unnecessary writes. + * Therefore, this implementation hard-codes all the operations. You're highly + * recommended to look at the two basic helpers before reading the code: + * c_rbtree_swap_child() + * c_rbtree_set_parent_and_color() + * Those are the only helpers used, hence, you should really know what they do + * before digging into the code. + * + * For a highlevel documentation of the API, see the header file and docbook + * comments. + */ + +#include <assert.h> +#include <stddef.h> +#include "c-rbtree.h" + +enum { + C_RBNODE_RED = 0, + C_RBNODE_BLACK = 1, +}; + +static inline unsigned long c_rbnode_color(CRBNode *n) { + return (unsigned long)n->__parent_and_color & 1UL; +} + +static inline _Bool c_rbnode_is_red(CRBNode *n) { + return c_rbnode_color(n) == C_RBNODE_RED; +} + +static inline _Bool c_rbnode_is_black(CRBNode *n) { + return c_rbnode_color(n) == C_RBNODE_BLACK; +} + +/** + * c_rbnode_leftmost() - return leftmost child + * @n: current node, or NULL + * + * This returns the leftmost child of @n. If @n is NULL, this will return NULL. + * In all other cases, this function returns a valid pointer. That is, if @n + * does not have any left children, this returns @n. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to leftmost child, or NULL. + */ +CRBNode *c_rbnode_leftmost(CRBNode *n) { + if (n) + while (n->left) + n = n->left; + return n; +} + +/** + * c_rbnode_rightmost() - return rightmost child + * @n: current node, or NULL + * + * This returns the rightmost child of @n. If @n is NULL, this will return + * NULL. In all other cases, this function returns a valid pointer. That is, if + * @n does not have any right children, this returns @n. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to rightmost child, or NULL. + */ +CRBNode *c_rbnode_rightmost(CRBNode *n) { + if (n) + while (n->right) + n = n->right; + return n; +} + +/** + * c_rbnode_next() - return next node + * @n: current node, or NULL + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically next node to @n. If @n is NULL, the last node or + * unlinked, this returns NULL. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to next node, or NULL. + */ +CRBNode *c_rbnode_next(CRBNode *n) { + CRBNode *p; + + if (!c_rbnode_is_linked(n)) + return NULL; + if (n->right) + return c_rbnode_leftmost(n->right); + + while ((p = c_rbnode_parent(n)) && n == p->right) + n = p; + + return p; +} + +/** + * c_rbnode_prev() - return previous node + * @n: current node, or NULL + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically previous node to @n. If @n is NULL, the first node or + * unlinked, this returns NULL. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to previous node, or NULL. + */ +CRBNode *c_rbnode_prev(CRBNode *n) { + CRBNode *p; + + if (!c_rbnode_is_linked(n)) + return NULL; + if (n->left) + return c_rbnode_rightmost(n->left); + + while ((p = c_rbnode_parent(n)) && n == p->left) + n = p; + + return p; +} + +/** + * c_rbtree_first() - return first node + * @t: tree to operate on + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically first node in @t. If @t is empty, NULL is returned. + * + * Fixed runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to first node, or NULL. + */ +CRBNode *c_rbtree_first(CRBTree *t) { + assert(t); + return c_rbnode_leftmost(t->root); +} + +/** + * c_rbtree_last() - return last node + * @t: tree to operate on + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically last node in @t. If @t is empty, NULL is returned. + * + * Fixed runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to last node, or NULL. + */ +CRBNode *c_rbtree_last(CRBTree *t) { + assert(t); + return c_rbnode_rightmost(t->root); +} + +/* + * Set the color and parent of a node. This should be treated as a simple + * assignment of the 'color' and 'parent' fields of the node. No other magic is + * applied. But since both fields share its backing memory, this helper + * function is provided. + */ +static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigned long c) { + assert(!((unsigned long)p & 1)); + assert(c < 2); + n->__parent_and_color = (CRBNode*)((unsigned long)p | c); +} + +/* same as c_rbnode_set_parent_and_color(), but keeps the current parent */ +static inline void c_rbnode_set_color(CRBNode *n, unsigned long c) { + c_rbnode_set_parent_and_color(n, c_rbnode_parent(n), c); +} + +/* same as c_rbnode_set_parent_and_color(), but keeps the current color */ +static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) { + c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n)); +} + +/* + * This function partially replaces an existing child pointer to a new one. The + * existing child must be given as @old, the new child as @new. @p must be the + * parent of @old (or NULL if it has no parent). + * This function ensures that the parent of @old now points to @new. However, + * it does *NOT* change the parent pointer of @new. The caller must ensure + * this. + * If @p is NULL, this function ensures that the root-pointer is adjusted + * instead (given as @t). + */ +static inline void c_rbtree_swap_child(CRBTree *t, CRBNode *p, CRBNode *old, CRBNode *new) { + if (p) { + if (p->left == old) + p->left = new; + else + p->right = new; + } else { + t->root = new; + } +} + +static inline CRBNode *c_rbtree_paint_one(CRBTree *t, CRBNode *n) { + CRBNode *p, *g, *gg, *u, *x; + + /* + * Paint a single node according to RB-Tree rules. The node must + * already be linked into the tree and painted red. + * We repaint the node or rotate the tree, if required. In case a + * recursive repaint is required, the next node to be re-painted + * is returned. + * p: parent + * g: grandparent + * gg: grandgrandparent + * u: uncle + * x: temporary + */ + + /* node is red, so we can access the parent directly */ + p = n->__parent_and_color; + + if (!p) { + /* Case 1: + * We reached the root. Mark it black and be done. As all + * leaf-paths share the root, the ratio of black nodes on each + * path stays the same. */ + c_rbnode_set_parent_and_color(n, p, C_RBNODE_BLACK); + n = NULL; + } else if (c_rbnode_is_black(p)) { + /* Case 2: + * The parent is already black. As our node is red, we did not + * change the number of black nodes on any path, nor do we have + * multiple consecutive red nodes. */ + n = NULL; + } else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */ + g = p->__parent_and_color; + gg = c_rbnode_parent(g); + u = g->right; + + if (u && c_rbnode_is_red(u)) { + /* Case 3: + * Parent and uncle are both red. We know the + * grandparent must be black then. Repaint parent and + * uncle black, the grandparent red and recurse into + * the grandparent. */ + c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED); + n = g; + } else { + /* parent is red, uncle is black */ + + if (n == p->right) { + /* Case 4: + * We're the right child. Rotate on parent to + * become left child, so we can handle it the + * same as case 5. */ + x = n->left; + p->right = n->left; + n->left = p; + if (x) + c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED); + p = n; + } + + /* 'n' is invalid from here on! */ + n = NULL; + + /* Case 5: + * We're the red left child or a red parent, black + * grandparent and uncle. Rotate on grandparent and + * switch color with parent. Number of black nodes on + * each path stays the same, but we got rid of the + * double red path. As the grandparent is still black, + * we're done. */ + x = p->right; + g->left = x; + p->right = g; + if (x) + c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED); + c_rbtree_swap_child(t, gg, g, p); + } + } else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */ + g = p->__parent_and_color; + gg = c_rbnode_parent(g); + u = g->left; + + if (u && c_rbnode_is_red(u)) { + c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED); + n = g; + } else { + if (n == p->left) { + x = n->right; + p->left = n->right; + n->right = p; + if (x) + c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED); + p = n; + } + + n = NULL; + + x = p->left; + g->right = x; + p->left = g; + if (x) + c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED); + c_rbtree_swap_child(t, gg, g, p); + } + } + + return n; +} + +static inline void c_rbtree_paint(CRBTree *t, CRBNode *n) { + assert(t); + assert(n); + + while (n) + n = c_rbtree_paint_one(t, n); +} + +/** + * c_rbtree_add() - add node to tree + * @t: tree to operate one + * @p: parent node to link under, or NULL + * @l: left/right slot of @p (or root) to link at + * @n: node to add + * + * This links @n into the tree given as @t. The caller must provide the exact + * spot where to link the node. That is, the caller must traverse the tree + * based on their search order. Once they hit a leaf where to insert the node, + * call this function to link it and rebalance the tree. + * + * A typical insertion would look like this (@t is your tree, @n is your node): + * + * CRBNode **i, *p; + * + * i = &t->root; + * p = NULL; + * while (*i) { + * p = *i; + * if (compare(n, *i) < 0) + * i = &(*i)->left; + * else + * i = &(*i)->right; + * } + * + * c_rbtree_add(t, p, i, n); + * + * Once the node is linked into the tree, a simple lookup on the same tree can + * be coded like this: + * + * CRBNode *i; + * + * i = t->root; + * while (i) { + * int v = compare(n, i); + * if (v < 0) + * i = (*i)->left; + * else if (v > 0) + * i = (*i)->right; + * else + * break; + * } + * + * When you add nodes to a tree, the memory contents of the node do not matter. + * That is, there is no need to initialize the node via c_rbnode_init(). + * However, if you relink nodes multiple times during their lifetime, it is + * usually very convenient to use c_rbnode_init() and c_rbtree_remove_init(). + * In those cases, you should validate that a node is unlinked before you call + * c_rbtree_add(). + */ +void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) { + assert(t); + assert(l); + assert(n); + assert(!p || l == &p->left || l == &p->right); + assert(p || l == &t->root); + + c_rbnode_set_parent_and_color(n, p, C_RBNODE_RED); + n->left = n->right = NULL; + *l = n; + + c_rbtree_paint(t, n); +} + +static inline CRBNode *c_rbtree_rebalance_one(CRBTree *t, CRBNode *p, CRBNode *n) { + CRBNode *s, *x, *y, *g; + + /* + * Rebalance tree after a node was removed. This happens only if you + * remove a black node and one path is now left with an unbalanced + * number or black nodes. + * This function assumes all paths through p and n have one black node + * less than all other paths. If recursive fixup is required, the + * current node is returned. + */ + + if (n == p->left) { + s = p->right; + if (c_rbnode_is_red(s)) { + /* Case 3: + * We have a red node as sibling. Rotate it onto our + * side so we can later on turn it black. This way, we + * gain the additional black node in our path. */ + g = c_rbnode_parent(p); + x = s->left; + p->right = x; + s->left = p; + c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); + c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED); + c_rbtree_swap_child(t, g, p, s); + s = x; + } + + x = s->right; + if (!x || c_rbnode_is_black(x)) { + y = s->left; + if (!y || c_rbnode_is_black(y)) { + /* Case 4: + * Our sibling is black and has only black + * children. Flip it red and turn parent black. + * This way we gained a black node in our path, + * or we fix it recursively one layer up, which + * will rotate the red sibling as parent. */ + c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED); + if (c_rbnode_is_black(p)) + return p; + + c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK); + return NULL; + } + + /* Case 5: + * Left child of our sibling is red, right one is black. + * Rotate on parent so the right child of our sibling is + * now red, and we can fall through to case 6. */ + x = y->right; + s->left = y->right; + y->right = s; + p->right = y; + if (x) + c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); + x = s; + s = y; + } + + /* Case 6: + * The right child of our sibling is red. Rotate left and flip + * colors, which gains us an additional black node in our path, + * that was previously on our sibling. */ + g = c_rbnode_parent(p); + y = s->left; + p->right = y; + s->left = p; + c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); + if (y) + c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y)); + c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); + c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK); + c_rbtree_swap_child(t, g, p, s); + } else /* if (!n || n == p->right) */ { /* same as above, but mirrored */ + s = p->left; + if (c_rbnode_is_red(s)) { + g = c_rbnode_parent(p); + x = s->right; + p->left = x; + s->right = p; + c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(s, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED); + c_rbtree_swap_child(t, g, p, s); + s = x; + } + + x = s->left; + if (!x || c_rbnode_is_black(x)) { + y = s->right; + if (!y || c_rbnode_is_black(y)) { + c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED); + if (c_rbnode_is_black(p)) + return p; + + c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK); + return NULL; + } + + x = y->left; + s->right = y->left; + y->left = s; + p->left = y; + if (x) + c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); + x = s; + s = y; + } + + g = c_rbnode_parent(p); + y = s->right; + p->left = y; + s->right = p; + c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); + if (y) + c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y)); + c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); + c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK); + c_rbtree_swap_child(t, g, p, s); + } + + return NULL; +} + +static inline void c_rbtree_rebalance(CRBTree *t, CRBNode *p) { + CRBNode *n = NULL; + + assert(t); + assert(p); + + do { + n = c_rbtree_rebalance_one(t, p, n); + p = n ? c_rbnode_parent(n) : NULL; + } while (p); +} + +/** + * c_rbtree_remove() - remove node from tree + * @t: tree to operate one + * @n: node to remove + * + * This removes the given node from its tree. Once unlinked, the tree is + * rebalanced. + * The caller *must* ensure that the given tree is actually the tree it is + * linked on. Otherwise, behavior is undefined. + * + * This does *NOT* reset @n to being unlinked (for performance reason, this + * function *never* modifies @n at all). If you need this, use + * c_rbtree_remove_init(). + */ +void c_rbtree_remove(CRBTree *t, CRBNode *n) { + CRBNode *p, *s, *gc, *x, *next = NULL; + unsigned long c; + + assert(t); + assert(n); + assert(c_rbnode_is_linked(n)); + + /* + * There are three distinct cases during node removal of a tree: + * * The node has no children, in which case it can simply be removed. + * * The node has exactly one child, in which case the child displaces + * its parent. + * * The node has two children, in which case there is guaranteed to + * be a successor to the node (successor being the node ordered + * directly after it). This successor cannot have two children by + * itself (two interior nodes can never be successive). Therefore, + * we can simply swap the node with its successor (including color) + * and have reduced this case to either of the first two. + * + * Whenever the node we removed was black, we have to rebalance the + * tree. Note that this affects the actual node we _remove_, not @n (in + * case we swap it). + * + * p: parent + * s: successor + * gc: grand-...-child + * x: temporary + * next: next node to rebalance on + */ + + if (!n->left) { + /* + * Case 1: + * The node has no left child. If it neither has a right child, + * it is a leaf-node and we can simply unlink it. If it also + * was black, we have to rebalance, as always if we remove a + * black node. + * But if the node has a right child, the child *must* be red + * (otherwise, the right path has more black nodes as the + * non-existing left path), and the node to be removed must + * hence be black. We simply replace the node with its child, + * turning the red child black, and thus no rebalancing is + * required. + */ + p = c_rbnode_parent(n); + c = c_rbnode_color(n); + c_rbtree_swap_child(t, p, n, n->right); + if (n->right) + c_rbnode_set_parent_and_color(n->right, p, c); + else + next = (c == C_RBNODE_BLACK) ? p : NULL; + } else if (!n->right) { + /* + * Case 1.1: + * The node has exactly one child, and it is on the left. Treat + * it as mirrored case of Case 1 (i.e., replace the node by its + * child). + */ + p = c_rbnode_parent(n); + c = c_rbnode_color(n); + c_rbtree_swap_child(t, p, n, n->left); + c_rbnode_set_parent_and_color(n->left, p, c); + } else { + /* + * Case 2: + * We are dealing with a full interior node with a child not on + * both sides. Find its successor and swap it. Then remove the + * node similar to Case 1. For performance reasons we don't + * perform the full swap, but skip links that are about to be + * removed, anyway. + */ + s = n->right; + if (!s->left) { + /* right child is next, no need to touch grandchild */ + p = s; + gc = s->right; + } else { + /* find successor and swap partially */ + s = c_rbnode_leftmost(s); + p = c_rbnode_parent(s); + + gc = s->right; + p->left = s->right; + s->right = n->right; + c_rbnode_set_parent(n->right, s); + } + + /* node is partially swapped, now remove as in Case 1 */ + s->left = n->left; + c_rbnode_set_parent(n->left, s); + + x = c_rbnode_parent(n); + c = c_rbnode_color(n); + c_rbtree_swap_child(t, x, n, s); + if (gc) + c_rbnode_set_parent_and_color(gc, p, C_RBNODE_BLACK); + else + next = c_rbnode_is_black(s) ? p : NULL; + c_rbnode_set_parent_and_color(s, x, c); + } + + if (next) + c_rbtree_rebalance(t, next); +} diff --git a/src/basic/c-rbtree.h b/src/basic/c-rbtree.h new file mode 100644 index 0000000000..20c5515ca1 --- /dev/null +++ b/src/basic/c-rbtree.h @@ -0,0 +1,297 @@ +#pragma once + +/*** + This file is part of systemd. See COPYING for details. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +/* + * Standalone Red-Black-Tree Implementation in Standard ISO-C11 + * + * This header provides an RB-Tree API, that is fully implemented in ISO-C11 + * and has no external dependencies. Furthermore, tree traversal, memory + * allocations, and key comparisons a fully in control of the API user. The + * implementation only provides the RB-Tree specific rebalancing and coloring. + * + * A tree is represented by the "CRBTree" structure. It contains a *singly* + * field, which is a pointer to the root node. If NULL, the tree is empty. If + * non-NULL, there is at least a single element in the tree. + * + * Each node of the tree is represented by the "CRBNode" structure. It has + * three fields. The @left and @right members can be accessed by the API user + * directly to traverse the tree. The third member is an implementation detail + * and encodes the parent pointer and color of the node. + * API users are required to embed the CRBNode object into their own objects + * and then use offsetof() (i.e., container_of() and friends) to turn CRBNode + * pointers into pointers to their own structure. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CRBNode CRBNode; +typedef struct CRBTree CRBTree; + +/** + * struct CRBNode - Node of a Red-Black Tree + * @__parent_and_color: internal state + * @left: left child, or NULL + * @right: right child, or NULL + * + * Each node in an RB-Tree must embed an CRBNode object. This object contains + * pointers to its left and right child, which can be freely accessed by the + * API user at any time. They are NULL, if the node does not have a left/right + * child. + * + * The @__parent_and_color field must never be accessed directly. It encodes + * the pointer to the parent node, and the color of the node. Use the accessor + * functions instead. + * + * There is no reason to initialize a CRBNode object before linking it. + * However, if you need a boolean state that tells you whether the node is + * linked or not, you should initialize the node via c_rbnode_init() or + * C_RBNODE_INIT. + */ +struct CRBNode { + CRBNode *__parent_and_color; + CRBNode *left; + CRBNode *right; +}; + +#define C_RBNODE_INIT(_var) { .__parent_and_color = &(_var) } + +CRBNode *c_rbnode_leftmost(CRBNode *n); +CRBNode *c_rbnode_rightmost(CRBNode *n); +CRBNode *c_rbnode_next(CRBNode *n); +CRBNode *c_rbnode_prev(CRBNode *n); + +/** + * struct CRBTree - Red-Black Tree + * @root: pointer to the root node, or NULL + * + * Each Red-Black Tree is rooted in an CRBTree object. This object contains a + * pointer to the root node of the tree. The API user is free to access the + * @root member at any time, and use it to traverse the tree. + * + * To initialize an RB-Tree, set it to NULL / all zero. + */ +struct CRBTree { + CRBNode *root; +}; + +CRBNode *c_rbtree_first(CRBTree *t); +CRBNode *c_rbtree_last(CRBTree *t); + +void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n); +void c_rbtree_remove(CRBTree *t, CRBNode *n); + +/** + * c_rbnode_init() - mark a node as unlinked + * @n: node to operate on + * + * This marks the node @n as unlinked. The node will be set to a valid state + * that can never happen if the node is linked in a tree. Furthermore, this + * state is fully known to the implementation, and as such handled gracefully + * in all cases. + * + * You are *NOT* required to call this on your node. c_rbtree_add() can handle + * uninitialized nodes just fine. However, calling this allows to use + * c_rbnode_is_linked() to check for the state of a node. Furthermore, + * iterators and accessors can be called on initialized (yet unlinked) nodes. + * + * Use the C_RBNODE_INIT macro if you want to initialize static variables. + */ +static inline void c_rbnode_init(CRBNode *n) { + *n = (CRBNode)C_RBNODE_INIT(*n); +} + +/** + * c_rbnode_is_linked() - check whether a node is linked + * @n: node to check, or NULL + * + * This checks whether the passed node is linked. If you pass NULL, or if the + * node is not linked into a tree, this will return false. Otherwise, this + * returns true. + * + * Note that you must have either linked the node or initialized it, before + * calling this function. Never call this function on uninitialized nodes. + * Furthermore, removing a node via c_rbtree_remove() does *NOT* mark the node + * as unlinked. You have to call c_rbnode_init() yourself after removal, or use + * the c_rbtree_remove_init() helper. + * + * Return: true if the node is linked, false if not. + */ +static inline _Bool c_rbnode_is_linked(CRBNode *n) { + return n && n->__parent_and_color != n; +} + +/** + * c_rbnode_parent() - return parent pointer + * @n node to access + * + * This returns a pointer to the parent of the given node @n. If @n does not + * have a parent, NULL is returned. If @n is not linked, @n itself is returned. + * + * You should not call this on unlinked or uninitialized nodes! If you do, you + * better know how its semantics. + * + * Return: Pointer to parent. + */ +static inline CRBNode *c_rbnode_parent(CRBNode *n) { + return (CRBNode*)((unsigned long)n->__parent_and_color & ~1UL); +} + +/** + * c_rbtree_remove_init() - safely remove node from tree and reinitialize it + * @t: tree to operate on + * @n: node to remove, or NULL + * + * This is almost the same as c_rbtree_remove(), but extends it slightly, to be + * more convenient to use in many cases: + * - if @n is unlinked or NULL, this is a no-op + * - @n is reinitialized after being removed + */ +static inline void c_rbtree_remove_init(CRBTree *t, CRBNode *n) { + if (c_rbnode_is_linked(n)) { + c_rbtree_remove(t, n); + c_rbnode_init(n); + } +} + +/** + * CRBCompareFunc - compare a node to a key + * @t: tree where the node is linked to + * @k: key to compare + * @n: node to compare + * + * If you use the tree-traversal helpers (which are optional), you need to + * provide this callback so they can compare nodes in a tree to the key you + * look for. + * + * The tree @t is provided as optional context to this callback. The key you + * look for is provided as @k, the current node that should be compared to is + * provided as @n. This function should work like strcmp(), that is, return -1 + * if @key orders before @n, 0 if both compare equal, and 1 if it orders after + * @n. + */ +typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n); + +/** + * c_rbtree_find_node() - find node + * @t: tree to search through + * @f: comparison function + * @k: key to search for + * + * This searches through @t for a node that compares equal to @k. The function + * @f must be provided by the caller, which is used to compare nodes to @k. See + * the documentation of CRBCompareFunc for details. + * + * If there are multiple entries that compare equal to @k, this will return a + * pseudo-randomly picked node. If you need stable lookup functions for trees + * where duplicate entries are allowed, you better code your own lookup. + * + * Return: Pointer to matching node, or NULL. + */ +static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const void *k) { + CRBNode *i; + + assert(t); + assert(f); + + i = t->root; + while (i) { + int v = f(t, (void *)k, i); + if (v < 0) + i = i->left; + else if (v > 0) + i = i->right; + else + return i; + } + + return NULL; +} + +/** + * c_rbtree_find_entry() - find entry + * @_t: tree to search through + * @_f: comparison function + * @_k: key to search for + * @_t: type of the structure that embeds the nodes + * @_o: name of the node-member in type @_t + * + * This is very similar to c_rbtree_find_node(), but instead of returning a + * pointer to the CRBNode, it returns a pointer to the surrounding object. This + * object must embed the CRBNode object. The type of the surrounding object + * must be given as @_t, and the name of the embedded CRBNode member as @_o. + * + * See c_rbtree_find_node() for more details. + * + * Return: Pointer to found entry, NULL if not found. + */ +#define c_rbtree_find_entry(_m, _f, _k, _t, _o) \ + ((_t *)(((char *)c_rbtree_find_node((_m), (_f), (_k)) ?: \ + (char *)NULL + offsetof(_t, _o)) - offsetof(_t, _o))) + +/** + * c_rbtree_find_slot() - find slot to insert new node + * @t: tree to search through + * @f: comparison function + * @k: key to search for + * @p: output storage for parent pointer + * + * This searches through @t just like c_rbtree_find_node() does. However, + * instead of returning a pointer to a node that compares equal to @k, this + * searches for a slot to insert a node with key @k. A pointer to the slot is + * returned, and a pointer to the parent of the slot is stored in @p. Both + * can be passed directly to c_rbtree_add(), together with your node to insert. + * + * If there already is a node in the tree, that compares equal to @k, this will + * return NULL and store the conflicting node in @p. In all other cases, + * this will return a pointer (non-NULL) to the empty slot to insert the node + * at. @p will point to the parent node of that slot. + * + * If you want trees that allow duplicate nodes, you better code your own + * insertion function. + * + * Return: Pointer to slot to insert node, or NULL on conflicts. + */ +static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const void *k, CRBNode **p) { + CRBNode **i; + + assert(t); + assert(f); + assert(p); + + i = &t->root; + *p = NULL; + while (*i) { + int v = f(t, (void *)k, *i); + *p = *i; + if (v < 0) + i = &(*i)->left; + else if (v > 0) + i = &(*i)->right; + else + return NULL; + } + + return i; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 2c670a1ac6..8f83d9c142 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -30,8 +30,8 @@ #include "alloc-util.h" #include "calendarspec.h" #include "fileio.h" -#include "parse-util.h" #include "macro.h" +#include "parse-util.h" #include "string-util.h" #define BITS_WEEKDAYS 127 diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c index aac812dc52..0e5cc452b9 100644 --- a/src/basic/cap-list.c +++ b/src/basic/cap-list.c @@ -23,9 +23,9 @@ #include <string.h> #include "cap-list.h" +#include "macro.h" #include "missing.h" #include "parse-util.h" -#include "macro.h" #include "util.h" static const struct capability_name* lookup_capability(register const char *str, register unsigned int len); diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index fef722b6f2..49c2d61afe 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -96,7 +96,62 @@ unsigned long cap_last_cap(void) { return p; } -int capability_bounding_set_drop(uint64_t drop, bool right_now) { +int capability_update_inherited_set(cap_t caps, uint64_t set) { + unsigned long i; + + /* Add capabilities in the set to the inherited caps. Do not apply + * them yet. */ + + for (i = 0; i < cap_last_cap(); i++) { + + if (set & (UINT64_C(1) << i)) { + cap_value_t v; + + v = (cap_value_t) i; + + /* Make the capability inheritable. */ + if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, CAP_SET) < 0) + return -errno; + } + } + + return 0; +} + +int capability_ambient_set_apply(uint64_t set, bool also_inherit) { + unsigned long i; + _cleanup_cap_free_ cap_t caps = NULL; + + /* Add the capabilities to the ambient set. */ + + if (also_inherit) { + int r; + caps = cap_get_proc(); + if (!caps) + return -errno; + + r = capability_update_inherited_set(caps, set); + if (r < 0) + return -errno; + + if (cap_set_proc(caps) < 0) + return -errno; + } + + for (i = 0; i < cap_last_cap(); i++) { + + if (set & (UINT64_C(1) << i)) { + + /* Add the capability to the ambient set. */ + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) + return -errno; + } + } + + return 0; +} + +int capability_bounding_set_drop(uint64_t keep, bool right_now) { _cleanup_cap_free_ cap_t after_cap = NULL; cap_flag_value_t fv; unsigned long i; @@ -137,7 +192,7 @@ int capability_bounding_set_drop(uint64_t drop, bool right_now) { for (i = 0; i <= cap_last_cap(); i++) { - if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { + if (!(keep & (UINT64_C(1) << i))) { cap_value_t v; /* Drop it from the bounding set */ @@ -176,7 +231,7 @@ finish: return r; } -static int drop_from_file(const char *fn, uint64_t drop) { +static int drop_from_file(const char *fn, uint64_t keep) { int r, k; uint32_t hi, lo; uint64_t current, after; @@ -196,7 +251,7 @@ static int drop_from_file(const char *fn, uint64_t drop) { return -EIO; current = (uint64_t) lo | ((uint64_t) hi << 32ULL); - after = current & ~drop; + after = current & keep; if (current == after) return 0; @@ -213,14 +268,14 @@ static int drop_from_file(const char *fn, uint64_t drop) { return r; } -int capability_bounding_set_drop_usermode(uint64_t drop) { +int capability_bounding_set_drop_usermode(uint64_t keep) { int r; - r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop); + r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep); if (r < 0) return r; - r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop); + r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep); if (r < 0) return r; @@ -257,7 +312,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) { return log_error_errno(errno, "Failed to disable keep capabilities flag: %m"); /* Drop all caps from the bounding set, except the ones we want */ - r = capability_bounding_set_drop(~keep_capabilities, true); + r = capability_bounding_set_drop(keep_capabilities, true); if (r < 0) return log_error_errno(r, "Failed to drop capabilities: %m"); diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h index 6bbf7318fd..be41475441 100644 --- a/src/basic/capability-util.h +++ b/src/basic/capability-util.h @@ -29,10 +29,15 @@ #include "macro.h" #include "util.h" +#define CAP_ALL (uint64_t) -1 + unsigned long cap_last_cap(void); int have_effective_cap(int value); -int capability_bounding_set_drop(uint64_t drop, bool right_now); -int capability_bounding_set_drop_usermode(uint64_t drop); +int capability_bounding_set_drop(uint64_t keep, bool right_now); +int capability_bounding_set_drop_usermode(uint64_t keep); + +int capability_ambient_set_apply(uint64_t set, bool also_inherit); +int capability_update_inherited_set(cap_t caps, uint64_t ambient_set); int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities); @@ -46,3 +51,9 @@ static inline void cap_free_charpp(char **p) { cap_free(*p); } #define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp) + +static inline bool cap_test_all(uint64_t caps) { + uint64_t m; + m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1; + return (caps & m) == m; +} diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 7c580caa43..f873fb89d3 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -34,14 +34,17 @@ #include "alloc-util.h" #include "cgroup-util.h" +#include "def.h" #include "dirent-util.h" #include "extract-word.h" #include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "fs-util.h" +#include "log.h" #include "login-util.h" #include "macro.h" +#include "missing.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" @@ -49,10 +52,8 @@ #include "process-util.h" #include "set.h" #include "special.h" -#include "def.h" -#include "log.h" -#include "missing.h" #include "stat-util.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "unit-name.h" @@ -92,7 +93,7 @@ int cg_read_pid(FILE *f, pid_t *_pid) { if (feof(f)) return 0; - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; } if (ul <= 0) @@ -647,7 +648,7 @@ int cg_trim(const char *controller, const char *path, bool delete_root) { if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) { if (errno == ENOENT) r = 0; - else if (errno != 0) + else if (errno > 0) r = -errno; else r = -EIO; @@ -716,7 +717,7 @@ int cg_attach(const char *controller, const char *path, pid_t pid) { if (pid == 0) pid = getpid(); - snprintf(c, sizeof(c), PID_FMT"\n", pid); + xsprintf(c, PID_FMT "\n", pid); return write_string_file(fs, c, 0); } @@ -2090,7 +2091,7 @@ int cg_kernel_controllers(Set *controllers) { if (feof(f)) break; - if (ferror(f) && errno != 0) + if (ferror(f) && errno > 0) return -errno; return -EBADMSG; @@ -2135,7 +2136,7 @@ int cg_unified(void) { else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) unified_cache = false; else - return -ENOEXEC; + return -ENOMEDIUM; return unified_cache; } diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index b506995794..661785784a 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -28,9 +28,9 @@ #include <sys/types.h> #include "def.h" -#include "set.h" #include "hashmap.h" #include "macro.h" +#include "set.h" /* An enum of well known cgroup controllers */ typedef enum CGroupController { diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index 00f549c023..05788a360e 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -33,6 +33,7 @@ #include "fd-util.h" #include "macro.h" #include "string-util.h" +#include "util.h" int clock_get_hwclock(struct tm *tm) { _cleanup_close_ int fd = -1; @@ -121,7 +122,8 @@ int clock_set_timezone(int *min) { * have read from the RTC. */ if (settimeofday(tv_null, &tz) < 0) - return -errno; + return negative_errno(); + if (min) *min = minutesdelta; return 0; diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index 75dad228e3..5854caeb51 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -41,6 +41,7 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { _cleanup_closedir_ DIR *dir = NULL; const char *dirpath; + struct dirent *de; int r; assert(path); @@ -55,18 +56,9 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char return -errno; } - for (;;) { - struct dirent *de; + FOREACH_DIRENT(de, dir, return -errno) { char *p; - errno = 0; - de = readdir(dir); - if (!de && errno != 0) - return -errno; - - if (!de) - break; - if (!dirent_is_file_with_suffix(de, suffix)) continue; @@ -116,17 +108,15 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const STRV_FOREACH(p, dirs) { r = files_add(fh, root, *p, suffix); - if (r == -ENOMEM) { + if (r == -ENOMEM) return r; - } else if (r < 0) - log_debug_errno(r, "Failed to search for files in %s: %m", - *p); + if (r < 0) + log_debug_errno(r, "Failed to search for files in %s, ignoring: %m", *p); } files = hashmap_get_strv(fh); - if (files == NULL) { + if (!files) return -ENOMEM; - } qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp); *strv = files; diff --git a/src/basic/copy.c b/src/basic/copy.c index c335959b74..024712d290 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -42,9 +42,9 @@ #include "fs-util.h" #include "io-util.h" #include "macro.h" -#include "time-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "umask-util.h" #include "xattr-util.h" diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c index 51c0693954..85b7519953 100644 --- a/src/basic/cpu-set-util.c +++ b/src/basic/cpu-set-util.c @@ -27,9 +27,9 @@ #include "alloc-util.h" #include "cpu-set-util.h" #include "extract-word.h" -#include "parse-util.h" #include "log.h" #include "macro.h" +#include "parse-util.h" #include "string-util.h" cpu_set_t* cpu_set_malloc(unsigned *ncpus) { diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h index 58273bb988..1ad5e4715a 100644 --- a/src/basic/dirent-util.h +++ b/src/basic/dirent-util.h @@ -25,8 +25,8 @@ #include <errno.h> #include <stdbool.h> -#include "path-util.h" #include "macro.h" +#include "path-util.h" int dirent_ensure_type(DIR *d, struct dirent *de); diff --git a/src/basic/env-util.c b/src/basic/env-util.c index fe8c825f36..dd56545f12 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -28,9 +28,9 @@ #include "alloc-util.h" #include "env-util.h" -#include "parse-util.h" #include "extract-word.h" #include "macro.h" +#include "parse-util.h" #include "string-util.h" #include "strv.h" #include "utf8.h" diff --git a/src/basic/errno-list.c b/src/basic/errno-list.c index 0a66902ac9..b4d080103b 100644 --- a/src/basic/errno-list.c +++ b/src/basic/errno-list.c @@ -25,7 +25,7 @@ #include "macro.h" static const struct errno_name* lookup_errno(register const char *str, - register unsigned int len); + register unsigned int len); #include "errno-from-name.h" #include "errno-to-name.h" @@ -48,8 +48,9 @@ int errno_from_name(const char *name) { sc = lookup_errno(name, strlen(name)); if (!sc) - return 0; + return -EINVAL; + assert(sc->id > 0); return sc->id; } diff --git a/src/basic/escape.c b/src/basic/escape.c index ab282efa3c..5661f36813 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -119,16 +119,18 @@ char *cescape(const char *s) { return cescape_length(s, strlen(s)); } -int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { +int cunescape_one(const char *p, size_t length, uint32_t *ret, bool *eight_bit) { int r = 1; assert(p); assert(*p); assert(ret); - /* Unescapes C style. Returns the unescaped character in ret, - * unless we encountered a \u sequence in which case the full - * unicode character is returned in ret_unicode, instead. */ + /* Unescapes C style. Returns the unescaped character in ret. + * Sets *eight_bit to true if the escaped sequence either fits in + * one byte in UTF-8 or is a non-unicode literal byte and should + * instead be copied directly. + */ if (length != (size_t) -1 && length < 1) return -EINVAL; @@ -190,7 +192,8 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (a == 0 && b == 0) return -EINVAL; - *ret = (char) ((a << 4U) | b); + *ret = (a << 4U) | b; + *eight_bit = true; r = 3; break; } @@ -217,16 +220,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (c == 0) return -EINVAL; - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - + *ret = c; r = 5; break; } @@ -258,16 +252,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (!unichar_is_valid(c)) return -EINVAL; - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - + *ret = c; r = 9; break; } @@ -309,6 +294,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode return -EINVAL; *ret = m; + *eight_bit = true; r = 3; break; } @@ -342,7 +328,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi for (f = s, t = r + pl; f < s + length; f++) { size_t remaining; uint32_t u; - char c; + bool eight_bit = false; int k; remaining = s + length - f; @@ -365,7 +351,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return -EINVAL; } - k = cunescape_one(f + 1, remaining - 1, &c, &u); + k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit); if (k < 0) { if (flags & UNESCAPE_RELAX) { /* Invalid escape code, let's take it literal then */ @@ -377,14 +363,13 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return k; } - if (c != 0) - /* Non-Unicode? Let's encode this directly */ - *(t++) = c; + f += k; + if (eight_bit) + /* One byte? Set directly as specified */ + *(t++) = u; else - /* Unicode? Then let's encode this in UTF-8 */ + /* Otherwise encode as multi-byte UTF-8 */ t += utf8_encode_unichar(t, u); - - f += k; } *t = 0; diff --git a/src/basic/escape.h b/src/basic/escape.h index c710f01743..d943aa71f5 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -45,7 +45,7 @@ size_t cescape_char(char c, char *buf); int cunescape(const char *s, UnescapeFlags flags, char **ret); int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); -int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode); +int cunescape_one(const char *p, size_t length, uint32_t *ret, bool *eight_bit); char *xescape(const char *s, const char *bad); diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h index 850f58fd98..664222c1d6 100644 --- a/src/basic/exit-status.h +++ b/src/basic/exit-status.h @@ -23,9 +23,9 @@ #include <stdbool.h> -#include "set.h" #include "hashmap.h" #include "macro.h" +#include "set.h" typedef enum ExitStatus { /* EXIT_SUCCESS defined by libc */ diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 7cc2a1de13..090d2a7884 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -108,8 +108,9 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra if (flags & EXTRACT_CUNESCAPE) { uint32_t u; + bool eight_bit = false; - r = cunescape_one(*p, (size_t) -1, &c, &u); + r = cunescape_one(*p, (size_t) -1, &u, &eight_bit); if (r < 0) { if (flags & EXTRACT_CUNESCAPE_RELAX) { s[sz++] = '\\'; @@ -119,10 +120,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra } else { (*p) += r - 1; - if (c != 0) - s[sz++] = c; /* normal explicit char */ + if (eight_bit) + s[sz++] = u; else - sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */ + sz += utf8_encode_unichar(s + sz, u); } } else s[sz++] = c; diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 678ac3b195..9759cac23c 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -27,11 +27,11 @@ #include <unistd.h> #include "fd-util.h" -#include "parse-util.h" -#include "socket-util.h" #include "macro.h" #include "missing.h" +#include "parse-util.h" #include "path-util.h" +#include "socket-util.h" #include "util.h" int close_nointr(int fd) { diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 5ce1592eeb..973413ff42 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -73,3 +73,6 @@ int same_fd(int a, int b); void cmsg_close_all(struct msghdr *mh); bool fdname_is_valid(const char *s); + +#define ERRNO_IS_DISCONNECT(r) \ + IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE) diff --git a/src/basic/fdset.c b/src/basic/fdset.c index 654ec5a639..de9b723ab8 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -29,11 +29,11 @@ #include "fd-util.h" #include "fdset.h" +#include "log.h" #include "macro.h" #include "parse-util.h" -#include "set.h" -#include "log.h" #include "path-util.h" +#include "set.h" #define MAKE_SET(s) ((Set*) s) #define MAKE_FDSET(s) ((FDSet*) s) diff --git a/src/basic/fdset.h b/src/basic/fdset.h index 58a5b45f28..615ba05661 100644 --- a/src/basic/fdset.h +++ b/src/basic/fdset.h @@ -23,9 +23,9 @@ #include <stdbool.h> -#include "set.h" #include "hashmap.h" #include "macro.h" +#include "set.h" typedef struct FDSet FDSet; diff --git a/src/basic/fileio-label.c b/src/basic/fileio-label.c index 52a1515cd7..1cee87c9cd 100644 --- a/src/basic/fileio-label.c +++ b/src/basic/fileio-label.c @@ -23,8 +23,8 @@ #include <sys/stat.h> #include "fileio-label.h" -#include "selinux-util.h" #include "fileio.h" +#include "selinux-util.h" int write_string_file_atomic_label(const char *fn, const char *line) { int r; diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 684ce3d58f..5ed5460904 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -37,15 +37,15 @@ #include "fileio.h" #include "fs-util.h" #include "hexdecoct.h" +#include "log.h" +#include "macro.h" #include "parse-util.h" #include "path-util.h" #include "random-util.h" -#include "log.h" -#include "macro.h" -#include "time-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "umask-util.h" #include "utf8.h" @@ -165,7 +165,7 @@ int read_one_line_file(const char *fn, char **line) { if (!fgets(t, sizeof(t), f)) { if (ferror(f)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; t[0] = 0; } @@ -1064,7 +1064,7 @@ int fflush_and_check(FILE *f) { fflush(f); if (ferror(f)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 0; } diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index cd7abee989..d31bd6e273 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -34,15 +34,15 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" -#include "mkdir.h" -#include "parse-util.h" -#include "path-util.h" #include "log.h" #include "macro.h" #include "missing.h" -#include "time-util.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "user-util.h" #include "util.h" @@ -481,7 +481,7 @@ int get_files_in_directory(const char *path, char ***list) { errno = 0; de = readdir(d); - if (!de && errno != 0) + if (!de && errno > 0) return -errno; if (!de) break; diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c index a0be0efd40..811ab6ec36 100644 --- a/src/basic/glob-util.c +++ b/src/basic/glob-util.c @@ -40,7 +40,7 @@ int glob_exists(const char *path) { if (k == GLOB_NOSPACE) return -ENOMEM; if (k != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return !strv_isempty(g.gl_pathv); } @@ -58,7 +58,7 @@ int glob_extend(char ***strv, const char *path) { if (k == GLOB_NOSPACE) return -ENOMEM; if (k != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; if (strv_isempty(g.gl_pathv)) return -ENOENT; diff --git a/src/basic/hash-funcs.c b/src/basic/hash-funcs.c new file mode 100644 index 0000000000..d4affaffee --- /dev/null +++ b/src/basic/hash-funcs.c @@ -0,0 +1,83 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2014 Michal Schmidt + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "hash-funcs.h" + +void string_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, strlen(p) + 1, state); +} + +int string_compare_func(const void *a, const void *b) { + return strcmp(a, b); +} + +const struct hash_ops string_hash_ops = { + .hash = string_hash_func, + .compare = string_compare_func +}; + +void trivial_hash_func(const void *p, struct siphash *state) { + siphash24_compress(&p, sizeof(p), state); +} + +int trivial_compare_func(const void *a, const void *b) { + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops trivial_hash_ops = { + .hash = trivial_hash_func, + .compare = trivial_compare_func +}; + +void uint64_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(uint64_t), state); +} + +int uint64_compare_func(const void *_a, const void *_b) { + uint64_t a, b; + a = *(const uint64_t*) _a; + b = *(const uint64_t*) _b; + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops uint64_hash_ops = { + .hash = uint64_hash_func, + .compare = uint64_compare_func +}; + +#if SIZEOF_DEV_T != 8 +void devt_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(dev_t), state); +} + +int devt_compare_func(const void *_a, const void *_b) { + dev_t a, b; + a = *(const dev_t*) _a; + b = *(const dev_t*) _b; + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops devt_hash_ops = { + .hash = devt_hash_func, + .compare = devt_compare_func +}; +#endif diff --git a/src/basic/hash-funcs.h b/src/basic/hash-funcs.h new file mode 100644 index 0000000000..c640eaf4d1 --- /dev/null +++ b/src/basic/hash-funcs.h @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2014 Michal Schmidt + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "macro.h" +#include "siphash24.h" + +typedef void (*hash_func_t)(const void *p, struct siphash *state); +typedef int (*compare_func_t)(const void *a, const void *b); + +struct hash_ops { + hash_func_t hash; + compare_func_t compare; +}; + +void string_hash_func(const void *p, struct siphash *state); +int string_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops string_hash_ops; + +/* This will compare the passed pointers directly, and will not + * dereference them. This is hence not useful for strings or + * suchlike. */ +void trivial_hash_func(const void *p, struct siphash *state); +int trivial_compare_func(const void *a, const void *b) _const_; +extern const struct hash_ops trivial_hash_ops; + +/* 32bit values we can always just embed in the pointer itself, but + * in order to support 32bit archs we need store 64bit values + * indirectly, since they don't fit in a pointer. */ +void uint64_hash_func(const void *p, struct siphash *state); +int uint64_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops uint64_hash_ops; + +/* On some archs dev_t is 32bit, and on others 64bit. And sometimes + * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ +#if SIZEOF_DEV_T != 8 +void devt_hash_func(const void *p, struct siphash *state) _pure_; +int devt_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops devt_hash_ops = { + .hash = devt_hash_func, + .compare = devt_compare_func +}; +#else +#define devt_hash_func uint64_hash_func +#define devt_compare_func uint64_compare_func +#define devt_hash_ops uint64_hash_ops +#endif diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index b3954e3223..dcd8ae412d 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -37,6 +37,7 @@ #include "util.h" #ifdef ENABLE_DEBUG_HASHMAP +#include <pthread.h> #include "list.h" #endif @@ -279,66 +280,6 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { }, }; -void string_hash_func(const void *p, struct siphash *state) { - siphash24_compress(p, strlen(p) + 1, state); -} - -int string_compare_func(const void *a, const void *b) { - return strcmp(a, b); -} - -const struct hash_ops string_hash_ops = { - .hash = string_hash_func, - .compare = string_compare_func -}; - -void trivial_hash_func(const void *p, struct siphash *state) { - siphash24_compress(&p, sizeof(p), state); -} - -int trivial_compare_func(const void *a, const void *b) { - return a < b ? -1 : (a > b ? 1 : 0); -} - -const struct hash_ops trivial_hash_ops = { - .hash = trivial_hash_func, - .compare = trivial_compare_func -}; - -void uint64_hash_func(const void *p, struct siphash *state) { - siphash24_compress(p, sizeof(uint64_t), state); -} - -int uint64_compare_func(const void *_a, const void *_b) { - uint64_t a, b; - a = *(const uint64_t*) _a; - b = *(const uint64_t*) _b; - return a < b ? -1 : (a > b ? 1 : 0); -} - -const struct hash_ops uint64_hash_ops = { - .hash = uint64_hash_func, - .compare = uint64_compare_func -}; - -#if SIZEOF_DEV_T != 8 -void devt_hash_func(const void *p, struct siphash *state) { - siphash24_compress(p, sizeof(dev_t), state); -} - -int devt_compare_func(const void *_a, const void *_b) { - dev_t a, b; - a = *(const dev_t*) _a; - b = *(const dev_t*) _b; - return a < b ? -1 : (a > b ? 1 : 0); -} - -const struct hash_ops devt_hash_ops = { - .hash = devt_hash_func, - .compare = devt_compare_func -}; -#endif - static unsigned n_buckets(HashmapBase *h) { return h->has_indirect ? h->indirect.n_buckets : hashmap_type_info[h->type].n_direct_buckets; diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index 708811124b..fdba9c61ff 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -26,8 +26,8 @@ #include <stdbool.h> #include <stddef.h> +#include "hash-funcs.h" #include "macro.h" -#include "siphash24.h" #include "util.h" /* @@ -70,47 +70,6 @@ typedef struct { #define _IDX_ITERATOR_FIRST (UINT_MAX - 1) #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) -typedef void (*hash_func_t)(const void *p, struct siphash *state); -typedef int (*compare_func_t)(const void *a, const void *b); - -struct hash_ops { - hash_func_t hash; - compare_func_t compare; -}; - -void string_hash_func(const void *p, struct siphash *state); -int string_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops string_hash_ops; - -/* This will compare the passed pointers directly, and will not - * dereference them. This is hence not useful for strings or - * suchlike. */ -void trivial_hash_func(const void *p, struct siphash *state); -int trivial_compare_func(const void *a, const void *b) _const_; -extern const struct hash_ops trivial_hash_ops; - -/* 32bit values we can always just embedd in the pointer itself, but - * in order to support 32bit archs we need store 64bit values - * indirectly, since they don't fit in a pointer. */ -void uint64_hash_func(const void *p, struct siphash *state); -int uint64_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops uint64_hash_ops; - -/* On some archs dev_t is 32bit, and on others 64bit. And sometimes - * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ -#if SIZEOF_DEV_T != 8 -void devt_hash_func(const void *p, struct siphash *state) _pure_; -int devt_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops devt_hash_ops = { - .hash = devt_hash_func, - .compare = devt_compare_func -}; -#else -#define devt_hash_func uint64_hash_func -#define devt_compare_func uint64_compare_func -#define devt_hash_ops uint64_hash_ops -#endif - /* Macros for type checking */ #define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \ (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \ diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 5143dddf8f..8609ffb3c9 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -219,7 +219,7 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { errno = 0; if (!inet_ntop(family, u, x, l)) { free(x); - return errno ? -errno : -EINVAL; + return errno > 0 ? -errno : -EINVAL; } *ret = x; @@ -236,7 +236,7 @@ int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { errno = 0; if (inet_pton(family, s, ret) <= 0) - return errno ? -errno : -EINVAL; + return errno > 0 ? -errno : -EINVAL; return 0; } diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index bcc116c783..f2b8865df5 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -33,6 +33,11 @@ union in_addr_union { struct in6_addr in6; }; +struct in_addr_data { + int family; + union in_addr_union address; +}; + int in_addr_is_null(int family, const union in_addr_union *u); int in_addr_is_link_local(int family, const union in_addr_union *u); int in_addr_is_localhost(int family, const union in_addr_union *u); diff --git a/src/basic/label.c b/src/basic/label.c index 70e6ee20bf..f72a985967 100644 --- a/src/basic/label.c +++ b/src/basic/label.c @@ -24,9 +24,9 @@ #include <unistd.h> #include "label.h" +#include "macro.h" #include "selinux-util.h" #include "smack-util.h" -#include "macro.h" int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { int r, q; diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 708da0d304..7784d02168 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -34,10 +34,10 @@ #include "dirent-util.h" #include "fd-util.h" +#include "hashmap.h" #include "locale-util.h" #include "path-util.h" #include "set.h" -#include "hashmap.h" #include "string-table.h" #include "string-util.h" #include "strv.h" diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index 704ae6cc52..6ecfc2ec46 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -30,8 +30,8 @@ #include "fd-util.h" #include "fs-util.h" #include "lockfile-util.h" -#include "path-util.h" #include "macro.h" +#include "path-util.h" int make_lock_file(const char *p, int operation, LockFile *ret) { _cleanup_close_ int fd = -1; diff --git a/src/basic/log.c b/src/basic/log.c index 829f85a5d8..a2bc0d5be2 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -49,12 +49,12 @@ #include "process-util.h" #include "signal-util.h" #include "socket-util.h" -#include "time-util.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "syslog-util.h" #include "terminal-util.h" +#include "time-util.h" #include "util.h" #define SNDBUF_SIZE (8*1024*1024) @@ -352,7 +352,7 @@ static int write_to_console( highlight = LOG_PRI(level) <= LOG_ERR && show_color; if (show_location) { - snprintf(location, sizeof(location), "(%s:%i) ", file, line); + xsprintf(location, "(%s:%i) ", file, line); IOVEC_SET_STRING(iovec[n++], location); } @@ -777,7 +777,7 @@ static void log_assert( return; DISABLE_WARNING_FORMAT_NONLITERAL; - snprintf(buffer, sizeof(buffer), format, text, file, line, func); + xsprintf(buffer, format, text, file, line, func); REENABLE_WARNING; log_abort_msg = buffer; diff --git a/src/basic/macro.h b/src/basic/macro.h index 5088e6720d..c529c6ecad 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -320,18 +320,47 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #define SET_FLAG(v, flag, b) \ (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) -#define IN_SET(x, y, ...) \ - ({ \ - static const typeof(y) _array[] = { (y), __VA_ARGS__ }; \ - const typeof(y) _x = (x); \ - unsigned _i; \ - bool _found = false; \ - for (_i = 0; _i < ELEMENTSOF(_array); _i++) \ - if (_array[_i] == _x) { \ - _found = true; \ - break; \ - } \ - _found; \ +#define CASE_F(X) case X: +#define CASE_F_1(CASE, X) CASE_F(X) +#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__) +#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__) +#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__) +#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__) +#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__) +#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__) +#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__) +#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__) +#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__) +#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__) +#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__) +#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__) +#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__) +#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__) +#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__) +#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__) +#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__) +#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__) +#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__) + +#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME +#define FOR_EACH_MAKE_CASE(...) \ + GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \ + CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ + (CASE_F,__VA_ARGS__) + +#define IN_SET(x, ...) \ + ({ \ + bool _found = false; \ + /* If the build breaks in the line below, you need to extend the case macros */ \ + static _unused_ char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){__VA_ARGS__})/sizeof(int)]; \ + switch(x) { \ + FOR_EACH_MAKE_CASE(__VA_ARGS__) \ + _found = true; \ + break; \ + default: \ + break; \ + } \ + _found; \ }) /* Define C11 thread_local attribute even on older gcc compiler diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index a9b2151195..789638f013 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -32,9 +32,9 @@ #include "alloc-util.h" #include "fd-util.h" +#include "macro.h" #include "memfd-util.h" #include "missing.h" -#include "macro.h" #include "string-util.h" #include "utf8.h" diff --git a/src/basic/missing.h b/src/basic/missing.h index d539ed00e4..c187afa287 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -131,6 +131,10 @@ #define NETLINK_LIST_MEMBERSHIPS 9 #endif +#ifndef SOL_SCTP +#define SOL_SCTP 132 +#endif + #if !HAVE_DECL_PIVOT_ROOT static inline int pivot_root(const char *new_root, const char *put_old) { return syscall(SYS_pivot_root, new_root, put_old); @@ -970,6 +974,10 @@ static inline int setns(int fd, int nstype) { #define IFA_FLAGS 8 #endif +#ifndef IFA_F_MANAGETEMPADDR +#define IFA_F_MANAGETEMPADDR 0x100 +#endif + #ifndef IFA_F_NOPREFIXROUTE #define IFA_F_NOPREFIXROUTE 0x200 #endif @@ -1125,3 +1133,19 @@ static inline key_serial_t request_key(const char *type, const char *description #ifndef KEY_SPEC_USER_KEYRING #define KEY_SPEC_USER_KEYRING -4 #endif + +#ifndef PR_CAP_AMBIENT +#define PR_CAP_AMBIENT 47 +#endif + +#ifndef PR_CAP_AMBIENT_IS_SET +#define PR_CAP_AMBIENT_IS_SET 1 +#endif + +#ifndef PR_CAP_AMBIENT_RAISE +#define PR_CAP_AMBIENT_RAISE 2 +#endif + +#ifndef PR_CAP_AMBIENT_CLEAR_ALL +#define PR_CAP_AMBIENT_CLEAR_ALL 4 +#endif diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 4b809541b1..9f9d52b5df 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -25,9 +25,9 @@ #include <sys/stat.h> #include "fs-util.h" +#include "macro.h" #include "mkdir.h" #include "path-util.h" -#include "macro.h" #include "stat-util.h" #include "user-util.h" diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index aaac2d47bd..10a6536cfc 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -31,11 +31,11 @@ #include "escape.h" #include "fd-util.h" #include "fileio.h" +#include "hashmap.h" #include "mount-util.h" #include "parse-util.h" #include "path-util.h" #include "set.h" -#include "hashmap.h" #include "stdio-util.h" #include "string-util.h" diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index 3be75e6614..b37250f08e 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -28,8 +28,8 @@ #include <sys/stat.h> #include <sys/types.h> -#include "missing.h" #include "macro.h" +#include "missing.h" int fd_is_mount_point(int fd, const char *filename, int flags); int path_is_mount_point(const char *path, int flags); diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 3d8123ca0d..d8de6f90ea 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -29,8 +29,8 @@ #include "alloc-util.h" #include "extract-word.h" -#include "parse-util.h" #include "macro.h" +#include "parse-util.h" #include "string-util.h" int parse_boolean(const char *v) { @@ -81,7 +81,7 @@ int parse_mode(const char *s, mode_t *ret) { errno = 0; l = strtol(s, &x, 8); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -176,7 +176,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { errno = 0; l = strtoull(p, &e, 10); - if (errno != 0) + if (errno > 0) return -errno; if (e == p) return -EINVAL; @@ -192,7 +192,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { char *e2; l2 = strtoull(e, &e2, 10); - if (errno != 0) + if (errno > 0) return -errno; /* Ignore failure. E.g. 10.M is valid */ @@ -330,7 +330,7 @@ int safe_atou(const char *s, unsigned *ret_u) { errno = 0; l = strtoul(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -352,7 +352,7 @@ int safe_atoi(const char *s, int *ret_i) { errno = 0; l = strtol(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -374,7 +374,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) { errno = 0; l = strtoull(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -394,7 +394,7 @@ int safe_atolli(const char *s, long long int *ret_lli) { errno = 0; l = strtoll(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -414,7 +414,7 @@ int safe_atou8(const char *s, uint8_t *ret) { errno = 0; l = strtoul(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -438,7 +438,7 @@ int safe_atou16(const char *s, uint16_t *ret) { errno = 0; l = strtoul(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -460,7 +460,7 @@ int safe_atoi16(const char *s, int16_t *ret) { errno = 0; l = strtol(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -485,7 +485,7 @@ int safe_atod(const char *s, double *ret_d) { errno = 0; d = strtod_l(s, &x, loc); - if (errno != 0) { + if (errno > 0) { freelocale(loc); return -errno; } diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 95b1052aeb..4837bb2d7d 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -34,16 +34,16 @@ #undef basename #include "alloc-util.h" +#include "extract-word.h" #include "fs-util.h" #include "log.h" #include "macro.h" #include "missing.h" #include "path-util.h" -#include "extract-word.h" -#include "time-util.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" bool path_is_absolute(const char *p) { return p[0] == '/'; @@ -102,7 +102,7 @@ int path_make_absolute_cwd(const char *p, char **ret) { cwd = get_current_dir_name(); if (!cwd) - return -errno; + return negative_errno(); c = strjoin(cwd, "/", p, NULL); } diff --git a/src/basic/prioq.c b/src/basic/prioq.c index 7d420d8a7b..86c5c0e9b4 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -33,8 +33,8 @@ #include <stdlib.h> #include "alloc-util.h" -#include "prioq.h" #include "hashmap.h" +#include "prioq.h" struct prioq_item { void *data; diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 1d60811cbf..4341d0093f 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -33,6 +33,9 @@ #include <sys/wait.h> #include <syslog.h> #include <unistd.h> +#ifdef HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> +#endif #include "alloc-util.h" #include "escape.h" @@ -41,10 +44,10 @@ #include "fs-util.h" #include "ioprio.h" #include "log.h" -#include "process-util.h" -#include "signal-util.h" #include "macro.h" #include "missing.h" +#include "process-util.h" +#include "signal-util.h" #include "string-table.h" #include "string-util.h" #include "user-util.h" @@ -730,6 +733,23 @@ const char* personality_to_string(unsigned long p) { return NULL; } +void valgrind_summary_hack(void) { +#ifdef HAVE_VALGRIND_VALGRIND_H + if (getpid() == 1 && RUNNING_ON_VALGRIND) { + pid_t pid; + pid = raw_clone(SIGCHLD, NULL); + if (pid < 0) + log_emergency_errno(errno, "Failed to fork off valgrind helper: %m"); + else if (pid == 0) + exit(EXIT_SUCCESS); + else { + log_info("Spawned valgrind helper as PID "PID_FMT".", pid); + (void) wait_for_terminate(pid, NULL); + } + } +#endif +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/basic/process-util.h b/src/basic/process-util.h index f4c4437624..ac4d05e65f 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -98,3 +98,5 @@ int sched_policy_from_string(const char *s); #define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) #define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) + +void valgrind_summary_hack(void); diff --git a/src/basic/ratelimit.c b/src/basic/ratelimit.c index ee0f8176b9..b62f3da76b 100644 --- a/src/basic/ratelimit.c +++ b/src/basic/ratelimit.c @@ -22,8 +22,8 @@ #include <sys/time.h> -#include "ratelimit.h" #include "macro.h" +#include "ratelimit.h" /* Modelled after Linux' lib/ratelimit.c by Dave Young * <hidave.darkstar@gmail.com>, which is licensed GPLv2. */ diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 2de965daa6..44f885db16 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -22,9 +22,9 @@ #include <errno.h> #include <sys/resource.h> +#include "macro.h" #include "missing.h" #include "rlimit-util.h" -#include "macro.h" #include "string-table.h" int setrlimit_closest(int resource, const struct rlimit *rlim) { diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index 0408e22777..4807561723 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -30,11 +30,11 @@ #include "btrfs-util.h" #include "fd-util.h" +#include "log.h" +#include "macro.h" #include "mount-util.h" #include "path-util.h" #include "rm-rf.h" -#include "log.h" -#include "macro.h" #include "stat-util.h" #include "string-util.h" @@ -82,7 +82,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { errno = 0; de = readdir(d); if (!de) { - if (errno != 0 && ret == 0) + if (errno > 0 && ret == 0) ret = -errno; return ret; } diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 9be8e2c76f..5956c4fe43 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -35,10 +35,10 @@ #endif #include "alloc-util.h" -#include "path-util.h" -#include "selinux-util.h" #include "log.h" #include "macro.h" +#include "path-util.h" +#include "selinux-util.h" #include "time-util.h" #include "util.h" diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index fd9258dfca..315efadd93 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -23,9 +23,10 @@ #include <stdarg.h> #include <stdio.h> +#include "macro.h" #include "parse-util.h" #include "signal-util.h" -#include "macro.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" @@ -234,9 +235,9 @@ const char *signal_to_string(int signo) { return name; if (signo >= SIGRTMIN && signo <= SIGRTMAX) - snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); + xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN); else - snprintf(buf, sizeof(buf), "%d", signo); + xsprintf(buf, "%d", signo); return buf; } diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index 65667b9859..060e8ba387 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -17,8 +17,8 @@ coding style) */ -#include "siphash24.h" #include "macro.h" +#include "siphash24.h" #include "unaligned.h" static inline uint64_t rotate_left(uint64_t x, uint8_t b) { diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index 3f7e20362b..54e2420cc6 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -16,6 +16,8 @@ struct siphash { void siphash24_init(struct siphash *state, const uint8_t k[16]); void siphash24_compress(const void *in, size_t inlen, struct siphash *state); +#define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state)) + uint64_t siphash24_finalize(struct siphash *state); uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index e8030c92f3..b9e4ff87d8 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -29,11 +29,11 @@ #include "alloc-util.h" #include "fileio.h" +#include "log.h" +#include "macro.h" #include "path-util.h" #include "process-util.h" #include "smack-util.h" -#include "log.h" -#include "macro.h" #include "string-table.h" #include "xattr-util.h" diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 2dc6c76752..bd206586ce 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -31,12 +31,12 @@ #include "alloc-util.h" #include "fd-util.h" +#include "log.h" #include "macro.h" #include "missing.h" #include "mkdir.h" #include "selinux-util.h" #include "socket-util.h" -#include "log.h" int socket_address_listen( const SocketAddress *a, @@ -147,7 +147,7 @@ int socket_address_listen( return r; } -int make_socket_fd(int log_level, const char* address, int flags) { +int make_socket_fd(int log_level, const char* address, int type, int flags) { SocketAddress a; int fd, r; @@ -155,7 +155,9 @@ int make_socket_fd(int log_level, const char* address, int flags) { if (r < 0) return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address); - fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, + a.type = type; + + fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, NULL, false, false, false, 0755, 0644, NULL); if (fd < 0 || log_get_max_level() >= log_level) { _cleanup_free_ char *p = NULL; diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index c4d6d0b9f5..f2bb3bab86 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -36,12 +36,12 @@ #include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "log.h" #include "macro.h" #include "missing.h" #include "parse-util.h" #include "path-util.h" #include "socket-util.h" -#include "log.h" #include "string-table.h" #include "string-util.h" #include "user-util.h" @@ -440,17 +440,10 @@ const char* socket_address_get_path(const SocketAddress *a) { } bool socket_ipv6_is_supported(void) { - _cleanup_free_ char *l = NULL; - - if (access("/sys/module/ipv6", F_OK) != 0) + if (access("/proc/net/sockstat6", F_OK) != 0) return false; - /* If we can't check "disable" parameter, assume enabled */ - if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0) - return true; - - /* If module was loaded with disable=1 no IPv6 available */ - return l[0] == '0'; + return true; } bool socket_address_matches_fd(const SocketAddress *a, int fd) { @@ -870,16 +863,24 @@ int getpeersec(int fd, char **ret) { return 0; } -int send_one_fd(int transport_fd, int fd, int flags) { +int send_one_fd_sa( + int transport_fd, + int fd, + const struct sockaddr *sa, socklen_t len, + int flags) { + union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; } control = {}; + struct cmsghdr *cmsg; + struct msghdr mh = { + .msg_name = (struct sockaddr*) sa, + .msg_namelen = len, .msg_control = &control, .msg_controllen = sizeof(control), }; - struct cmsghdr *cmsg; assert(transport_fd >= 0); assert(fd >= 0); diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index eb3febf669..2323ccf3ab 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -89,7 +89,7 @@ int socket_address_listen( mode_t directory_mode, mode_t socket_mode, const char *label); -int make_socket_fd(int log_level, const char* address, int flags); +int make_socket_fd(int log_level, const char* address, int type, int flags); bool socket_address_is(const SocketAddress *a, const char *s, int type); bool socket_address_is_netlink(const SocketAddress *a, const char *s); @@ -128,7 +128,11 @@ int ip_tos_from_string(const char *s); int getpeercred(int fd, struct ucred *ucred); int getpeersec(int fd, char **ret); -int send_one_fd(int transport_fd, int fd, int flags); +int send_one_fd_sa(int transport_fd, + int fd, + const struct sockaddr *sa, socklen_t len, + int flags); +#define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags) int receive_one_fd(int transport_fd, int flags); #define CMSG_FOREACH(cmsg, mh) \ diff --git a/src/basic/string-table.c b/src/basic/string-table.c index 07a6d785f8..4633a57f44 100644 --- a/src/basic/string-table.c +++ b/src/basic/string-table.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "string-util.h" #include "string-table.h" +#include "string-util.h" ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { size_t i; diff --git a/src/basic/string-table.h b/src/basic/string-table.h index 2181a3a767..588404ab5a 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -47,16 +47,34 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ } +#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ + scope type name##_from_string(const char *s) { \ + int b; \ + b = parse_boolean(s); \ + if (b == 0) \ + return (type) 0; \ + else if (b > 0) \ + return yes; \ + return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ + } + #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ struct __useless_struct_to_allow_trailing_semicolon__ +#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) +#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) + /* For string conversions where numbers are also acceptable */ #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ int name##_to_string_alloc(type i, char **str) { \ diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 8178c7093f..1f95a9abba 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -317,18 +317,67 @@ char *truncate_nl(char *s) { return s; } +char ascii_tolower(char x) { + + if (x >= 'A' && x <= 'Z') + return x - 'A' + 'a'; + + return x; +} + char *ascii_strlower(char *t) { char *p; assert(t); for (p = t; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p = *p - 'A' + 'a'; + *p = ascii_tolower(*p); return t; } +char *ascii_strlower_n(char *t, size_t n) { + size_t i; + + if (n <= 0) + return t; + + for (i = 0; i < n; i++) + t[i] = ascii_tolower(t[i]); + + return t; +} + +int ascii_strcasecmp_n(const char *a, const char *b, size_t n) { + + for (; n > 0; a++, b++, n--) { + int x, y; + + x = (int) (uint8_t) ascii_tolower(*a); + y = (int) (uint8_t) ascii_tolower(*b); + + if (x != y) + return x - y; + } + + return 0; +} + +int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m) { + int r; + + r = ascii_strcasecmp_n(a, b, MIN(n, m)); + if (r != 0) + return r; + + if (n < m) + return -1; + else if (n > m) + return 1; + else + return 0; +} + bool chars_intersect(const char *a, const char *b) { const char *p; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index b59b9b5a71..8ea18f45aa 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -130,7 +130,12 @@ char *strstrip(char *s); char *delete_chars(char *s, const char *bad); char *truncate_nl(char *s); -char *ascii_strlower(char *path); +char ascii_tolower(char x); +char *ascii_strlower(char *s); +char *ascii_strlower_n(char *s, size_t n); + +int ascii_strcasecmp_n(const char *a, const char *b, size_t n); +int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m); bool chars_intersect(const char *a, const char *b) _pure_; diff --git a/src/basic/strv.h b/src/basic/strv.h index d0dd08baf3..bb61db2638 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -26,8 +26,8 @@ #include <stdbool.h> #include <stddef.h> -#include "extract-word.h" #include "alloc-util.h" +#include "extract-word.h" #include "macro.h" #include "util.h" diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 68664a152f..fedfc8a5df 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -43,11 +43,11 @@ #include "fileio.h" #include "fs-util.h" #include "io-util.h" +#include "log.h" +#include "macro.h" #include "parse-util.h" #include "process-util.h" #include "socket-util.h" -#include "log.h" -#include "macro.h" #include "stat-util.h" #include "string-util.h" #include "terminal-util.h" @@ -128,7 +128,7 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { errno = 0; if (!fgets(line, sizeof(line), f)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; truncate_nl(line); @@ -212,7 +212,7 @@ int ask_string(char **ret, const char *text, ...) { errno = 0; if (!fgets(line, sizeof(line), stdin)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; if (!endswith(line, "\n")) putchar('\n'); @@ -1135,3 +1135,16 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { return receive_one_fd(pair[0], 0); } + +bool colors_enabled(void) { + const char *colors; + + colors = getenv("SYSTEMD_COLORS"); + if (!colors) { + if (streq_ptr(getenv("TERM"), "dumb")) + return false; + return on_tty(); + } + + return parse_boolean(colors) != 0; +} diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 597a0060ad..a7c96a77cb 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -79,37 +79,38 @@ unsigned lines(void); void columns_lines_cache_reset(int _unused_ signum); bool on_tty(void); +bool colors_enabled(void); static inline const char *ansi_underline(void) { - return on_tty() ? ANSI_UNDERLINE : ""; + return colors_enabled() ? ANSI_UNDERLINE : ""; } static inline const char *ansi_highlight(void) { - return on_tty() ? ANSI_HIGHLIGHT : ""; + return colors_enabled() ? ANSI_HIGHLIGHT : ""; } static inline const char *ansi_highlight_underline(void) { - return on_tty() ? ANSI_HIGHLIGHT_UNDERLINE : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_UNDERLINE : ""; } static inline const char *ansi_highlight_red(void) { - return on_tty() ? ANSI_HIGHLIGHT_RED : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_RED : ""; } static inline const char *ansi_highlight_green(void) { - return on_tty() ? ANSI_HIGHLIGHT_GREEN : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_GREEN : ""; } static inline const char *ansi_highlight_yellow(void) { - return on_tty() ? ANSI_HIGHLIGHT_YELLOW : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_YELLOW : ""; } static inline const char *ansi_highlight_blue(void) { - return on_tty() ? ANSI_HIGHLIGHT_BLUE : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_BLUE : ""; } static inline const char *ansi_normal(void) { - return on_tty() ? ANSI_NORMAL : ""; + return colors_enabled() ? ANSI_NORMAL : ""; } int get_ctty_devnr(pid_t pid, dev_t *d); diff --git a/src/basic/time-util.c b/src/basic/time-util.c index a9296d6ee6..bfc7cf870c 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -34,10 +34,10 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" -#include "parse-util.h" -#include "path-util.h" #include "log.h" #include "macro.h" +#include "parse-util.h" +#include "path-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index bdec97e54b..5fc3b9d6fd 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -28,8 +28,8 @@ #include "alloc-util.h" #include "bus-label.h" #include "hexdecoct.h" -#include "path-util.h" #include "macro.h" +#include "path-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 55c64abdd9..70a6e1f5e4 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -34,10 +34,10 @@ #include "alloc-util.h" #include "fd-util.h" +#include "formats-util.h" #include "macro.h" #include "parse-util.h" #include "path-util.h" -#include "formats-util.h" #include "string-util.h" #include "user-util.h" @@ -68,7 +68,7 @@ int parse_uid(const char *s, uid_t *ret) { if (!uid_is_valid(uid)) return -ENXIO; /* we return ENXIO instead of EINVAL * here, to make it easy to distuingish - * invalid numeric uids invalid + * invalid numeric uids from invalid * strings. */ if (ret) diff --git a/src/basic/util.c b/src/basic/util.c index 6d264e0007..4434ecfdf6 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -51,12 +51,12 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" -#include "signal-util.h" #include "set.h" -#include "time-util.h" +#include "signal-util.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "user-util.h" #include "util.h" @@ -513,7 +513,7 @@ int on_ac_power(void) { errno = 0; de = readdir(d); - if (!de && errno != 0) + if (!de && errno > 0) return -errno; if (!de) diff --git a/src/basic/virt.c b/src/basic/virt.c index eb67949166..0ffc2769d2 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -26,9 +26,11 @@ #include <unistd.h> #include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" #include "fileio.h" -#include "process-util.h" #include "macro.h" +#include "process-util.h" #include "stat-util.h" #include "string-table.h" #include "string-util.h" diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index 166e2b23fa..960209282f 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -29,10 +29,10 @@ #include "alloc-util.h" #include "fd-util.h" -#include "sparse-endian.h" #include "macro.h" -#include "time-util.h" +#include "sparse-endian.h" #include "stdio-util.h" +#include "time-util.h" #include "xattr-util.h" int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) { |