diff options
Diffstat (limited to 'src/basic')
216 files changed, 5119 insertions, 5072 deletions
diff --git a/src/basic/MurmurHash2.c b/src/basic/MurmurHash2.c index 47adfb4d0a..5859af0a81 100644 --- a/src/basic/MurmurHash2.c +++ b/src/basic/MurmurHash2.c @@ -30,7 +30,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") // Other compilers -#else // defined(_MSC_VER) +#else // defined(_MSC_VER) #define BIG_CONSTANT(x) (x##LLU) diff --git a/src/basic/MurmurHash2.h b/src/basic/MurmurHash2.h index 93362dd485..6104b4fbe6 100644 --- a/src/basic/MurmurHash2.h +++ b/src/basic/MurmurHash2.h @@ -18,7 +18,7 @@ typedef unsigned __int64 uint64_t; // Other compilers -#else // defined(_MSC_VER) +#else // defined(_MSC_VER) #include <stdint.h> diff --git a/src/basic/af-list.c b/src/basic/af-list.c index fa81a69e0e..866a1d4317 100644 --- a/src/basic/af-list.c +++ b/src/basic/af-list.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <string.h> #include <sys/socket.h> diff --git a/src/basic/af-list.h b/src/basic/af-list.h index 1684bc6a0f..8342323b8a 100644 --- a/src/basic/af-list.h +++ b/src/basic/af-list.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <sys/socket.h> #include "string-util.h" diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c index cdde4f2859..405445eac1 100644 --- a/src/basic/alloc-util.c +++ b/src/basic/alloc-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdint.h> #include <string.h> diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index ec7808c1f7..ebe42889ea 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <alloca.h> #include <stddef.h> #include <stdlib.h> @@ -31,9 +12,17 @@ #define new0(t, n) ((t*) calloc((n), sizeof(t))) -#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) +#define newa(t, n) \ + ({ \ + assert(!size_multiply_overflow(sizeof(t), n)); \ + (t*) alloca(sizeof(t)*(n)); \ + }) -#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) +#define newa0(t, n) \ + ({ \ + assert(!size_multiply_overflow(sizeof(t), n)); \ + (t*) alloca0(sizeof(t)*(n)); \ + }) #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) @@ -130,3 +119,12 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); _new_ = alloca_align(_size_, (align)); \ (void*)memset(_new_, 0, _size_); \ }) + +/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to + * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ +#define TAKE_PTR(ptr) \ + ({ \ + typeof(ptr) _ptr_ = (ptr); \ + (ptr) = NULL; \ + _ptr_; \ + }) diff --git a/src/basic/architecture.c b/src/basic/architecture.c index 46157061ed..85837b5ebf 100644 --- a/src/basic/architecture.c +++ b/src/basic/architecture.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <sys/utsname.h> diff --git a/src/basic/architecture.h b/src/basic/architecture.h index c81a1c2f44..443e890eab 100644 --- a/src/basic/architecture.h +++ b/src/basic/architecture.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <endian.h> #include "macro.h" diff --git a/src/basic/arphrd-list.c b/src/basic/arphrd-list.c index 5df93a59c1..a7ae4b8162 100644 --- a/src/basic/arphrd-list.c +++ b/src/basic/arphrd-list.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <net/if_arp.h> #include <string.h> diff --git a/src/basic/arphrd-list.h b/src/basic/arphrd-list.h index 2222e92c8a..5dcfe5e12d 100644 --- a/src/basic/arphrd-list.h +++ b/src/basic/arphrd-list.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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/>. -***/ - const char *arphrd_to_name(int id); int arphrd_from_name(const char *name); diff --git a/src/basic/async.c b/src/basic/async.c index b6c6d6a80b..1c4b575b05 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <errno.h> #include <pthread.h> diff --git a/src/basic/async.h b/src/basic/async.h index 01c975bb30..3160613184 100644 --- a/src/basic/async.h +++ b/src/basic/async.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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/>. -***/ - int asynchronous_job(void* (*func)(void *p), void *arg); int asynchronous_sync(pid_t *ret_pid); diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c index 6a93c9109c..5cbaef3eba 100644 --- a/src/basic/audit-util.c +++ b/src/basic/audit-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <linux/netlink.h> @@ -95,10 +77,9 @@ bool use_audit(void) { fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT); if (fd < 0) { cached_use = !IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT, EPERM); - if (errno == EPERM) - log_debug_errno(errno, "Audit access prohibited, won't talk to audit"); - } - else { + if (!cached_use) + log_debug_errno(errno, "Won't talk to audit: %m"); + } else { cached_use = true; safe_close(fd); } diff --git a/src/basic/audit-util.h b/src/basic/audit-util.h index dba15de8ee..c9fc49871d 100644 --- a/src/basic/audit-util.h +++ b/src/basic/audit-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <stdint.h> #include <sys/types.h> diff --git a/src/basic/barrier.c b/src/basic/barrier.c index cd3638b676..587852aac8 100644 --- a/src/basic/barrier.c +++ b/src/basic/barrier.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann <dh.herrmann@gmail.com> - - 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 <errno.h> #include <fcntl.h> diff --git a/src/basic/barrier.h b/src/basic/barrier.h index 7260d751c4..96a9955c6f 100644 --- a/src/basic/barrier.h +++ b/src/basic/barrier.h @@ -1,24 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann <dh.herrmann@gmail.com> - - 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 <stdbool.h> #include <stdint.h> diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index f1aa7c5e51..c17c6a7a02 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2015 Tom Gundersen - - 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 <errno.h> #include <stddef.h> diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h index f1d822c643..7ff5cffd26 100644 --- a/src/basic/bitmap.h +++ b/src/basic/bitmap.h @@ -1,24 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2015 Tom Gundersen - - 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 <stdbool.h> diff --git a/src/basic/blkid-util.h b/src/basic/blkid-util.h index 3aba76b79e..e4eb600ed6 100644 --- a/src/basic/blkid-util.h +++ b/src/basic/blkid-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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/>. -***/ - #if HAVE_BLKID #include <blkid.h> #endif @@ -28,5 +9,4 @@ #if HAVE_BLKID DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe); -#define _cleanup_blkid_free_probe_ _cleanup_(blkid_free_probep) #endif diff --git a/src/basic/blockdev-util.c b/src/basic/blockdev-util.c index 3a8f8d1c27..42b311eccd 100644 --- a/src/basic/blockdev-util.c +++ b/src/basic/blockdev-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <sys/stat.h> #include <sys/statfs.h> @@ -94,38 +76,26 @@ int get_block_device(const char *path, dev_t *dev) { if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) return btrfs_get_block_device(path, dev); + *dev = 0; return 0; } -int get_block_device_harder(const char *path, dev_t *dev) { +int block_get_originating(dev_t dt, dev_t *ret) { _cleanup_closedir_ DIR *d = NULL; _cleanup_free_ char *t = NULL; char p[SYS_BLOCK_PATH_MAX("/slaves")]; struct dirent *de, *found = NULL; - const char *q; unsigned maj, min; - dev_t dt; + const char *q; int r; - assert(path); - assert(dev); - - /* Gets the backing block device for a file system, and - * handles LUKS encrypted file systems, looking for its - * immediate parent, if there is one. */ - - r = get_block_device(path, &dt); - if (r <= 0) - return r; + /* For the specified block device tries to chase it through the layers, in case LUKS-style DM stacking is used, + * trying to find the next underlying layer. */ xsprintf_sys_block_path(p, "/slaves", dt); d = opendir(p); - if (!d) { - if (errno == ENOENT) - goto fallback; - + if (!d) return -errno; - } FOREACH_DIRENT_ALL(de, d, return -errno) { @@ -153,34 +123,28 @@ int get_block_device_harder(const char *path, dev_t *dev) { return -ENOMEM; r = read_one_line_file(u, &a); - if (r < 0) { - log_debug_errno(r, "Failed to read %s: %m", u); - goto fallback; - } + if (r < 0) + return log_debug_errno(r, "Failed to read %s: %m", u); r = read_one_line_file(v, &b); - if (r < 0) { - log_debug_errno(r, "Failed to read %s: %m", v); - goto fallback; - } + if (r < 0) + return log_debug_errno(r, "Failed to read %s: %m", v); /* Check if the parent device is the same. If not, then the two backing devices are on * different physical devices, and we don't support that. */ if (!streq(a, b)) - goto fallback; + return -ENOTUNIQ; } found = de; } if (!found) - goto fallback; + return -ENOENT; q = strjoina(p, "/", found->d_name, "/dev"); r = read_one_line_file(q, &t); - if (r == -ENOENT) - goto fallback; if (r < 0) return r; @@ -188,12 +152,28 @@ int get_block_device_harder(const char *path, dev_t *dev) { return -EINVAL; if (maj == 0) - goto fallback; + return -ENOENT; - *dev = makedev(maj, min); + *ret = makedev(maj, min); return 1; +} + +int get_block_device_harder(const char *path, dev_t *ret) { + int r; + + assert(path); + assert(ret); + + /* Gets the backing block device for a file system, and handles LUKS encrypted file systems, looking for its + * immediate parent, if there is one. */ + + r = get_block_device(path, ret); + if (r <= 0) + return r; + + r = block_get_originating(*ret, ret); + if (r < 0) + log_debug_errno(r, "Failed to chase block device '%s', ignoring: %m", path); -fallback: - *dev = dt; return 1; } diff --git a/src/basic/blockdev-util.h b/src/basic/blockdev-util.h index 642b7ce522..6d8a796568 100644 --- a/src/basic/blockdev-util.h +++ b/src/basic/blockdev-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <sys/types.h> #include "macro.h" @@ -32,6 +13,7 @@ xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), strempty(suffix)) int block_get_whole_disk(dev_t d, dev_t *ret); +int block_get_originating(dev_t d, dev_t *ret); int get_block_device(const char *path, dev_t *dev); diff --git a/src/basic/bpf-program.c b/src/basic/bpf-program.c index a244742f91..ed57f9ffdc 100644 --- a/src/basic/bpf-program.c +++ b/src/basic/bpf-program.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2016 Daniel Mack - - 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 <fcntl.h> #include <sys/stat.h> @@ -42,8 +24,8 @@ int bpf_program_new(uint32_t prog_type, BPFProgram **ret) { p->prog_type = prog_type; p->kernel_fd = -1; - *ret = p; - p = NULL; + *ret = TAKE_PTR(p); + return 0; } diff --git a/src/basic/bpf-program.h b/src/basic/bpf-program.h index 3d6c5e50ef..c21eb2f72a 100644 --- a/src/basic/bpf-program.h +++ b/src/basic/bpf-program.h @@ -1,27 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2016 Daniel Mack - - 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/>. - - [Except for the stuff copy/pasted from the kernel sources, see below] -***/ - #include <linux/bpf.h> #include <stdint.h> #include <sys/syscall.h> diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 3d30497f74..6d2490f3d7 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> @@ -290,8 +272,10 @@ int btrfs_get_block_device_fd(int fd, dev_t *dev) { return -errno; /* We won't do this for btrfs RAID */ - if (fsi.num_devices != 1) + if (fsi.num_devices != 1) { + *dev = 0; return 0; + } for (id = 1; id <= fsi.max_id; id++) { struct btrfs_ioctl_dev_info_args di = { @@ -511,7 +495,7 @@ int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) { (usec_t) le32toh(ri->otime.nsec) / NSEC_PER_USEC; ret->subvol_id = subvol_id; - ret->read_only = !!(le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY); + ret->read_only = le64toh(ri->flags) & BTRFS_ROOT_SUBVOL_RDONLY; assert_cc(sizeof(ri->uuid) == sizeof(ret->uuid)); memcpy(&ret->uuid, ri->uuid, sizeof(ret->uuid)); @@ -1703,7 +1687,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag if (r == -ENOTTY && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) { /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */ if (mkdir(new_path, 0755) < 0) - return r; + return -errno; plain_directory = true; } else if (r < 0) @@ -1841,8 +1825,7 @@ int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) { return 0; } - *ret = items; - items = NULL; + *ret = TAKE_PTR(items); return (int) n_items; } diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 952b3c26da..a594387b5a 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <stdbool.h> #include <stdint.h> #include <sys/types.h> diff --git a/src/basic/build.h b/src/basic/build.h index 0d078efe6f..2c46550300 100644 --- a/src/basic/build.h +++ b/src/basic/build.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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/>. -***/ - #if HAVE_PAM #define _PAM_FEATURE_ "+PAM" #else diff --git a/src/basic/bus-label.c b/src/basic/bus-label.c index a072d0ad5d..1613cf7fd7 100644 --- a/src/basic/bus-label.c +++ b/src/basic/bus-label.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <stdlib.h> diff --git a/src/basic/bus-label.h b/src/basic/bus-label.h index 5c6bc1f267..664cfaf67f 100644 --- a/src/basic/bus-label.h +++ b/src/basic/bus-label.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <stddef.h> #include <stdlib.h> #include <string.h> diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index fd78022773..8cb645aeac 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - 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 <alloca.h> #include <ctype.h> @@ -43,6 +25,12 @@ #define MIN_YEAR 1970 #define MAX_YEAR 2199 +/* An arbitrary limit on the length of the chains of components. We don't want to + * build a very long linked list, which would be slow to iterate over and might cause + * our stack to overflow. It's unlikely that legitimate uses require more than a few + * linked compenents anyway. */ +#define CALENDARSPEC_COMPONENTS_MAX 240 + static void free_chain(CalendarComponent *c) { CalendarComponent *n; @@ -91,8 +79,8 @@ static int component_compare(const void *_a, const void *_b) { } static void normalize_chain(CalendarComponent **c) { - unsigned n = 0, k; CalendarComponent **b, *i, **j, *next; + size_t n = 0, k; assert(c); @@ -111,7 +99,7 @@ static void normalize_chain(CalendarComponent **c) { if (n <= 1) return; - j = b = alloca(sizeof(CalendarComponent*) * n); + j = b = newa(CalendarComponent*, n); for (i = *c; i; i = i->next) *(j++) = i; @@ -181,6 +169,8 @@ int calendar_spec_normalize(CalendarSpec *c) { } _pure_ static bool chain_valid(CalendarComponent *c, int from, int to, bool end_of_month) { + assert(to >= from); + if (!c) return true; @@ -191,6 +181,10 @@ _pure_ static bool chain_valid(CalendarComponent *c, int from, int to, bool end_ if (c->start < from || c->start > to) return false; + /* Avoid overly large values that could cause overflow */ + if (c->repeat > to - from) + return false; + /* * c->repeat must be short enough so at least one repetition may * occur before the end of the interval. For dates scheduled @@ -421,7 +415,7 @@ static int parse_weekdays(const char **p, CalendarSpec *c) { assert(c); for (;;) { - unsigned i; + size_t i; for (i = 0; i < ELEMENTSOF(day_nr); i++) { size_t skip; @@ -581,7 +575,8 @@ static int calendarspec_from_time_t(CalendarSpec *c, time_t time) { CalendarComponent *year = NULL, *month = NULL, *day = NULL, *hour = NULL, *minute = NULL, *us = NULL; int r; - assert_se(gmtime_r(&time, &tm)); + if (!gmtime_r(&time, &tm)) + return -ERANGE; r = const_chain(tm.tm_year + 1900, &year); if (r < 0) @@ -617,15 +612,16 @@ static int calendarspec_from_time_t(CalendarSpec *c, time_t time) { return 0; } -static int prepend_component(const char **p, bool usec, CalendarComponent **c) { +static int prepend_component(const char **p, bool usec, unsigned nesting, CalendarComponent **c) { int r, start, stop = -1, repeat = 0; CalendarComponent *cc; - const char *e; + const char *e = *p; assert(p); assert(c); - e = *p; + if (nesting > CALENDARSPEC_COMPONENTS_MAX) + return -ENOBUFS; r = parse_component_decimal(&e, usec, &start); if (r < 0) @@ -667,7 +663,7 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) { if (*e ==',') { *p += 1; - return prepend_component(p, usec, c); + return prepend_component(p, usec, nesting + 1, c); } return 0; @@ -696,7 +692,7 @@ static int parse_chain(const char **p, bool usec, CalendarComponent **c) { return 0; } - r = prepend_component(&t, usec, &cc); + r = prepend_component(&t, usec, 0, &cc); if (r < 0) { free_chain(cc); return r; @@ -890,7 +886,7 @@ fail: int calendar_spec_from_string(const char *p, CalendarSpec **spec) { const char *utc; - CalendarSpec *c; + _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL; int r; assert(p); @@ -936,60 +932,56 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { const char *last_space; last_space = strrchr(p, ' '); - if (last_space != NULL && timezone_is_valid(last_space + 1)) { + if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG)) { c->timezone = strdup(last_space + 1); - if (!c->timezone) { - r = -ENOMEM; - goto fail; - } + if (!c->timezone) + return -ENOMEM; p = strndupa(p, last_space - p); } } } - if (isempty(p)) { - r = -EINVAL; - goto fail; - } + if (isempty(p)) + return -EINVAL; if (strcaseeq(p, "minutely")) { r = const_chain(0, &c->microsecond); if (r < 0) - goto fail; + return r; } else if (strcaseeq(p, "hourly")) { r = const_chain(0, &c->minute); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->microsecond); if (r < 0) - goto fail; + return r; } else if (strcaseeq(p, "daily")) { r = const_chain(0, &c->hour); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->minute); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->microsecond); if (r < 0) - goto fail; + return r; } else if (strcaseeq(p, "monthly")) { r = const_chain(1, &c->day); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->hour); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->minute); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->microsecond); if (r < 0) - goto fail; + return r; } else if (strcaseeq(p, "annually") || strcaseeq(p, "yearly") || @@ -997,19 +989,19 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(1, &c->month); if (r < 0) - goto fail; + return r; r = const_chain(1, &c->day); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->hour); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->minute); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->microsecond); if (r < 0) - goto fail; + return r; } else if (strcaseeq(p, "weekly")) { @@ -1017,40 +1009,40 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(0, &c->hour); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->minute); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->microsecond); if (r < 0) - goto fail; + return r; } else if (strcaseeq(p, "quarterly")) { r = const_chain(1, &c->month); if (r < 0) - goto fail; + return r; r = const_chain(4, &c->month); if (r < 0) - goto fail; + return r; r = const_chain(7, &c->month); if (r < 0) - goto fail; + return r; r = const_chain(10, &c->month); if (r < 0) - goto fail; + return r; r = const_chain(1, &c->day); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->hour); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->minute); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->microsecond); if (r < 0) - goto fail; + return r; } else if (strcaseeq(p, "biannually") || strcaseeq(p, "bi-annually") || @@ -1059,59 +1051,51 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(1, &c->month); if (r < 0) - goto fail; + return r; r = const_chain(7, &c->month); if (r < 0) - goto fail; + return r; r = const_chain(1, &c->day); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->hour); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->minute); if (r < 0) - goto fail; + return r; r = const_chain(0, &c->microsecond); if (r < 0) - goto fail; + return r; } else { r = parse_weekdays(&p, c); if (r < 0) - goto fail; + return r; r = parse_date(&p, c); if (r < 0) - goto fail; + return r; if (r == 0) { r = parse_calendar_time(&p, c); if (r < 0) - goto fail; + return r; } - if (*p != 0) { - r = -EINVAL; - goto fail; - } + if (*p != 0) + return -EINVAL; } r = calendar_spec_normalize(c); if (r < 0) - goto fail; + return r; - if (!calendar_spec_valid(c)) { - r = -EINVAL; - goto fail; - } + if (!calendar_spec_valid(c)) + return -EINVAL; - *spec = c; + *spec = TAKE_PTR(c); return 0; - -fail: - calendar_spec_free(c); - return r; } static int find_end_of_month(struct tm *tm, bool utc, int day) { @@ -1161,7 +1145,7 @@ static int find_matching_component(const CalendarSpec *spec, const CalendarCompo } else if (c->repeat > 0) { int k; - k = start + c->repeat * ((*val - start + c->repeat - 1) / c->repeat); + k = start + c->repeat * DIV_ROUND_UP(*val - start, c->repeat); if ((!d_set || k < d) && (stop < 0 || k <= stop)) { d = k; diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h index 124f7f5880..3bf8a39e1a 100644 --- a/src/basic/calendarspec.h +++ b/src/basic/calendarspec.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - 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/>. -***/ - /* A structure for specifying (possibly repetitive) points in calendar * time, a la cron */ diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c index c4557666ef..bfcda33520 100644 --- a/src/basic/cap-list.c +++ b/src/basic/cap-list.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <errno.h> #include <string.h> @@ -103,8 +85,7 @@ int capability_set_to_string_alloc(uint64_t set, char **s) { str[n > 0 ? n - 1 : 0] = '\0'; /* truncate the last space, if it's there */ - *s = str; - str = NULL; + *s = TAKE_PTR(str); return 0; } diff --git a/src/basic/cap-list.h b/src/basic/cap-list.h index ca9f4aa970..ab41924d9c 100644 --- a/src/basic/cap-list.h +++ b/src/basic/cap-list.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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/>. -***/ - const char *capability_to_name(int id); int capability_from_name(const char *name); int capability_list_length(void); diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index 97778c55ab..6ae35e078b 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <grp.h> @@ -241,10 +223,10 @@ finish: } static int drop_from_file(const char *fn, uint64_t keep) { - int r, k; - uint32_t hi, lo; + _cleanup_free_ char *p = NULL; uint64_t current, after; - char *p; + uint32_t hi, lo; + int r, k; r = read_one_line_file(fn, &p); if (r < 0) @@ -254,8 +236,6 @@ static int drop_from_file(const char *fn, uint64_t keep) { assert_cc(sizeof(lo) == sizeof(unsigned)); k = sscanf(p, "%u %u", &lo, &hi); - free(p); - if (k != 2) return -EIO; @@ -268,13 +248,7 @@ static int drop_from_file(const char *fn, uint64_t keep) { lo = (unsigned) (after & 0xFFFFFFFFULL); hi = (unsigned) ((after >> 32ULL) & 0xFFFFFFFFULL); - if (asprintf(&p, "%u %u", lo, hi) < 0) - return -ENOMEM; - - r = write_string_file(fn, p, WRITE_STRING_FILE_CREATE); - free(p); - - return r; + return write_string_filef(fn, WRITE_STRING_FILE_CREATE, "%u %u", lo, hi); } int capability_bounding_set_drop_usermode(uint64_t keep) { @@ -314,8 +288,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) { if (prctl(PR_SET_KEEPCAPS, 1) < 0) return log_error_errno(errno, "Failed to enable keep capabilities flag: %m"); - r = setresuid(uid, uid, uid); - if (r < 0) + if (setresuid(uid, uid, uid) < 0) return log_error_errno(errno, "Failed to change user ID: %m"); if (prctl(PR_SET_KEEPCAPS, 0) < 0) diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h index fd9370ecb7..4a4a86093a 100644 --- a/src/basic/capability-util.h +++ b/src/basic/capability-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <stdint.h> #include <sys/capability.h> @@ -54,7 +35,7 @@ static inline void cap_free_charpp(char **p) { 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; + return FLAGS_SET(caps, m); } bool ambient_capabilities_supported(void); diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 9a4dd72270..038ece4b06 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <errno.h> @@ -434,7 +416,7 @@ int cg_migrate( * exist in the root cgroup, we only check for * them there. */ if (cfrom && - (isempty(pfrom) || path_equal(pfrom, "/")) && + empty_or_root(pfrom) && is_kernel_thread(pid) > 0) continue; @@ -641,7 +623,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch if (!t) return -ENOMEM; - *fs = path_kill_slashes(t); + *fs = path_simplify(t, false); return 0; } @@ -658,7 +640,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch if (r < 0) return r; - path_kill_slashes(*fs); + path_simplify(*fs, false); return 0; } @@ -767,6 +749,9 @@ int cg_trim(const char *controller, const char *path, bool delete_root) { return r; } +/* Create a cgroup in the hierarchy of controller. + * Returns 0 if the group already existed, 1 on success, negative otherwise. + */ int cg_create(const char *controller, const char *path) { _cleanup_free_ char *fs = NULL; int r; @@ -1198,7 +1183,7 @@ int cg_is_empty_recursive(const char *controller, const char *path) { assert(path); /* The root cgroup is always populated */ - if (controller && (isempty(path) || path_equal(path, "/"))) + if (controller && empty_or_root(path)) return false; r = cg_unified_controller(controller); @@ -1263,7 +1248,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) { if (!t) return -ENOMEM; - *path = path_kill_slashes(t); + *path = path_simplify(t, false); } if (controller) @@ -1315,7 +1300,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) { return -EINVAL; } - path_kill_slashes(u); + path_simplify(u, false); } if (controller) @@ -1346,7 +1331,7 @@ int cg_mangle_path(const char *path, char **result) { if (!t) return -ENOMEM; - *result = path_kill_slashes(t); + *result = path_simplify(t, false); return 0; } @@ -1424,10 +1409,9 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) { if (r < 0) return r; - if (c == raw) { - *cgroup = raw; - raw = NULL; - } else { + if (c == raw) + *cgroup = TAKE_PTR(raw); + else { char *n; n = strdup(c); @@ -1977,6 +1961,14 @@ int cg_slice_to_path(const char *unit, char **ret) { _cleanup_free_ char *escaped = NULL; char n[dash - p + sizeof(".slice")]; +#if HAS_FEATURE_MEMORY_SANITIZER + /* msan doesn't instrument stpncpy, so it thinks + * n is later used unitialized: + * https://github.com/google/sanitizers/issues/926 + */ + zero(n); +#endif + /* Don't allow trailing or double dashes */ if (IN_SET(dash[1], 0, '-')) return -EINVAL; @@ -2002,8 +1994,7 @@ int cg_slice_to_path(const char *unit, char **ret) { if (!strextend(&s, e, NULL)) return -ENOMEM; - *ret = s; - s = NULL; + *ret = TAKE_PTR(s); return 0; } @@ -2038,7 +2029,6 @@ int cg_get_keyed_attribute( char **ret_values) { _cleanup_free_ char *filename = NULL, *contents = NULL; - _cleanup_fclose_ FILE *f = NULL; const char *p; size_t n, i, n_done = 0; char **v; @@ -2112,23 +2102,29 @@ done: int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) { CGroupController c; + bool created; int r; /* This one will create a cgroup in our private tree, but also * duplicate it in the trees specified in mask, and remove it - * in all others */ + * in all others. + * + * Returns 0 if the group already existed in the systemd hierarchy, + * 1 on success, negative otherwise. + */ /* First create the cgroup in our own hierarchy. */ r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path); if (r < 0) return r; + created = !!r; /* If we are in the unified hierarchy, we are done now */ r = cg_all_unified(); if (r < 0) return r; if (r > 0) - return 0; + return created; /* Otherwise, do the same in the other hierarchies */ for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) { @@ -2143,7 +2139,7 @@ int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path (void) cg_trim(n, path, true); } - return 0; + return created; } int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) { @@ -2294,8 +2290,7 @@ int cg_mask_to_string(CGroupMask mask, char **ret) { assert(s); s[n] = 0; - *ret = s; - s = NULL; + *ret = TAKE_PTR(s); return 0; } @@ -2444,8 +2439,7 @@ int cg_kernel_controllers(Set **ret) { return r; } - *ret = controllers; - controllers = NULL; + *ret = TAKE_PTR(controllers); return 0; } @@ -2476,7 +2470,7 @@ static int cg_unified_update(void) { return 0; if (statfs("/sys/fs/cgroup/", &fs) < 0) - return log_debug_errno(errno, "statfs(\"/sys/fs/cgroup/\" failed: %m"); + return log_debug_errno(errno, "statfs(\"/sys/fs/cgroup/\") failed: %m"); if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) { log_debug("Found cgroup2 on /sys/fs/cgroup/, full unified hierarchy"); @@ -2599,8 +2593,10 @@ int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) { } r = write_string_stream(f, s, 0); - if (r < 0) + if (r < 0) { log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs); + clearerr(f); + } } } diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 068df102f7..1a28a8163a 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <stdbool.h> #include <stdint.h> diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c index 3635deee4e..4ec14515eb 100644 --- a/src/basic/chattr-util.c +++ b/src/basic/chattr-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h index a4ddaeeb8c..0c0816344a 100644 --- a/src/basic/chattr-util.h +++ b/src/basic/chattr-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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/>. -***/ - int chattr_fd(int fd, unsigned value, unsigned mask); int chattr_path(const char *p, unsigned value, unsigned mask); diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index e2499099b6..3ea016af0e 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index b90c31fb78..b9db54eac9 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 <time.h> int clock_is_localtime(const char* adjtime_path); diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index 8b4129e1cd..d6ef0e941e 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <errno.h> @@ -26,6 +8,7 @@ #include <string.h> #include "conf-files.h" +#include "def.h" #include "dirent-util.h" #include "fd-util.h" #include "hashmap.h" @@ -33,17 +16,28 @@ #include "macro.h" #include "missing.h" #include "path-util.h" +#include "set.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" +#include "terminal-util.h" #include "util.h" -static int files_add(Hashmap *h, const char *suffix, const char *root, unsigned flags, const char *path) { +static int files_add( + Hashmap *h, + Set *masked, + const char *suffix, + const char *root, + unsigned flags, + const char *path) { + _cleanup_closedir_ DIR *dir = NULL; const char *dirpath; struct dirent *de; int r; + assert(h); + assert((flags & CONF_FILES_FILTER_MASKED) == 0 || masked); assert(path); dirpath = prefix_roota(root, path); @@ -52,62 +46,89 @@ static int files_add(Hashmap *h, const char *suffix, const char *root, unsigned if (!dir) { if (errno == ENOENT) return 0; - return -errno; + + return log_debug_errno(errno, "Failed to open directory '%s': %m", dirpath); } FOREACH_DIRENT(de, dir, return -errno) { - char *p; + struct stat st; + char *p, *key; + + /* Does this match the suffix? */ + if (suffix && !endswith(de->d_name, suffix)) + continue; - if (!dirent_is_file_with_suffix(de, suffix)) { - log_debug("Ignoring %s/%s, because it's not a regular file with suffix %s.", dirpath, de->d_name, strna(suffix)); + /* Has this file already been found in an earlier directory? */ + if (hashmap_contains(h, de->d_name)) { + log_debug("Skipping overridden file '%s/%s'.", dirpath, de->d_name); continue; } - if (flags & CONF_FILES_EXECUTABLE) { - struct stat st; + /* Has this been masked in an earlier directory? */ + if ((flags & CONF_FILES_FILTER_MASKED) && set_contains(masked, de->d_name)) { + log_debug("File '%s/%s' is masked by previous entry.", dirpath, de->d_name); + continue; + } + + /* Read file metadata if we shall validate the check for file masks, for node types or whether the node is marked executable. */ + if (flags & (CONF_FILES_FILTER_MASKED|CONF_FILES_REGULAR|CONF_FILES_DIRECTORY|CONF_FILES_EXECUTABLE)) + if (fstatat(dirfd(dir), de->d_name, &st, 0) < 0) { + log_debug_errno(errno, "Failed to stat '%s/%s', ignoring: %m", dirpath, de->d_name); + continue; + } + + /* Is this a masking entry? */ + if ((flags & CONF_FILES_FILTER_MASKED)) + if (null_or_empty(&st)) { + /* Mark this one as masked */ + r = set_put_strdup(masked, de->d_name); + if (r < 0) + return r; + + log_debug("File '%s/%s' is a mask.", dirpath, de->d_name); + continue; + } + + /* Does this node have the right type? */ + if (flags & (CONF_FILES_REGULAR|CONF_FILES_DIRECTORY)) + if (!((flags & CONF_FILES_DIRECTORY) && S_ISDIR(st.st_mode)) && + !((flags & CONF_FILES_REGULAR) && S_ISREG(st.st_mode))) { + log_debug("Ignoring '%s/%s', as it is not a of the right type.", dirpath, de->d_name); + continue; + } + /* Does this node have the executable bit set? */ + if (flags & CONF_FILES_EXECUTABLE) /* As requested: check if the file is marked exectuable. Note that we don't check access(X_OK) * here, as we care about whether the file is marked executable at all, and not whether it is - * executable for us, because if such errors are stuff we should log about. */ + * executable for us, because if so, such errors are stuff we should log about. */ - if (fstatat(dirfd(dir), de->d_name, &st, 0) < 0) { - log_debug_errno(errno, "Failed to stat %s/%s, ignoring: %m", dirpath, de->d_name); + if ((st.st_mode & 0111) == 0) { /* not executable */ + log_debug("Ignoring '%s/%s', as it is not marked executable.", dirpath, de->d_name); continue; } - if (!null_or_empty(&st)) { - /* A mask is a symlink to /dev/null or an empty file. It does not even - * have to be executable. Other entries must be regular executable files - * or symlinks to them. */ - if (S_ISREG(st.st_mode)) { - if ((st.st_mode & 0111) == 0) { /* not executable */ - log_debug("Ignoring %s/%s, as it is not marked executable.", - dirpath, de->d_name); - continue; - } - } else { - log_debug("Ignoring %s/%s, as it is neither a regular file nor a mask.", - dirpath, de->d_name); - continue; - } - } - } + if (flags & CONF_FILES_BASENAME) { + p = strdup(de->d_name); + if (!p) + return -ENOMEM; - p = strjoin(dirpath, "/", de->d_name); - if (!p) - return -ENOMEM; + key = p; + } else { + p = strjoin(dirpath, "/", de->d_name); + if (!p) + return -ENOMEM; - r = hashmap_put(h, basename(p), p); - if (r == -EEXIST) { - log_debug("Skipping overridden file: %s.", p); - free(p); - } else if (r < 0) { - free(p); - return r; - } else if (r == 0) { - log_debug("Duplicate file %s", p); + key = basename(p); + } + + r = hashmap_put(h, key, p); + if (r < 0) { free(p); + return log_debug_errno(r, "Failed to add item to hashmap: %m"); } + + assert(r > 0); } return 0; @@ -123,6 +144,7 @@ static int base_cmp(const void *a, const void *b) { static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, unsigned flags, char **dirs) { _cleanup_hashmap_free_ Hashmap *fh = NULL; + _cleanup_set_free_free_ Set *masked = NULL; char **files, **p; int r; @@ -132,12 +154,18 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const if (!path_strv_resolve_uniq(dirs, root)) return -ENOMEM; - fh = hashmap_new(&string_hash_ops); + fh = hashmap_new(&path_hash_ops); if (!fh) return -ENOMEM; + if (flags & CONF_FILES_FILTER_MASKED) { + masked = set_new(&path_hash_ops); + if (!masked) + return -ENOMEM; + } + STRV_FOREACH(p, dirs) { - r = files_add(fh, suffix, root, flags, *p); + r = files_add(fh, masked, suffix, root, flags, *p); if (r == -ENOMEM) return r; if (r < 0) @@ -165,8 +193,8 @@ int conf_files_insert(char ***strv, const char *root, char **dirs, const char *p * - do nothing if our new entry matches the existing entry, * - replace the existing entry if our new entry has higher priority. */ + size_t i; char *t; - unsigned i; int r; for (i = 0; i < strv_length(*strv); i++) { @@ -269,3 +297,71 @@ int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, u return conf_files_list_strv_internal(strv, suffix, root, flags, d); } + +int conf_files_list_with_replacement( + const char *root, + char **config_dirs, + const char *replacement, + char ***files, + char **replace_file) { + + _cleanup_strv_free_ char **f = NULL; + _cleanup_free_ char *p = NULL; + int r; + + assert(config_dirs); + assert(files); + assert(replace_file || !replacement); + + r = conf_files_list_strv(&f, ".conf", root, 0, (const char* const*) config_dirs); + if (r < 0) + return log_error_errno(r, "Failed to enumerate config files: %m"); + + if (replacement) { + r = conf_files_insert(&f, root, config_dirs, replacement); + if (r < 0) + return log_error_errno(r, "Failed to extend config file list: %m"); + + p = path_join(root, replacement, NULL); + if (!p) + return log_oom(); + } + + *files = TAKE_PTR(f); + if (replace_file) + *replace_file = TAKE_PTR(p); + return 0; +} + +int conf_files_cat(const char *root, const char *name) { + _cleanup_strv_free_ char **dirs = NULL, **files = NULL; + _cleanup_free_ char *path = NULL; + const char *dir; + char **t; + int r; + + NULSTR_FOREACH(dir, CONF_PATHS_NULSTR("")) { + assert(endswith(dir, "/")); + r = strv_extendf(&dirs, "%s%s.d", dir, name); + if (r < 0) + return log_error_errno(r, "Failed to build directory list: %m"); + } + + r = conf_files_list_strv(&files, ".conf", root, 0, (const char* const*) dirs); + if (r < 0) + return log_error_errno(r, "Failed to query file list: %m"); + + path = path_join(root, "/etc", name); + if (!path) + return log_oom(); + + if (DEBUG_LOGGING) { + log_debug("Looking for configuration in:"); + log_debug(" %s", path); + STRV_FOREACH(t, dirs) + log_debug(" %s/*.conf", *t); + } + + /* show */ + return cat_files(path, files, CAT_FLAGS_MAIN_FILE_OPTIONAL); +} diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h index 5dc83578e4..9da03ed228 100644 --- a/src/basic/conf-files.h +++ b/src/basic/conf-files.h @@ -1,28 +1,13 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - Copyright 2010-2012 Kay Sievers - - 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/>. -***/ enum { - CONF_FILES_EXECUTABLE = 1, + CONF_FILES_EXECUTABLE = 1 << 0, + CONF_FILES_REGULAR = 1 << 1, + CONF_FILES_DIRECTORY = 1 << 2, + CONF_FILES_BASENAME = 1 << 3, + CONF_FILES_FILTER_MASKED = 1 << 4, }; int conf_files_list(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dir, ...); @@ -30,3 +15,10 @@ int conf_files_list_strv(char ***ret, const char *suffix, const char *root, unsi int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dirs); int conf_files_insert(char ***strv, const char *root, char **dirs, const char *path); int conf_files_insert_nulstr(char ***strv, const char *root, const char *dirs, const char *path); +int conf_files_list_with_replacement( + const char *root, + char **config_dirs, + const char *replacement, + char ***files, + char **replace_file); +int conf_files_cat(const char *root, const char *name); diff --git a/src/basic/copy.c b/src/basic/copy.c index a9e1a87622..e06a503a29 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <dirent.h> #include <errno.h> @@ -42,6 +24,7 @@ #include "io-util.h" #include "macro.h" #include "missing.h" +#include "mount-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -49,56 +32,149 @@ #include "user-util.h" #include "xattr-util.h" -#define COPY_BUFFER_SIZE (16*1024u) +#define COPY_BUFFER_SIZE (16U*1024U) + +/* A safety net for descending recursively into file system trees to copy. On Linux PATH_MAX is 4096, which means the + * deepest valid path one can build is around 2048, which we hence use as a safety net here, to not spin endlessly in + * case of bind mount cycles and suchlike. */ +#define COPY_DEPTH_MAX 2048U + +static ssize_t try_copy_file_range( + int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { -static ssize_t try_copy_file_range(int fd_in, loff_t *off_in, - int fd_out, loff_t *off_out, - size_t len, - unsigned int flags) { static int have = -1; ssize_t r; - if (have == false) + if (have == 0) return -ENOSYS; r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); - if (_unlikely_(have < 0)) + if (have < 0) have = r >= 0 || errno != ENOSYS; - if (r >= 0) - return r; - else + if (r < 0) return -errno; + + return r; } -int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) { +enum { + FD_IS_NO_PIPE, + FD_IS_BLOCKING_PIPE, + FD_IS_NONBLOCKING_PIPE, +}; + +static int fd_is_nonblock_pipe(int fd) { + struct stat st; + int flags; + + /* Checks whether the specified file descriptor refers to a pipe, and if so if O_NONBLOCK is set. */ + + if (fstat(fd, &st) < 0) + return -errno; + + if (!S_ISFIFO(st.st_mode)) + return FD_IS_NO_PIPE; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; + + return FLAGS_SET(flags, O_NONBLOCK) ? FD_IS_NONBLOCKING_PIPE : FD_IS_BLOCKING_PIPE; +} + +int copy_bytes_full( + int fdf, int fdt, + uint64_t max_bytes, + CopyFlags copy_flags, + void **ret_remains, + size_t *ret_remains_size) { + bool try_cfr = true, try_sendfile = true, try_splice = true; - int r; + int r, nonblock_pipe = -1; size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */ assert(fdf >= 0); assert(fdt >= 0); - /* Try btrfs reflinks first. */ - if ((copy_flags & COPY_REFLINK) && - max_bytes == (uint64_t) -1 && - lseek(fdf, 0, SEEK_CUR) == 0 && - lseek(fdt, 0, SEEK_CUR) == 0) { + /* Tries to copy bytes from the file descriptor 'fdf' to 'fdt' in the smartest possible way. Copies a maximum + * of 'max_bytes', which may be specified as UINT64_MAX, in which no maximum is applied. Returns negative on + * error, zero if EOF is hit before the bytes limit is hit and positive otherwise. If the copy fails for some + * reason but we read but didn't yet write some data an ret_remains/ret_remains_size is not NULL, then it will + * be initialized with an allocated buffer containing this "remaining" data. Note that these two parameters are + * initialized with a valid buffer only on failure and only if there's actually data already read. Otherwise + * these parameters if non-NULL are set to NULL. */ + + if (ret_remains) + *ret_remains = NULL; + if (ret_remains_size) + *ret_remains_size = 0; + + /* Try btrfs reflinks first. This only works on regular, seekable files, hence let's check the file offsets of + * source and destination first. */ + if ((copy_flags & COPY_REFLINK)) { + off_t foffset; + + foffset = lseek(fdf, 0, SEEK_CUR); + if (foffset >= 0) { + off_t toffset; + + toffset = lseek(fdt, 0, SEEK_CUR); + if (toffset >= 0) { + + if (foffset == 0 && toffset == 0 && max_bytes == UINT64_MAX) + r = btrfs_reflink(fdf, fdt); /* full file reflink */ + else + r = btrfs_clone_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes); /* partial reflink */ + if (r >= 0) { + off_t t; + + /* This worked, yay! Now — to be fully correct — let's adjust the file pointers */ + if (max_bytes == UINT64_MAX) { + + /* We cloned to the end of the source file, let's position the read + * pointer there, and query it at the same time. */ + t = lseek(fdf, 0, SEEK_END); + if (t < 0) + return -errno; + if (t < foffset) + return -ESPIPE; + + /* Let's adjust the destination file write pointer by the same number + * of bytes. */ + t = lseek(fdt, toffset + (t - foffset), SEEK_SET); + if (t < 0) + return -errno; + + return 0; /* we copied the whole thing, hence hit EOF, return 0 */ + } else { + t = lseek(fdf, foffset + max_bytes, SEEK_SET); + if (t < 0) + return -errno; + + t = lseek(fdt, toffset + max_bytes, SEEK_SET); + if (t < 0) + return -errno; + + return 1; /* we copied only some number of bytes, which worked, but this means we didn't hit EOF, return 1 */ + } + } - r = btrfs_reflink(fdf, fdt); - if (r >= 0) - return 0; /* we copied the whole thing, hence hit EOF, return 0 */ + log_debug_errno(r, "Reflinking didn't work, falling back to non-reflink copying: %m"); + } + } } for (;;) { ssize_t n; - if (max_bytes != (uint64_t) -1) { - if (max_bytes <= 0) - return 1; /* return > 0 if we hit the max_bytes limit */ + if (max_bytes <= 0) + return 1; /* return > 0 if we hit the max_bytes limit */ - if (m > max_bytes) - m = max_bytes; - } + if (max_bytes != UINT64_MAX && m > max_bytes) + m = max_bytes; /* First try copy_file_range(), unless we already tried */ if (try_cfr) { @@ -132,9 +208,51 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) { goto next; } - /* Then try splice, unless we already tried */ + /* Then try splice, unless we already tried. */ + if (try_splice) { + + /* splice()'s asynchronous I/O support is a bit weird. When it encounters a pipe file + * descriptor, then it will ignore its O_NONBLOCK flag and instead only honour the + * SPLICE_F_NONBLOCK flag specified in its flag parameter. Let's hide this behaviour here, and + * check if either of the specified fds are a pipe, and if so, let's pass the flag + * automatically, depending on O_NONBLOCK being set. + * + * Here's a twist though: when we use it to move data between two pipes of which one has + * O_NONBLOCK set and the other has not, then we have no individual control over O_NONBLOCK + * behaviour. Hence in that case we can't use splice() and still guarantee systematic + * O_NONBLOCK behaviour, hence don't. */ + + if (nonblock_pipe < 0) { + int a, b; + + /* Check if either of these fds is a pipe, and if so non-blocking or not */ + a = fd_is_nonblock_pipe(fdf); + if (a < 0) + return a; + + b = fd_is_nonblock_pipe(fdt); + if (b < 0) + return b; + + if ((a == FD_IS_NO_PIPE && b == FD_IS_NO_PIPE) || + (a == FD_IS_BLOCKING_PIPE && b == FD_IS_NONBLOCKING_PIPE) || + (a == FD_IS_NONBLOCKING_PIPE && b == FD_IS_BLOCKING_PIPE)) + + /* splice() only works if one of the fds is a pipe. If neither is, let's skip + * this step right-away. As mentioned above, if one of the two fds refers to a + * blocking pipe and the other to a non-blocking pipe, we can't use splice() + * either, hence don't try either. This hence means we can only use splice() if + * either only one of the two fds is a pipe, or if both are pipes with the same + * nonblocking flag setting. */ + + try_splice = false; + else + nonblock_pipe = a == FD_IS_NONBLOCKING_PIPE || b == FD_IS_NONBLOCKING_PIPE; + } + } + if (try_splice) { - n = splice(fdf, NULL, fdt, NULL, m, 0); + n = splice(fdf, NULL, fdt, NULL, m, nonblock_pipe ? SPLICE_F_NONBLOCK : 0); if (n < 0) { if (!IN_SET(errno, EINVAL, ENOSYS)) return -errno; @@ -150,7 +268,8 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) { /* As a fallback just copy bits by hand */ { - uint8_t buf[MIN(m, COPY_BUFFER_SIZE)]; + uint8_t buf[MIN(m, COPY_BUFFER_SIZE)], *p = buf; + ssize_t z; n = read(fdf, buf, sizeof buf); if (n < 0) @@ -158,9 +277,34 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) { if (n == 0) /* EOF */ break; - r = loop_write(fdt, buf, (size_t) n, false); - if (r < 0) - return r; + z = (size_t) n; + do { + ssize_t k; + + k = write(fdt, p, z); + if (k < 0) { + r = -errno; + + if (ret_remains) { + void *copy; + + copy = memdup(p, z); + if (!copy) + return -ENOMEM; + + *ret_remains = copy; + } + + if (ret_remains_size) + *ret_remains_size = z; + + return r; + } + + assert(k <= z); + z -= k; + p += k; + } while (z > 0); } next: @@ -336,6 +480,7 @@ static int fd_copy_directory( int dt, const char *to, dev_t original_device, + unsigned depth_left, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { @@ -349,6 +494,9 @@ static int fd_copy_directory( assert(st); assert(to); + if (depth_left == 0) + return -ENAMETOOLONG; + if (from) fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); else @@ -387,13 +535,40 @@ static int fd_copy_directory( continue; } - if (buf.st_dev != original_device) - continue; + if (S_ISDIR(buf.st_mode)) { + /* + * Don't descend into directories on other file systems, if this is requested. We do a simple + * .st_dev check here, which basically comes for free. Note that we do this check only on + * directories, not other kind of file system objects, for two reason: + * + * • The kernel's overlayfs pseudo file system that overlays multiple real file systems + * propagates the .st_dev field of the file system a file originates from all the way up + * through the stack to stat(). It doesn't do that for directories however. This means that + * comparing .st_dev on non-directories suggests that they all are mount points. To avoid + * confusion we hence avoid relying on this check for regular files. + * + * • The main reason we do this check at all is to protect ourselves from bind mount cycles, + * where we really want to avoid descending down in all eternity. However the .st_dev check + * is usually not sufficient for this protection anyway, as bind mount cycles from the same + * file system onto itself can't be detected that way. (Note we also do a recursion depth + * check, which is probably the better protection in this regard, which is why + * COPY_SAME_MOUNT is optional). + */ + + if (FLAGS_SET(copy_flags, COPY_SAME_MOUNT)) { + if (buf.st_dev != original_device) + continue; + + r = fd_is_mount_point(dirfd(d), de->d_name, 0); + if (r < 0) + return r; + if (r > 0) + continue; + } - if (S_ISREG(buf.st_mode)) + q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags); + } else if (S_ISREG(buf.st_mode)) q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); - else if (S_ISDIR(buf.st_mode)) - q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags); else if (S_ISLNK(buf.st_mode)) q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); else if (S_ISFIFO(buf.st_mode)) @@ -443,7 +618,7 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t overr if (S_ISREG(st.st_mode)) return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); else if (S_ISDIR(st.st_mode)) - return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, override_uid, override_gid, copy_flags); + return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags); else if (S_ISLNK(st.st_mode)) return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); else if (S_ISFIFO(st.st_mode)) @@ -470,7 +645,7 @@ int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) { if (!S_ISDIR(st.st_mode)) return -ENOTDIR; - return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags); + return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags); } int copy_directory(const char *from, const char *to, CopyFlags copy_flags) { @@ -485,7 +660,7 @@ int copy_directory(const char *from, const char *to, CopyFlags copy_flags) { if (!S_ISDIR(st.st_mode)) return -ENOTDIR; - return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, UID_INVALID, GID_INVALID, copy_flags); + return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags); } int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) { @@ -538,31 +713,55 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned } int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) { - _cleanup_free_ char *t = NULL; + _cleanup_(unlink_and_freep) char *t = NULL; + _cleanup_close_ int fdt = -1; int r; assert(from); assert(to); - r = tempfn_random(to, NULL, &t); - if (r < 0) - return r; + /* We try to use O_TMPFILE here to create the file if we can. Note that that only works if COPY_REPLACE is not + * set though as we need to use linkat() for linking the O_TMPFILE file into the file system but that system + * call can't replace existing files. Hence, if COPY_REPLACE is set we create a temporary name in the file + * system right-away and unconditionally which we then can renameat() to the right name after we completed + * writing it. */ + + if (copy_flags & COPY_REPLACE) { + r = tempfn_random(to, NULL, &t); + if (r < 0) + return r; - r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags); + fdt = open(t, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600); + if (fdt < 0) { + t = mfree(t); + return -errno; + } + } else { + fdt = open_tmpfile_linkable(to, O_WRONLY|O_CLOEXEC, &t); + if (fdt < 0) + return fdt; + } + + if (chattr_flags != 0) + (void) chattr_fd(fdt, chattr_flags, (unsigned) -1); + + r = copy_file_fd(from, fdt, copy_flags); if (r < 0) return r; + if (fchmod(fdt, mode) < 0) + return -errno; + if (copy_flags & COPY_REPLACE) { - r = renameat(AT_FDCWD, t, AT_FDCWD, to); + if (renameat(AT_FDCWD, t, AT_FDCWD, to) < 0) + return -errno; + } else { + r = link_tmpfile(fdt, t, to); if (r < 0) - r = -errno; - } else - r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to); - if (r < 0) { - (void) unlink(t); - return r; + return r; } + t = mfree(t); return 0; } diff --git a/src/basic/copy.h b/src/basic/copy.h index 59da4c2425..6a0a6bc9b3 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -1,34 +1,16 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <inttypes.h> #include <stdbool.h> #include <stdint.h> #include <sys/types.h> typedef enum CopyFlags { - COPY_REFLINK = 0x1, /* try to reflink */ - COPY_MERGE = 0x2, /* merge existing trees with our new one to copy */ - COPY_REPLACE = 0x4, /* replace an existing file if there's one */ + COPY_REFLINK = 1 << 0, /* Try to reflink */ + COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */ + COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */ + COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */ } CopyFlags; int copy_file_fd(const char *from, int to, CopyFlags copy_flags); @@ -38,6 +20,9 @@ int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t overri int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags); int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags); int copy_directory(const char *from, const char *to, CopyFlags copy_flags); -int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags); +int copy_bytes_full(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags, void **ret_remains, size_t *ret_remains_size); +static inline int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) { + return copy_bytes_full(fdf, fdt, max_bytes, copy_flags, NULL, NULL); +} int copy_times(int fdf, int fdt); int copy_xattr(int fdf, int fdt); diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c index 9f0a61a18e..b1c927bcb8 100644 --- a/src/basic/cpu-set-util.c +++ b/src/basic/cpu-set-util.c @@ -1,22 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2010-2015 Lennart Poettering - Copyright 2015 Filipe Brandenburger - - 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/>. + Copyright © 2015 Filipe Brandenburger ***/ #include <errno.h> @@ -111,10 +95,8 @@ int parse_cpu_set_internal( } /* On success, sets *cpu_set and returns ncpus for the system. */ - if (c) { - *cpu_set = c; - c = NULL; - } + if (c) + *cpu_set = TAKE_PTR(c); return (int) ncpus; } diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h index c98149eaeb..88470fe15a 100644 --- a/src/basic/cpu-set-util.h +++ b/src/basic/cpu-set-util.h @@ -2,23 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2010-2015 Lennart Poettering - Copyright 2015 Filipe Brandenburger - - 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/>. + Copyright © 2015 Filipe Brandenburger ***/ #include <sched.h> diff --git a/src/basic/crypt-util.c b/src/basic/crypt-util.c index 193cf65dfc..b181ba3ba0 100644 --- a/src/basic/crypt-util.c +++ b/src/basic/crypt-util.c @@ -1,21 +1,4 @@ -/*** - This file is part of systemd. - - Copyright 2017 Zbigniew Jędrzejewski-Szmek - - 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/>. -***/ +/* SPDX-License-Identifier: LGPL-2.1+ */ #if HAVE_LIBCRYPTSETUP #include "crypt-util.h" diff --git a/src/basic/crypt-util.h b/src/basic/crypt-util.h index 537f785607..5b03cb072d 100644 --- a/src/basic/crypt-util.h +++ b/src/basic/crypt-util.h @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2017 Zbigniew Jędrzejewski-Szmek - - 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/>. -***/ #if HAVE_LIBCRYPTSETUP #include <libcryptsetup.h> diff --git a/src/basic/def.h b/src/basic/def.h index 43e7e17008..4d515c11b6 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 "util.h" #define DEFAULT_TIMEOUT_USEC (90*USEC_PER_SEC) @@ -67,8 +48,10 @@ #define NOTIFY_BUFFER_MAX PIPE_BUF #if HAVE_SPLIT_USR -# define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0" +# define _CONF_PATHS_SPLIT_USR_NULSTR(n) "/lib/" n "\0" +# define _CONF_PATHS_SPLIT_USR(n) , "/lib/" n #else +# define _CONF_PATHS_SPLIT_USR_NULSTR(n) # define _CONF_PATHS_SPLIT_USR(n) #endif @@ -81,6 +64,14 @@ "/run/" n "\0" \ "/usr/local/lib/" n "\0" \ "/usr/lib/" n "\0" \ - _CONF_PATHS_SPLIT_USR(n) + _CONF_PATHS_SPLIT_USR_NULSTR(n) + +#define CONF_PATHS_STRV(n) \ + STRV_MAKE( \ + "/etc/" n, \ + "/run/" n, \ + "/usr/local/lib/" n, \ + "/usr/lib/" n \ + _CONF_PATHS_SPLIT_USR(n)) #define LONG_LINE_MAX (1U*1024U*1024U) diff --git a/src/basic/device-nodes.c b/src/basic/device-nodes.c index 61dc49238c..5fcdf24bd2 100644 --- a/src/basic/device-nodes.c +++ b/src/basic/device-nodes.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2008-2011 Kay Sievers - - 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 <errno.h> #include <stdio.h> diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h index 49f4ccc729..3840e6d307 100644 --- a/src/basic/device-nodes.h +++ b/src/basic/device-nodes.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - 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 <stddef.h> #include <sys/types.h> diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index e2b093bad3..d1d2c0ef46 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 <fcntl.h> #include <sys/stat.h> diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h index 94d5ee81a3..b1b87679dc 100644 --- a/src/basic/dirent-util.h +++ b/src/basic/dirent-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <errno.h> #include <stdbool.h> diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 0b1d086394..a784a30e1d 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - 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 <errno.h> #include <limits.h> @@ -84,9 +66,9 @@ bool env_value_is_valid(const char *e) { if (!utf8_is_valid(e)) return false; - /* bash allows tabs in environment variables, and so should - * we */ - if (string_has_cc(e, "\t")) + /* bash allows tabs and newlines in environment variables, and so + * should we */ + if (string_has_cc(e, "\t\n")) return false; /* POSIX says the overall size of the environment block cannot @@ -209,11 +191,11 @@ static int env_append(char **r, char ***k, char **a) { return 0; } -char **strv_env_merge(unsigned n_lists, ...) { +char **strv_env_merge(size_t n_lists, ...) { size_t n = 0; char **l, **k, **r; va_list ap; - unsigned i; + size_t i; /* Merges an arbitrary number of environment sets */ @@ -288,7 +270,7 @@ static bool env_entry_has_name(const char *entry, const char *name) { return *t == '='; } -char **strv_env_delete(char **x, unsigned n_lists, ...) { +char **strv_env_delete(char **x, size_t n_lists, ...) { size_t n, i = 0; char **k, **r; va_list ap; @@ -303,7 +285,7 @@ char **strv_env_delete(char **x, unsigned n_lists, ...) { return NULL; STRV_FOREACH(k, x) { - unsigned v; + size_t v; va_start(ap, n_lists); for (v = 0; v < n_lists; v++) { @@ -430,7 +412,8 @@ int strv_env_replace(char ***l, char *p) { char **strv_env_set(char **x, const char *p) { - char **k, **r; + char **k; + _cleanup_strv_free_ char **r = NULL; char* m[2] = { (char*) p, NULL }; /* Overrides the env var setting of p, returns a new copy */ @@ -441,18 +424,14 @@ char **strv_env_set(char **x, const char *p) { k = r; if (env_append(r, &k, x) < 0) - goto fail; + return NULL; if (env_append(r, &k, m) < 0) - goto fail; + return NULL; *k = NULL; - return r; - -fail: - strv_free(r); - return NULL; + return TAKE_PTR(r); } char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) { @@ -689,7 +668,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { char **replace_env_argv(char **argv, char **env) { char **ret, **i; - unsigned k = 0, l = 0; + size_t k = 0, l = 0; l = strv_length(argv); @@ -703,7 +682,7 @@ char **replace_env_argv(char **argv, char **env) { if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) { char *e; char **w, **m = NULL; - unsigned q; + size_t q; e = strv_env_get(env, *i+1); if (e) { diff --git a/src/basic/env-util.h b/src/basic/env-util.h index 956a2a8270..ef9398e618 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <stdbool.h> #include <stddef.h> #include <stdio.h> @@ -50,8 +31,8 @@ char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const cha bool strv_env_name_is_valid(char **l); bool strv_env_name_or_assignment_is_valid(char **l); -char **strv_env_merge(unsigned n_lists, ...); -char **strv_env_delete(char **x, unsigned n_lists, ...); /* New copy */ +char **strv_env_merge(size_t n_lists, ...); +char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */ char **strv_env_set(char **x, const char *p); /* New copy ... */ char **strv_env_unset(char **l, const char *p); /* In place ... */ diff --git a/src/basic/errno-list.c b/src/basic/errno-list.c index 7eb28b8fd1..1b72bbf3ad 100644 --- a/src/basic/errno-list.c +++ b/src/basic/errno-list.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <errno.h> #include <string.h> diff --git a/src/basic/errno-list.h b/src/basic/errno-list.h index 38beaf96dd..9c639b4f55 100644 --- a/src/basic/errno-list.h +++ b/src/basic/errno-list.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <stdbool.h> /* * MAX_ERRNO is defined as 4095 in linux/err.h diff --git a/src/basic/escape.c b/src/basic/escape.c index 7d77aef329..5004763d97 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <stdlib.h> @@ -28,8 +10,10 @@ #include "macro.h" #include "utf8.h" -size_t cescape_char(char c, char *buf) { - char * buf_old = buf; +int cescape_char(char c, char *buf) { + char *buf_old = buf; + + /* Needs space for 4 characters in the buffer */ switch (c) { @@ -201,7 +185,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) /* C++11 style 16bit unicode */ int a[4]; - unsigned i; + size_t i; uint32_t c; if (length != (size_t) -1 && length < 5) @@ -228,7 +212,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) /* C++11 style 32bit unicode */ int a[8]; - unsigned i; + size_t i; char32_t c; if (length != (size_t) -1 && length < 9) diff --git a/src/basic/escape.h b/src/basic/escape.h index de89f43a82..2e07c73b9e 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <inttypes.h> #include <stddef.h> #include <stdint.h> @@ -58,7 +39,7 @@ typedef enum EscapeStyle { char *cescape(const char *s); char *cescape_length(const char *s, size_t n); -size_t cescape_char(char c, char *buf); +int 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); diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index bfbd1a4931..461ace73e2 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen - - 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 <errno.h> #include <net/ethernet.h> @@ -46,19 +28,23 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR return buffer; } -bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) { +int ether_addr_compare(const void *a, const void *b) { assert(a); assert(b); - return a->ether_addr_octet[0] == b->ether_addr_octet[0] && - a->ether_addr_octet[1] == b->ether_addr_octet[1] && - a->ether_addr_octet[2] == b->ether_addr_octet[2] && - a->ether_addr_octet[3] == b->ether_addr_octet[3] && - a->ether_addr_octet[4] == b->ether_addr_octet[4] && - a->ether_addr_octet[5] == b->ether_addr_octet[5]; + return memcmp(a, b, ETH_ALEN); } -int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset) { +static void ether_addr_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(struct ether_addr), state); +} + +const struct hash_ops ether_addr_hash_ops = { + .hash = ether_addr_hash_func, + .compare = ether_addr_compare +}; + +int ether_addr_from_string(const char *s, struct ether_addr *ret) { size_t pos = 0, n, field; char sep = '\0'; const char *hex = HEXDIGITS, *hexoff; @@ -97,31 +83,35 @@ int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset assert(s); assert(ret); + s += strspn(s, WHITESPACE); sep = s[strspn(s, hex)]; - if (sep == '\n') - return -EINVAL; - if (!strchr(":.-", sep)) - return -EINVAL; if (sep == '.') { uint16_t shorts[3] = { 0 }; parse_fields(shorts); + if (s[pos] != '\0') + return -EINVAL; + for (n = 0; n < ELEMENTSOF(shorts); n++) { ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8); ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff); } - } else { - struct ether_addr out = { .ether_addr_octet = { 0 } }; + + } else if (IN_SET(sep, ':', '-')) { + struct ether_addr out = ETHER_ADDR_NULL; parse_fields(out.ether_addr_octet); + if (s[pos] != '\0') + return -EINVAL; + for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++) ret->ether_addr_octet[n] = out.ether_addr_octet[n]; - } - if (offset) - *offset = pos; + } else + return -EINVAL; + return 0; } diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 08d05a136f..f12f1215d2 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -1,35 +1,22 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen - - 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 <net/ethernet.h> #include <stdbool.h> +#include "hash-funcs.h" + #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X" #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] #define ETHER_ADDR_TO_STRING_MAX (3*6) char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); -bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b); +int ether_addr_compare(const void *a, const void *b); +static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) { + return ether_addr_compare(a, b) == 0; +} #define ETHER_ADDR_NULL ((const struct ether_addr){}) @@ -37,4 +24,6 @@ static inline bool ether_addr_is_null(const struct ether_addr *addr) { return ether_addr_equal(addr, ÐER_ADDR_NULL); } -int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset); +int ether_addr_from_string(const char *s, struct ether_addr *ret); + +extern const struct hash_ops ether_addr_hash_ops; diff --git a/src/basic/exec-util.c b/src/basic/exec-util.c index e0057a7572..7e336f9ce1 100644 --- a/src/basic/exec-util.c +++ b/src/basic/exec-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <errno.h> @@ -102,7 +84,7 @@ static int do_execute( * If callbacks is nonnull, execution is serial. Otherwise, we default to parallel. */ - r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE, (const char* const*) directories); + r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char* const*) directories); if (r < 0) return r; @@ -116,7 +98,7 @@ static int do_execute( * default action terminating the process, and turn on alarm(). */ if (timeout != USEC_INFINITY) - alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC); + alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC)); STRV_FOREACH(path, paths) { _cleanup_free_ char *t = NULL; diff --git a/src/basic/exec-util.h b/src/basic/exec-util.h index d69bec7bc2..8b1f18139c 100644 --- a/src/basic/exec-util.h +++ b/src/basic/exec-util.h @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2017 Zbigniew Jędrzejewski-Szmek - - 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 <stdbool.h> diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c index c02681d4cc..21af8c4c71 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -1,25 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <signal.h> #include <stdlib.h> +#include <sysexits.h> #include "exit-status.h" #include "macro.h" @@ -27,10 +10,21 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) { - /* We cast to int here, so that -Wenum doesn't complain that - * EXIT_SUCCESS/EXIT_FAILURE aren't in the enum */ - - switch (status) { + /* Exit status ranges: + * + * 0…1 │ ISO C, EXIT_SUCCESS + EXIT_FAILURE + * 2…7 │ LSB exit codes for init scripts + * 8…63 │ (Currently unmapped) + * 64…78 │ BSD defined exit codes + * 79…199 │ (Currently unmapped) + * 200…241 │ systemd's private error codes (might be extended to 254 in future development) + * 242…254 │ (Currently unmapped, but see above) + * 255 │ (We should probably stay away from that one, it's frequently used by applications to indicate an + * │ exit reason that cannot really be expressed in a single exit status value — such as a propagated + * │ signal or such) + */ + + switch (status) { /* We always cover the ISO C ones */ case EXIT_SUCCESS: return "SUCCESS"; @@ -39,8 +33,8 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) { return "FAILURE"; } - if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB)) { - switch (status) { + if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) { + switch (status) { /* Optionally we cover our own ones */ case EXIT_CHDIR: return "CHDIR"; @@ -164,8 +158,8 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) { } } - if (level == EXIT_STATUS_LSB) { - switch (status) { + if (IN_SET(level, EXIT_STATUS_LSB, EXIT_STATUS_FULL)) { + switch (status) { /* Optionally we support LSB ones */ case EXIT_INVALIDARGUMENT: return "INVALIDARGUMENT"; @@ -187,6 +181,56 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) { } } + if (level == EXIT_STATUS_FULL) { + switch (status) { /* Optionally, we support BSD exit statusses */ + + case EX_USAGE: + return "USAGE"; + + case EX_DATAERR: + return "DATAERR"; + + case EX_NOINPUT: + return "NOINPUT"; + + case EX_NOUSER: + return "NOUSER"; + + case EX_NOHOST: + return "NOHOST"; + + case EX_UNAVAILABLE: + return "UNAVAILABLE"; + + case EX_SOFTWARE: + return "SOFTWARE"; + + case EX_OSERR: + return "OSERR"; + + case EX_OSFILE: + return "OSFILE"; + + case EX_CANTCREAT: + return "CANTCREAT"; + + case EX_IOERR: + return "IOERR"; + + case EX_TEMPFAIL: + return "TEMPFAIL"; + + case EX_PROTOCOL: + return "PROTOCOL"; + + case EX_NOPERM: + return "NOPERM"; + + case EX_CONFIG: + return "CONFIG"; + } + } + return NULL; } @@ -195,7 +239,7 @@ bool is_clean_exit(int code, int status, ExitClean clean, ExitStatusSet *success if (code == CLD_EXITED) return status == 0 || (success_status && - set_contains(success_status->status, INT_TO_PTR(status))); + set_contains(success_status->status, INT_TO_PTR(status))); /* If a daemon does not implement handlers for some of the signals that's not considered an unclean shutdown */ if (code == CLD_KILLED) diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h index 1e10419f8b..c41e8b82c3 100644 --- a/src/basic/exit-status.h +++ b/src/basic/exit-status.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include "hashmap.h" @@ -42,10 +23,10 @@ enum { EXIT_NOTCONFIGURED = 6, EXIT_NOTRUNNING = 7, - /* The LSB suggests that error codes >= 200 are "reserved". We - * use them here under the assumption that they hence are - * unused by init scripts. */ + /* BSD's sysexits.h defines a couple EX_xyz exit codes in the range 64 … 78 */ + /* The LSB suggests that error codes >= 200 are "reserved". We use them here under the assumption that they + * hence are unused by init scripts. */ EXIT_CHDIR = 200, EXIT_NICE, EXIT_FDS, @@ -94,7 +75,7 @@ typedef enum ExitStatusLevel { EXIT_STATUS_MINIMAL, /* only cover libc EXIT_STATUS/EXIT_FAILURE */ EXIT_STATUS_SYSTEMD, /* cover libc and systemd's own exit codes */ EXIT_STATUS_LSB, /* cover libc, systemd's own and LSB exit codes */ - EXIT_STATUS_FULL = EXIT_STATUS_LSB + EXIT_STATUS_FULL, /* cover libc, systemd's own, LSB and BSD (EX_xyz) exit codes */ } ExitStatusLevel; typedef struct ExitStatusSet { diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 5e42560487..a861b56653 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <stdarg.h> @@ -194,8 +176,7 @@ finish: finish_force_next: s[sz] = 0; - *ret = s; - s = NULL; + *ret = TAKE_PTR(s); return 1; } diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h index 300c51bb77..8c63b7c306 100644 --- a/src/basic/extract-word.h +++ b/src/basic/extract-word.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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" typedef enum ExtractFlags { diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 678ab12bb8..e085dc23b4 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> @@ -25,10 +7,13 @@ #include <sys/stat.h> #include <unistd.h> +#include "alloc-util.h" +#include "copy.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "io-util.h" #include "macro.h" #include "memfd-util.h" #include "missing.h" @@ -98,8 +83,8 @@ void safe_close_pair(int p[]) { p[1] = safe_close(p[1]); } -void close_many(const int fds[], unsigned n_fd) { - unsigned i; +void close_many(const int fds[], size_t n_fd) { + size_t i; assert(fds || n_fd <= 0); @@ -191,8 +176,8 @@ int fd_cloexec(int fd, bool cloexec) { return 0; } -_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { - unsigned i; +_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) { + size_t i; assert(n_fdset == 0 || fdset); @@ -203,7 +188,7 @@ _pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { return false; } -int close_all_fds(const int except[], unsigned n_except) { +int close_all_fds(const int except[], size_t n_except) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; int r = 0; @@ -212,15 +197,22 @@ int close_all_fds(const int except[], unsigned n_except) { d = opendir("/proc/self/fd"); if (!d) { - int fd; struct rlimit rl; + int fd, max_fd; - /* When /proc isn't available (for example in chroots) - * the fallback is brute forcing through the fd + /* When /proc isn't available (for example in chroots) the fallback is brute forcing through the fd * table */ assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); - for (fd = 3; fd < (int) rl.rlim_max; fd ++) { + + if (rl.rlim_max == 0) + return -EINVAL; + + /* Let's take special care if the resource limit is set to unlimited, or actually larger than the range + * of 'int'. Let's avoid implicit overflows. */ + max_fd = (rl.rlim_max == RLIM_INFINITY || rl.rlim_max > INT_MAX) ? INT_MAX : (int) (rl.rlim_max - 1); + + for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) { int q; if (fd_in_set(fd, except, n_except)) @@ -361,14 +353,21 @@ bool fdname_is_valid(const char *s) { } int fd_get_path(int fd, char **ret) { - char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_ int dir = -1; + char fdname[DECIMAL_STR_MAX(int)]; int r; - xsprintf(procfs_path, "/proc/self/fd/%i", fd); + dir = open("/proc/self/fd/", O_CLOEXEC | O_DIRECTORY | O_PATH); + if (dir < 0) + /* /proc is not available or not set up properly, we're most likely + * in some chroot environment. */ + return errno == ENOENT ? -EOPNOTSUPP : -errno; - r = readlink_malloc(procfs_path, ret); + xsprintf(fdname, "%i", fd); - if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */ + r = readlinkat_malloc(dir, fdname, ret); + if (r == -ENOENT) + /* If the file doesn't exist the fd is invalid */ return -EBADF; return r; @@ -420,7 +419,6 @@ int move_fd(int from, int to, int cloexec) { int acquire_data_fd(const void *data, size_t size, unsigned flags) { - char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; _cleanup_close_pair_ int pipefds[2] = { -1, -1 }; char pattern[] = "/dev/shm/data-fd-XXXXXX"; _cleanup_close_ int fd = -1; @@ -477,10 +475,7 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags) { if (r < 0) return r; - r = fd; - fd = -1; - - return r; + return TAKE_FD(fd); } try_pipe: @@ -517,10 +512,7 @@ try_pipe: (void) fd_nonblock(pipefds[0], false); - r = pipefds[0]; - pipefds[0] = -1; - - return r; + return TAKE_FD(pipefds[0]); } try_dev_shm: @@ -536,12 +528,7 @@ try_dev_shm: return -EIO; /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */ - xsprintf(procfs_path, "/proc/self/fd/%i", fd); - r = open(procfs_path, O_RDONLY|O_CLOEXEC); - if (r < 0) - return -errno; - - return r; + return fd_reopen(fd, O_RDONLY|O_CLOEXEC); } try_dev_shm_without_o_tmpfile: @@ -573,6 +560,201 @@ try_dev_shm_without_o_tmpfile: return -EOPNOTSUPP; } +/* When the data is smaller or equal to 64K, try to place the copy in a memfd/pipe */ +#define DATA_FD_MEMORY_LIMIT (64U*1024U) + +/* If memfd/pipe didn't work out, then let's use a file in /tmp up to a size of 1M. If it's large than that use /var/tmp instead. */ +#define DATA_FD_TMP_LIMIT (1024U*1024U) + +int fd_duplicate_data_fd(int fd) { + + _cleanup_close_ int copy_fd = -1, tmp_fd = -1; + _cleanup_free_ void *remains = NULL; + size_t remains_size = 0; + const char *td; + struct stat st; + int r; + + /* Creates a 'data' fd from the specified source fd, containing all the same data in a read-only fashion, but + * independent of it (i.e. the source fd can be closed and unmounted after this call succeeded). Tries to be + * somewhat smart about where to place the data. In the best case uses a memfd(). If memfd() are not supported + * uses a pipe instead. For larger data will use an unlinked file in /tmp, and for even larger data one in + * /var/tmp. */ + + if (fstat(fd, &st) < 0) + return -errno; + + /* For now, let's only accept regular files, sockets, pipes and char devices */ + if (S_ISDIR(st.st_mode)) + return -EISDIR; + if (S_ISLNK(st.st_mode)) + return -ELOOP; + if (!S_ISREG(st.st_mode) && !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode) && !S_ISCHR(st.st_mode)) + return -EBADFD; + + /* If we have reason to believe the data is bounded in size, then let's use memfds or pipes as backing fd. Note + * that we use the reported regular file size only as a hint, given that there are plenty special files in + * /proc and /sys which report a zero file size but can be read from. */ + + if (!S_ISREG(st.st_mode) || st.st_size < DATA_FD_MEMORY_LIMIT) { + + /* Try a memfd first */ + copy_fd = memfd_new("data-fd"); + if (copy_fd >= 0) { + off_t f; + + r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, 0); + if (r < 0) + return r; + + f = lseek(copy_fd, 0, SEEK_SET); + if (f != 0) + return -errno; + + if (r == 0) { + /* Did it fit into the limit? If so, we are done. */ + r = memfd_set_sealed(copy_fd); + if (r < 0) + return r; + + return TAKE_FD(copy_fd); + } + + /* Hmm, pity, this didn't fit. Let's fall back to /tmp then, see below */ + + } else { + _cleanup_(close_pairp) int pipefds[2] = { -1, -1 }; + int isz; + + /* If memfds aren't available, use a pipe. Set O_NONBLOCK so that we will get EAGAIN rather + * then block indefinitely when we hit the pipe size limit */ + + if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0) + return -errno; + + isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0); + if (isz < 0) + return -errno; + + /* Try to enlarge the pipe size if necessary */ + if ((size_t) isz < DATA_FD_MEMORY_LIMIT) { + + (void) fcntl(pipefds[1], F_SETPIPE_SZ, DATA_FD_MEMORY_LIMIT); + + isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0); + if (isz < 0) + return -errno; + } + + if ((size_t) isz >= DATA_FD_MEMORY_LIMIT) { + + r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size); + if (r < 0 && r != -EAGAIN) + return r; /* If we get EAGAIN it could be because of the source or because of + * the destination fd, we can't know, as sendfile() and friends won't + * tell us. Hence, treat this as reason to fall back, just to be + * sure. */ + if (r == 0) { + /* Everything fit in, yay! */ + (void) fd_nonblock(pipefds[0], false); + + return TAKE_FD(pipefds[0]); + } + + /* Things didn't fit in. But we read data into the pipe, let's remember that, so that + * when writing the new file we incorporate this first. */ + copy_fd = TAKE_FD(pipefds[0]); + } + } + } + + /* If we have reason to believe this will fit fine in /tmp, then use that as first fallback. */ + if ((!S_ISREG(st.st_mode) || st.st_size < DATA_FD_TMP_LIMIT) && + (DATA_FD_MEMORY_LIMIT + remains_size) < DATA_FD_TMP_LIMIT) { + off_t f; + + tmp_fd = open_tmpfile_unlinkable(NULL /* NULL as directory means /tmp */, O_RDWR|O_CLOEXEC); + if (tmp_fd < 0) + return tmp_fd; + + if (copy_fd >= 0) { + /* If we tried a memfd/pipe first and it ended up being too large, then copy this into the + * temporary file first. */ + + r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, 0); + if (r < 0) + return r; + + assert(r == 0); + } + + if (remains_size > 0) { + /* If there were remaining bytes (i.e. read into memory, but not written out yet) from the + * failed copy operation, let's flush them out next. */ + + r = loop_write(tmp_fd, remains, remains_size, false); + if (r < 0) + return r; + } + + r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT - remains_size, COPY_REFLINK); + if (r < 0) + return r; + if (r == 0) + goto finish; /* Yay, it fit in */ + + /* It didn't fit in. Let's not forget to use what we already used */ + f = lseek(tmp_fd, 0, SEEK_SET); + if (f != 0) + return -errno; + + safe_close(copy_fd); + copy_fd = TAKE_FD(tmp_fd); + + remains = mfree(remains); + remains_size = 0; + } + + /* As last fallback use /var/tmp */ + r = var_tmp_dir(&td); + if (r < 0) + return r; + + tmp_fd = open_tmpfile_unlinkable(td, O_RDWR|O_CLOEXEC); + if (tmp_fd < 0) + return tmp_fd; + + if (copy_fd >= 0) { + /* If we tried a memfd/pipe first, or a file in /tmp, and it ended up being too large, than copy this + * into the temporary file first. */ + r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK); + if (r < 0) + return r; + + assert(r == 0); + } + + if (remains_size > 0) { + /* Then, copy in any read but not yet written bytes. */ + r = loop_write(tmp_fd, remains, remains_size, false); + if (r < 0) + return r; + } + + /* Copy in the rest */ + r = copy_bytes(fd, tmp_fd, UINT64_MAX, COPY_REFLINK); + if (r < 0) + return r; + + assert(r == 0); + +finish: + /* Now convert the O_RDWR file descriptor into an O_RDONLY one (and as side effect seek to the beginning of the + * file again */ + + return fd_reopen(tmp_fd, O_RDONLY|O_CLOEXEC); +} + int fd_move_above_stdio(int fd) { int flags, copy; PROTECT_ERRNO; @@ -724,3 +906,46 @@ finish: return r; } + +int fd_reopen(int fd, int flags) { + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + int new_fd; + + /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to + * turn O_RDWR fds into O_RDONLY fds. + * + * This doesn't work on sockets (since they cannot be open()ed, ever). + * + * This implicitly resets the file read index to 0. */ + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + new_fd = open(procfs_path, flags); + if (new_fd < 0) + return -errno; + + return new_fd; +} + +int read_nr_open(void) { + _cleanup_free_ char *nr_open = NULL; + int r; + + /* Returns the kernel's current fd limit, either by reading it of /proc/sys if that works, or using the + * hard-coded default compiled-in value of current kernels (1M) if not. This call will never fail. */ + + r = read_one_line_file("/proc/sys/fs/nr_open", &nr_open); + if (r < 0) + log_debug_errno(r, "Failed to read /proc/sys/fs/nr_open, ignoring: %m"); + else { + int v; + + r = safe_atoi(nr_open, &v); + if (r < 0) + log_debug_errno(r, "Failed to parse /proc/sys/fs/nr_open value '%s', ignoring: %m", nr_open); + else + return v; + } + + /* If we fail, fallback to the hard-coded kernel limit of 1024 * 1024. */ + return 1024 * 1024; +} diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 635a538b5a..8adc959da8 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <stdbool.h> #include <stdio.h> @@ -42,7 +23,7 @@ static inline int safe_close_above_stdio(int fd) { return safe_close(fd); } -void close_many(const int fds[], unsigned n_fd); +void close_many(const int fds[], size_t n_fd); int fclose_nointr(FILE *f); FILE* safe_fclose(FILE *f); @@ -72,7 +53,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); int fd_nonblock(int fd, bool nonblock); int fd_cloexec(int fd, bool cloexec); -int close_all_fds(const int except[], unsigned n_except); +int close_all_fds(const int except[], size_t n_except); int same_fd(int a, int b); @@ -94,10 +75,16 @@ enum { int acquire_data_fd(const void *data, size_t size, unsigned flags); +int fd_duplicate_data_fd(int fd); + /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ #define ERRNO_IS_DISCONNECT(r) \ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) +/* Resource exhaustion, could be our fault or general system trouble */ +#define ERRNO_IS_RESOURCE(r) \ + IN_SET(r, ENOMEM, EMFILE, ENFILE) + int fd_move_above_stdio(int fd); int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd); @@ -105,3 +92,15 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_ static inline int make_null_stdio(void) { return rearrange_stdio(-1, -1, -1); } + +/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */ +#define TAKE_FD(fd) \ + ({ \ + int _fd_ = (fd); \ + (fd) = -1; \ + _fd_; \ + }) + +int fd_reopen(int fd, int flags); + +int read_nr_open(void); diff --git a/src/basic/fileio-label.c b/src/basic/fileio-label.c index b832b6bf04..5f8d8af9af 100644 --- a/src/basic/fileio-label.c +++ b/src/basic/fileio-label.c @@ -1,22 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2010 Harald Hoyer - - 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/>. + Copyright © 2010 Harald Hoyer ***/ #include <sys/stat.h> diff --git a/src/basic/fileio-label.h b/src/basic/fileio-label.h index 16d095f522..db8e738326 100644 --- a/src/basic/fileio-label.h +++ b/src/basic/fileio-label.h @@ -2,23 +2,7 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2010 Harald Hoyer - - 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/>. + Copyright © 2010 Harald Hoyer ***/ #include <stdio.h> diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 29b941348a..6b0bad5b71 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> @@ -63,6 +45,7 @@ int write_string_stream_ts( struct timespec *ts) { bool needs_nl; + int r; assert(f); assert(line); @@ -87,6 +70,13 @@ int write_string_stream_ts( if (fputc('\n', f) == EOF) return -errno; + if (flags & WRITE_STRING_FILE_SYNC) + r = fflush_sync_and_check(f); + else + r = fflush_and_check(f); + if (r < 0) + return r; + if (ts) { struct timespec twice[2] = {*ts, *ts}; @@ -94,10 +84,7 @@ int write_string_stream_ts( return -errno; } - if (flags & WRITE_STRING_FILE_SYNC) - return fflush_sync_and_check(f); - else - return fflush_and_check(f); + return 0; } static int write_string_file_atomic( @@ -214,6 +201,25 @@ fail: return 0; } +int write_string_filef( + const char *fn, + WriteStringFileFlags flags, + const char *format, ...) { + + _cleanup_free_ char *p = NULL; + va_list ap; + int r; + + va_start(ap, format); + r = vasprintf(&p, format, ap); + va_end(ap); + + if (r < 0) + return -ENOMEM; + + return write_string_file(fn, p, flags); +} + int read_one_line_file(const char *fn, char **line) { _cleanup_fclose_ FILE *f = NULL; int r; @@ -271,29 +277,35 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { } int read_full_stream(FILE *f, char **contents, size_t *size) { - size_t n, l; _cleanup_free_ char *buf = NULL; struct stat st; + size_t n, l; + int fd; assert(f); assert(contents); - if (fstat(fileno(f), &st) < 0) - return -errno; - n = LINE_MAX; - if (S_ISREG(st.st_mode)) { + fd = fileno(f); + if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's + * optimize our buffering) */ - /* Safety check */ - if (st.st_size > READ_FULL_BYTES_MAX) - return -E2BIG; + if (fstat(fileno(f), &st) < 0) + return -errno; + + if (S_ISREG(st.st_mode)) { - /* Start with the right file size, but be prepared for files from /proc which generally report a file - * size of 0. Note that we increase the size to read here by one, so that the first read attempt - * already makes us notice the EOF. */ - if (st.st_size > 0) - n = st.st_size + 1; + /* Safety check */ + if (st.st_size > READ_FULL_BYTES_MAX) + return -E2BIG; + + /* Start with the right file size, but be prepared for files from /proc which generally report a file + * size of 0. Note that we increase the size to read here by one, so that the first read attempt + * already makes us notice the EOF. */ + if (st.st_size > 0) + n = st.st_size + 1; + } } l = 0; @@ -330,8 +342,7 @@ int read_full_stream(FILE *f, char **contents, size_t *size) { } buf[l] = 0; - *contents = buf; - buf = NULL; /* do not free */ + *contents = TAKE_PTR(buf); if (size) *size = l; @@ -363,11 +374,11 @@ static int parse_env_file_internal( void *userdata, int *n_pushed) { - _cleanup_free_ char *contents = NULL, *key = NULL; size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; - char *p, *value = NULL; - int r; + _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL; unsigned line = 1; + char *p; + int r; enum { PRE_KEY, @@ -404,10 +415,8 @@ static int parse_env_file_internal( state = KEY; last_key_whitespace = (size_t) -1; - if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) + return -ENOMEM; key[n_key++] = c; } @@ -427,10 +436,8 @@ static int parse_env_file_internal( else if (last_key_whitespace == (size_t) -1) last_key_whitespace = n_key; - if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) + return -ENOMEM; key[n_key++] = c; } @@ -452,7 +459,7 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - goto fail; + return r; n_key = 0; value = NULL; @@ -467,10 +474,8 @@ static int parse_env_file_internal( else if (!strchr(WHITESPACE, c)) { state = VALUE; - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -497,7 +502,7 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - goto fail; + return r; n_key = 0; value = NULL; @@ -512,10 +517,8 @@ static int parse_env_file_internal( else if (last_value_whitespace == (size_t) -1) last_value_whitespace = n_value; - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -527,10 +530,8 @@ static int parse_env_file_internal( if (!strchr(newline, c)) { /* Escaped newlines we eat up entirely */ - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -542,10 +543,8 @@ static int parse_env_file_internal( else if (c == '\\') state = SINGLE_QUOTE_VALUE_ESCAPE; else { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -556,10 +555,8 @@ static int parse_env_file_internal( state = SINGLE_QUOTE_VALUE; if (!strchr(newline, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -571,10 +568,8 @@ static int parse_env_file_internal( else if (c == '\\') state = DOUBLE_QUOTE_VALUE_ESCAPE; else { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -585,10 +580,8 @@ static int parse_env_file_internal( state = DOUBLE_QUOTE_VALUE; if (!strchr(newline, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -633,14 +626,12 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - goto fail; + return r; + + value = NULL; } return 0; - -fail: - free(value); - return r; } static int check_utf8ness_and_warn( @@ -705,21 +696,41 @@ static int parse_env_file_push( return 0; } -int parse_env_file( +int parse_env_filev( + FILE *f, const char *fname, - const char *newline, ...) { + const char *newline, + va_list ap) { - va_list ap; int r, n_pushed = 0; + va_list aq; if (!newline) newline = NEWLINE; + va_copy(aq, ap); + r = parse_env_file_internal(f, fname, newline, parse_env_file_push, &aq, &n_pushed); + va_end(aq); + if (r < 0) + return r; + + return n_pushed; +} + +int parse_env_file( + FILE *f, + const char *fname, + const char *newline, + ...) { + + va_list ap; + int r; + va_start(ap, newline); - r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed); + r = parse_env_filev(f, fname, newline, ap); va_end(ap); - return r < 0 ? r : n_pushed; + return r; } static int load_env_file_push( @@ -1237,7 +1248,7 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); - *ret = path_kill_slashes(t); + *ret = path_simplify(t, false); return 0; } @@ -1278,7 +1289,7 @@ int tempfn_random(const char *p, const char *extra, char **ret) { *x = 0; - *ret = path_kill_slashes(t); + *ret = path_simplify(t, false); return 0; } @@ -1318,7 +1329,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { *x = 0; - *ret = path_kill_slashes(t); + *ret = path_simplify(t, false); return 0; } @@ -1452,8 +1463,7 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { if (fd < 0) return -errno; - *ret_path = tmp; - tmp = NULL; + *ret_path = TAKE_PTR(tmp); return fd; } @@ -1539,28 +1549,35 @@ int read_nul_string(FILE *f, char **ret) { return -ENOMEM; } - *ret = x; - x = NULL; + *ret = TAKE_PTR(x); return 0; } int mkdtemp_malloc(const char *template, char **ret) { - char *p; + _cleanup_free_ char *p = NULL; + int r; - assert(template); assert(ret); - p = strdup(template); + if (template) + p = strdup(template); + else { + const char *tmp; + + r = tmp_dir(&tmp); + if (r < 0) + return r; + + p = strjoin(tmp, "/XXXXXX"); + } if (!p) return -ENOMEM; - if (!mkdtemp(p)) { - free(p); + if (!mkdtemp(p)) return -errno; - } - *ret = p; + *ret = TAKE_PTR(p); return 0; } @@ -1629,8 +1646,7 @@ int read_line(FILE *f, size_t limit, char **ret) { if (ret) { buffer[n] = 0; - *ret = buffer; - buffer = NULL; + *ret = TAKE_PTR(buffer); } return (int) count; diff --git a/src/basic/fileio.h b/src/basic/fileio.h index da5d5c66b5..77e6206e95 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <stdbool.h> #include <stddef.h> @@ -30,12 +11,12 @@ #include "time-util.h" typedef enum { - WRITE_STRING_FILE_CREATE = 1<<0, - WRITE_STRING_FILE_ATOMIC = 1<<1, - WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2, - WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1<<3, - WRITE_STRING_FILE_SYNC = 1<<4, - WRITE_STRING_FILE_DISABLE_BUFFER = 1<<5, + WRITE_STRING_FILE_CREATE = 1 << 0, + WRITE_STRING_FILE_ATOMIC = 1 << 1, + WRITE_STRING_FILE_AVOID_NEWLINE = 1 << 2, + WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3, + WRITE_STRING_FILE_SYNC = 1 << 4, + WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5, /* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file() @@ -52,13 +33,16 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin return write_string_file_ts(fn, line, flags, NULL); } +int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4); + int read_one_line_file(const char *fn, char **line); int read_full_file(const char *fn, char **contents, size_t *size); int read_full_stream(FILE *f, char **contents, size_t *size); int verify_file(const char *fn, const char *blob, bool accept_extra_nl); -int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; +int parse_env_filev(FILE *f, const char *fname, const char *separator, va_list ap); +int parse_env_file(FILE *f, const char *fname, const char *separator, ...) _sentinel_; int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l); diff --git a/src/basic/format-table.c b/src/basic/format-table.c new file mode 100644 index 0000000000..94e796d1ca --- /dev/null +++ b/src/basic/format-table.c @@ -0,0 +1,1247 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <stdio_ext.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "format-table.h" +#include "gunicode.h" +#include "pager.h" +#include "parse-util.h" +#include "string-util.h" +#include "terminal-util.h" +#include "time-util.h" +#include "utf8.h" +#include "util.h" + +#define DEFAULT_WEIGHT 100 + +/* + A few notes on implementation details: + + - TableCell is a 'fake' structure, it's just used as data type to pass references to specific cell positions in the + table. It can be easily converted to an index number and back. + + - TableData is where the actual data is stored: it encapsulates the data and formatting for a specific cell. It's + 'pseudo-immutable' and ref-counted. When a cell's data's formatting is to be changed, we duplicate the object if the + ref-counting is larger than 1. Note that TableData and its ref-counting is mostly not visible to the outside. The + outside only sees Table and TableCell. + + - The Table object stores a simple one-dimensional array of references to TableData objects, one row after the + previous one. + + - There's no special concept of a "row" or "column" in the table, and no special concept of the "header" row. It's all + derived from the cell index: we know how many cells are to be stored in a row, and can determine the rest from + that. The first row is always the header row. If header display is turned off we simply skip outputting the first + row. Also, when sorting rows we always leave the first row where it is, as the header shouldn't move. + + - Note because there's no row and no column object some properties that might be approproate as row/column properties + are exposed as cell properties instead. For example, the "weight" of a column (which is used to determine where to + add/remove space preferable when expanding/compressing tables horizontally) is actually made the "weight" of a + cell. Given that we usually need it per-column though we will calculate the average across every cell of the column + instead. + + - To make things easy, when cells are added without any explicit configured formatting, then we'll copy the formatting + from the same cell in the previous cell. This is particularly useful for the "weight" of the cell (see above), as + this means setting the weight of the cells of the header row will nicely propagate to all cells in the other rows. +*/ + +typedef struct TableData { + unsigned n_ref; + TableDataType type; + + size_t minimum_width; /* minimum width for the column */ + size_t maximum_width; /* maximum width for the column */ + unsigned weight; /* the horizontal weight for this column, in case the table is expanded/compressed */ + unsigned ellipsize_percent; /* 0 … 100, where to place the ellipsis when compression is needed */ + unsigned align_percent; /* 0 … 100, where to pad with spaces when expanding is needed. 0: left-aligned, 100: right-aligned */ + + const char *color; /* ANSI color string to use for this cell. When written to terminal should not move cursor. Will automatically be reset after the cell */ + char *formatted; /* A cached textual representation of the cell data, before ellipsation/alignment */ + + union { + uint8_t data[0]; /* data is generic array */ + bool boolean; + usec_t timestamp; + usec_t timespan; + uint64_t size; + char string[0]; + uint32_t uint32; + /* … add more here as we start supporting more cell data types … */ + }; +} TableData; + +static size_t TABLE_CELL_TO_INDEX(TableCell *cell) { + unsigned i; + + assert(cell); + + i = PTR_TO_UINT(cell); + assert(i > 0); + + return i-1; +} + +static TableCell* TABLE_INDEX_TO_CELL(size_t index) { + assert(index != (size_t) -1); + return UINT_TO_PTR((unsigned) (index + 1)); +} + +struct Table { + size_t n_columns; + size_t n_cells; + + bool header; /* Whether to show the header row? */ + size_t width; /* If != (size_t) -1 the width to format this table in */ + + TableData **data; + size_t n_allocated; + + size_t *display_map; /* List of columns to show (by their index). It's fine if columns are listed multiple times or not at all */ + size_t n_display_map; + + size_t *sort_map; /* The columns to order rows by, in order of preference. */ + size_t n_sort_map; +}; + +Table *table_new_raw(size_t n_columns) { + _cleanup_(table_unrefp) Table *t = NULL; + + assert(n_columns > 0); + + t = new(Table, 1); + if (!t) + return NULL; + + *t = (struct Table) { + .n_columns = n_columns, + .header = true, + .width = (size_t) -1, + }; + + return TAKE_PTR(t); +} + +Table *table_new_internal(const char *first_header, ...) { + _cleanup_(table_unrefp) Table *t = NULL; + size_t n_columns = 1; + va_list ap; + int r; + + assert(first_header); + + va_start(ap, first_header); + for (;;) { + const char *h; + + h = va_arg(ap, const char*); + if (!h) + break; + + n_columns++; + } + va_end(ap); + + t = table_new_raw(n_columns); + if (!t) + return NULL; + + r = table_add_cell(t, NULL, TABLE_STRING, first_header); + if (r < 0) + return NULL; + + va_start(ap, first_header); + for (;;) { + const char *h; + + h = va_arg(ap, const char*); + if (!h) + break; + + r = table_add_cell(t, NULL, TABLE_STRING, h); + if (r < 0) { + va_end(ap); + return NULL; + } + } + va_end(ap); + + assert(t->n_columns == t->n_cells); + return TAKE_PTR(t); +} + +static TableData *table_data_unref(TableData *d) { + if (!d) + return NULL; + + assert(d->n_ref > 0); + d->n_ref--; + + if (d->n_ref > 0) + return NULL; + + free(d->formatted); + return mfree(d); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(TableData*, table_data_unref); + +static TableData *table_data_ref(TableData *d) { + if (!d) + return NULL; + + assert(d->n_ref > 0); + d->n_ref++; + + return d; +} + +Table *table_unref(Table *t) { + size_t i; + + if (!t) + return NULL; + + for (i = 0; i < t->n_cells; i++) + table_data_unref(t->data[i]); + + free(t->data); + free(t->display_map); + free(t->sort_map); + + return mfree(t); +} + +static size_t table_data_size(TableDataType type, const void *data) { + + switch (type) { + + case TABLE_EMPTY: + return 0; + + case TABLE_STRING: + return strlen(data) + 1; + + case TABLE_BOOLEAN: + return sizeof(bool); + + case TABLE_TIMESTAMP: + case TABLE_TIMESPAN: + return sizeof(usec_t); + + case TABLE_SIZE: + return sizeof(uint64_t); + + case TABLE_UINT32: + return sizeof(uint32_t); + + default: + assert_not_reached("Uh? Unexpected cell type"); + } +} + +static bool table_data_matches( + TableData *d, + TableDataType type, + const void *data, + size_t minimum_width, + size_t maximum_width, + unsigned weight, + unsigned align_percent, + unsigned ellipsize_percent) { + + size_t k, l; + assert(d); + + if (d->type != type) + return false; + + if (d->minimum_width != minimum_width) + return false; + + if (d->maximum_width != maximum_width) + return false; + + if (d->weight != weight) + return false; + + if (d->align_percent != align_percent) + return false; + + if (d->ellipsize_percent != ellipsize_percent) + return false; + + k = table_data_size(type, data); + l = table_data_size(d->type, d->data); + + if (k != l) + return false; + + return memcmp(data, d->data, l) == 0; +} + +static TableData *table_data_new( + TableDataType type, + const void *data, + size_t minimum_width, + size_t maximum_width, + unsigned weight, + unsigned align_percent, + unsigned ellipsize_percent) { + + size_t data_size; + TableData *d; + + data_size = table_data_size(type, data); + + d = malloc0(offsetof(TableData, data) + data_size); + if (!d) + return NULL; + + d->n_ref = 1; + d->type = type; + d->minimum_width = minimum_width; + d->maximum_width = maximum_width; + d->weight = weight; + d->align_percent = align_percent; + d->ellipsize_percent = ellipsize_percent; + memcpy_safe(d->data, data, data_size); + + return d; +} + +int table_add_cell_full( + Table *t, + TableCell **ret_cell, + TableDataType type, + const void *data, + size_t minimum_width, + size_t maximum_width, + unsigned weight, + unsigned align_percent, + unsigned ellipsize_percent) { + + _cleanup_(table_data_unrefp) TableData *d = NULL; + TableData *p; + + assert(t); + assert(type >= 0); + assert(type < _TABLE_DATA_TYPE_MAX); + + /* Determine the cell adjacent to the current one, but one row up */ + if (t->n_cells >= t->n_columns) + assert_se(p = t->data[t->n_cells - t->n_columns]); + else + p = NULL; + + /* If formatting parameters are left unspecified, copy from the previous row */ + if (minimum_width == (size_t) -1) + minimum_width = p ? p->minimum_width : 1; + + if (weight == (unsigned) -1) + weight = p ? p->weight : DEFAULT_WEIGHT; + + if (align_percent == (unsigned) -1) + align_percent = p ? p->align_percent : 0; + + if (ellipsize_percent == (unsigned) -1) + ellipsize_percent = p ? p->ellipsize_percent : 100; + + assert(align_percent <= 100); + assert(ellipsize_percent <= 100); + + /* Small optimization: Pretty often adjacent cells in two subsequent lines have the same data and + * formatting. Let's see if we can reuse the cell data and ref it once more. */ + + if (p && table_data_matches(p, type, data, minimum_width, maximum_width, weight, align_percent, ellipsize_percent)) + d = table_data_ref(p); + else { + d = table_data_new(type, data, minimum_width, maximum_width, weight, align_percent, ellipsize_percent); + if (!d) + return -ENOMEM; + } + + if (!GREEDY_REALLOC(t->data, t->n_allocated, MAX(t->n_cells + 1, t->n_columns))) + return -ENOMEM; + + if (ret_cell) + *ret_cell = TABLE_INDEX_TO_CELL(t->n_cells); + + t->data[t->n_cells++] = TAKE_PTR(d); + + return 0; +} + +int table_dup_cell(Table *t, TableCell *cell) { + size_t i; + + assert(t); + + /* Add the data of the specified cell a second time as a new cell to the end. */ + + i = TABLE_CELL_TO_INDEX(cell); + if (i >= t->n_cells) + return -ENXIO; + + if (!GREEDY_REALLOC(t->data, t->n_allocated, MAX(t->n_cells + 1, t->n_columns))) + return -ENOMEM; + + t->data[t->n_cells++] = table_data_ref(t->data[i]); + return 0; +} + +static int table_dedup_cell(Table *t, TableCell *cell) { + TableData *nd, *od; + size_t i; + + assert(t); + + /* Helper call that ensures the specified cell's data object has a ref count of 1, which we can use before + * changing a cell's formatting without effecting every other cell's formatting that shares the same data */ + + i = TABLE_CELL_TO_INDEX(cell); + if (i >= t->n_cells) + return -ENXIO; + + assert_se(od = t->data[i]); + if (od->n_ref == 1) + return 0; + + assert(od->n_ref > 1); + + nd = table_data_new(od->type, od->data, od->minimum_width, od->maximum_width, od->weight, od->align_percent, od->ellipsize_percent); + if (!nd) + return -ENOMEM; + + table_data_unref(od); + t->data[i] = nd; + + assert(nd->n_ref == 1); + + return 1; +} + +static TableData *table_get_data(Table *t, TableCell *cell) { + size_t i; + + assert(t); + assert(cell); + + /* Get the data object of the specified cell, or NULL if it doesn't exist */ + + i = TABLE_CELL_TO_INDEX(cell); + if (i >= t->n_cells) + return NULL; + + assert(t->data[i]); + assert(t->data[i]->n_ref > 0); + + return t->data[i]; +} + +int table_set_minimum_width(Table *t, TableCell *cell, size_t minimum_width) { + int r; + + assert(t); + assert(cell); + + if (minimum_width == (size_t) -1) + minimum_width = 1; + + r = table_dedup_cell(t, cell); + if (r < 0) + return r; + + table_get_data(t, cell)->minimum_width = minimum_width; + return 0; +} + +int table_set_maximum_width(Table *t, TableCell *cell, size_t maximum_width) { + int r; + + assert(t); + assert(cell); + + r = table_dedup_cell(t, cell); + if (r < 0) + return r; + + table_get_data(t, cell)->maximum_width = maximum_width; + return 0; +} + +int table_set_weight(Table *t, TableCell *cell, unsigned weight) { + int r; + + assert(t); + assert(cell); + + if (weight == (unsigned) -1) + weight = DEFAULT_WEIGHT; + + r = table_dedup_cell(t, cell); + if (r < 0) + return r; + + table_get_data(t, cell)->weight = weight; + return 0; +} + +int table_set_align_percent(Table *t, TableCell *cell, unsigned percent) { + int r; + + assert(t); + assert(cell); + + if (percent == (unsigned) -1) + percent = 0; + + assert(percent <= 100); + + r = table_dedup_cell(t, cell); + if (r < 0) + return r; + + table_get_data(t, cell)->align_percent = percent; + return 0; +} + +int table_set_ellipsize_percent(Table *t, TableCell *cell, unsigned percent) { + int r; + + assert(t); + assert(cell); + + if (percent == (unsigned) -1) + percent = 100; + + assert(percent <= 100); + + r = table_dedup_cell(t, cell); + if (r < 0) + return r; + + table_get_data(t, cell)->ellipsize_percent = percent; + return 0; +} + +int table_set_color(Table *t, TableCell *cell, const char *color) { + int r; + + assert(t); + assert(cell); + + r = table_dedup_cell(t, cell); + if (r < 0) + return r; + + table_get_data(t, cell)->color = empty_to_null(color); + return 0; +} + +int table_add_many_internal(Table *t, TableDataType first_type, ...) { + TableDataType type; + va_list ap; + int r; + + assert(t); + assert(first_type >= 0); + assert(first_type < _TABLE_DATA_TYPE_MAX); + + type = first_type; + + va_start(ap, first_type); + for (;;) { + const void *data; + union { + uint64_t size; + usec_t usec; + uint32_t uint32; + bool b; + } buffer; + + switch (type) { + + case TABLE_EMPTY: + data = NULL; + break; + + case TABLE_STRING: + data = va_arg(ap, const char *); + break; + + case TABLE_BOOLEAN: + buffer.b = va_arg(ap, int); + data = &buffer.b; + break; + + case TABLE_TIMESTAMP: + case TABLE_TIMESPAN: + buffer.usec = va_arg(ap, usec_t); + data = &buffer.usec; + break; + + case TABLE_SIZE: + buffer.size = va_arg(ap, uint64_t); + data = &buffer.size; + break; + + case TABLE_UINT32: + buffer.uint32 = va_arg(ap, uint32_t); + data = &buffer.uint32; + break; + + case _TABLE_DATA_TYPE_MAX: + /* Used as end marker */ + va_end(ap); + return 0; + + default: + assert_not_reached("Uh? Unexpected data type."); + } + + r = table_add_cell(t, NULL, type, data); + if (r < 0) { + va_end(ap); + return r; + } + + type = va_arg(ap, TableDataType); + } +} + +void table_set_header(Table *t, bool b) { + assert(t); + + t->header = b; +} + +void table_set_width(Table *t, size_t width) { + assert(t); + + t->width = width; +} + +int table_set_display(Table *t, size_t first_column, ...) { + size_t allocated, column; + va_list ap; + + assert(t); + + allocated = t->n_display_map; + column = first_column; + + va_start(ap, first_column); + for (;;) { + assert(column < t->n_columns); + + if (!GREEDY_REALLOC(t->display_map, allocated, MAX(t->n_columns, t->n_display_map+1))) { + va_end(ap); + return -ENOMEM; + } + + t->display_map[t->n_display_map++] = column; + + column = va_arg(ap, size_t); + if (column == (size_t) -1) + break; + + } + va_end(ap); + + return 0; +} + +int table_set_sort(Table *t, size_t first_column, ...) { + size_t allocated, column; + va_list ap; + + assert(t); + + allocated = t->n_sort_map; + column = first_column; + + va_start(ap, first_column); + for (;;) { + assert(column < t->n_columns); + + if (!GREEDY_REALLOC(t->sort_map, allocated, MAX(t->n_columns, t->n_sort_map+1))) { + va_end(ap); + return -ENOMEM; + } + + t->sort_map[t->n_sort_map++] = column; + + column = va_arg(ap, size_t); + if (column == (size_t) -1) + break; + } + va_end(ap); + + return 0; +} + +static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t index_b) { + assert(a); + assert(b); + + if (a->type == b->type) { + + /* We only define ordering for cells of the same data type. If cells with different data types are + * compared we follow the order the cells were originally added in */ + + switch (a->type) { + + case TABLE_STRING: + return strcmp(a->string, b->string); + + case TABLE_BOOLEAN: + if (!a->boolean && b->boolean) + return -1; + if (a->boolean && !b->boolean) + return 1; + return 0; + + case TABLE_TIMESTAMP: + if (a->timestamp < b->timestamp) + return -1; + if (a->timestamp > b->timestamp) + return 1; + return 0; + + case TABLE_TIMESPAN: + if (a->timespan < b->timespan) + return -1; + if (a->timespan > b->timespan) + return 1; + return 0; + + case TABLE_SIZE: + if (a->size < b->size) + return -1; + if (a->size > b->size) + return 1; + return 0; + + case TABLE_UINT32: + if (a->uint32 < b->uint32) + return -1; + if (a->uint32 > b->uint32) + return 1; + return 0; + + default: + ; + } + } + + /* Generic fallback using the orginal order in which the cells where added. */ + if (index_a < index_b) + return -1; + if (index_a > index_b) + return 1; + + return 0; +} + +static int table_data_compare(const void *x, const void *y, void *userdata) { + const size_t *a = x, *b = y; + Table *t = userdata; + size_t i; + int r; + + assert(t); + assert(t->sort_map); + + /* Make sure the header stays at the beginning */ + if (*a < t->n_columns && *b < t->n_columns) + return 0; + if (*a < t->n_columns) + return -1; + if (*b < t->n_columns) + return 1; + + /* Order other lines by the sorting map */ + for (i = 0; i < t->n_sort_map; i++) { + TableData *d, *dd; + + d = t->data[*a + t->sort_map[i]]; + dd = t->data[*b + t->sort_map[i]]; + + r = cell_data_compare(d, *a, dd, *b); + if (r != 0) + return r; + } + + /* Order identical lines by the order there were originally added in */ + if (*a < *b) + return -1; + if (*a > *b) + return 1; + + return 0; +} + +static const char *table_data_format(TableData *d) { + assert(d); + + if (d->formatted) + return d->formatted; + + switch (d->type) { + case TABLE_EMPTY: + return ""; + + case TABLE_STRING: + return d->string; + + case TABLE_BOOLEAN: + return yes_no(d->boolean); + + case TABLE_TIMESTAMP: { + _cleanup_free_ char *p; + + p = new(char, FORMAT_TIMESTAMP_MAX); + if (!p) + return NULL; + + if (!format_timestamp(p, FORMAT_TIMESTAMP_MAX, d->timestamp)) + return "n/a"; + + d->formatted = TAKE_PTR(p); + break; + } + + case TABLE_TIMESPAN: { + _cleanup_free_ char *p; + + p = new(char, FORMAT_TIMESPAN_MAX); + if (!p) + return NULL; + + if (!format_timespan(p, FORMAT_TIMESPAN_MAX, d->timestamp, 0)) + return "n/a"; + + d->formatted = TAKE_PTR(p); + break; + } + + case TABLE_SIZE: { + _cleanup_free_ char *p; + + p = new(char, FORMAT_BYTES_MAX); + if (!p) + return NULL; + + if (!format_bytes(p, FORMAT_BYTES_MAX, d->size)) + return "n/a"; + + d->formatted = TAKE_PTR(p); + break; + } + + case TABLE_UINT32: { + _cleanup_free_ char *p; + + p = new(char, DECIMAL_STR_WIDTH(d->uint32) + 1); + if (!p) + return NULL; + + sprintf(p, "%" PRIu32, d->uint32); + d->formatted = TAKE_PTR(p); + break; + } + + default: + assert_not_reached("Unexpected type?"); + } + + return d->formatted; +} + +static int table_data_requested_width(TableData *d, size_t *ret) { + const char *t; + size_t l; + + t = table_data_format(d); + if (!t) + return -ENOMEM; + + l = utf8_console_width(t); + if (l == (size_t) -1) + return -EINVAL; + + if (d->maximum_width != (size_t) -1 && l > d->maximum_width) + l = d->maximum_width; + + if (l < d->minimum_width) + l = d->minimum_width; + + *ret = l; + return 0; +} + +static char *align_string_mem(const char *str, size_t new_length, unsigned percent) { + size_t w = 0, space, lspace, old_length; + const char *p; + char *ret; + size_t i; + + /* As with ellipsize_mem(), 'old_length' is a byte size while 'new_length' is a width in character cells */ + + assert(str); + assert(percent <= 100); + + old_length = strlen(str); + + /* Determine current width on screen */ + p = str; + while (p < str + old_length) { + char32_t c; + + if (utf8_encoded_to_unichar(p, &c) < 0) { + p++, w++; /* count invalid chars as 1 */ + continue; + } + + p = utf8_next_char(p); + w += unichar_iswide(c) ? 2 : 1; + } + + /* Already wider than the target, if so, don't do anything */ + if (w >= new_length) + return strndup(str, old_length); + + /* How much spaces shall we add? An how much on the left side? */ + space = new_length - w; + lspace = space * percent / 100U; + + ret = new(char, space + old_length + 1); + if (!ret) + return NULL; + + for (i = 0; i < lspace; i++) + ret[i] = ' '; + memcpy(ret + lspace, str, old_length); + for (i = lspace + old_length; i < space + old_length; i++) + ret[i] = ' '; + + ret[space + old_length] = 0; + return ret; +} + +int table_print(Table *t, FILE *f) { + size_t n_rows, *minimum_width, *maximum_width, display_columns, *requested_width, + i, j, table_minimum_width, table_maximum_width, table_requested_width, table_effective_width, + *width; + _cleanup_free_ size_t *sorted = NULL; + uint64_t *column_weight, weight_sum; + int r; + + assert(t); + + if (!f) + f = stdout; + + /* Ensure we have no incomplete rows */ + assert(t->n_cells % t->n_columns == 0); + + n_rows = t->n_cells / t->n_columns; + assert(n_rows > 0); /* at least the header row must be complete */ + + if (t->sort_map) { + /* If sorting is requested, let's calculate an index table we use to lookup the actual index to display with. */ + + sorted = new(size_t, n_rows); + if (!sorted) + return -ENOMEM; + + for (i = 0; i < n_rows; i++) + sorted[i] = i * t->n_columns; + + qsort_r_safe(sorted, n_rows, sizeof(size_t), table_data_compare, t); + } + + if (t->display_map) + display_columns = t->n_display_map; + else + display_columns = t->n_columns; + + assert(display_columns > 0); + + minimum_width = newa(size_t, display_columns); + maximum_width = newa(size_t, display_columns); + requested_width = newa(size_t, display_columns); + width = newa(size_t, display_columns); + column_weight = newa0(uint64_t, display_columns); + + for (j = 0; j < display_columns; j++) { + minimum_width[j] = 1; + maximum_width[j] = (size_t) -1; + requested_width[j] = (size_t) -1; + } + + /* First pass: determine column sizes */ + for (i = t->header ? 0 : 1; i < n_rows; i++) { + TableData **row; + + /* Note that we don't care about ordering at this time, as we just want to determine column sizes, + * hence we don't care for sorted[] during the first pass. */ + row = t->data + i * t->n_columns; + + for (j = 0; j < display_columns; j++) { + TableData *d; + size_t req; + + assert_se(d = row[t->display_map ? t->display_map[j] : j]); + + r = table_data_requested_width(d, &req); + if (r < 0) + return r; + + /* Determine the biggest width that any cell in this column would like to have */ + if (requested_width[j] == (size_t) -1 || + requested_width[j] < req) + requested_width[j] = req; + + /* Determine the minimum width any cell in this column needs */ + if (minimum_width[j] < d->minimum_width) + minimum_width[j] = d->minimum_width; + + /* Determine the maximum width any cell in this column needs */ + if (d->maximum_width != (size_t) -1 && + (maximum_width[j] == (size_t) -1 || + maximum_width[j] > d->maximum_width)) + maximum_width[j] = d->maximum_width; + + /* Determine the full columns weight */ + column_weight[j] += d->weight; + } + } + + /* One space between each column */ + table_requested_width = table_minimum_width = table_maximum_width = display_columns - 1; + + /* Calculate the total weight for all columns, plus the minimum, maximum and requested width for the table. */ + weight_sum = 0; + for (j = 0; j < display_columns; j++) { + weight_sum += column_weight[j]; + + table_minimum_width += minimum_width[j]; + + if (maximum_width[j] == (size_t) -1) + table_maximum_width = (size_t) -1; + else + table_maximum_width += maximum_width[j]; + + table_requested_width += requested_width[j]; + } + + /* Calculate effective table width */ + if (t->width == (size_t) -1) + table_effective_width = pager_have() ? table_requested_width : MIN(table_requested_width, columns()); + else + table_effective_width = t->width; + + if (table_maximum_width != (size_t) -1 && table_effective_width > table_maximum_width) + table_effective_width = table_maximum_width; + + if (table_effective_width < table_minimum_width) + table_effective_width = table_minimum_width; + + if (table_effective_width >= table_requested_width) { + size_t extra; + + /* We have extra room, let's distribute it among columns according to their weights. We first provide + * each column with what it asked for and the distribute the rest. */ + + extra = table_effective_width - table_requested_width; + + for (j = 0; j < display_columns; j++) { + size_t delta; + + if (weight_sum == 0) + width[j] = requested_width[j] + extra / (display_columns - j); /* Avoid division by zero */ + else + width[j] = requested_width[j] + (extra * column_weight[j]) / weight_sum; + + if (maximum_width[j] != (size_t) -1 && width[j] > maximum_width[j]) + width[j] = maximum_width[j]; + + if (width[j] < minimum_width[j]) + width[j] = minimum_width[j]; + + assert(width[j] >= requested_width[j]); + delta = width[j] - requested_width[j]; + + /* Subtract what we just added from the rest */ + if (extra > delta) + extra -= delta; + else + extra = 0; + + assert(weight_sum >= column_weight[j]); + weight_sum -= column_weight[j]; + } + + } else { + /* We need to compress the table, columns can't get what they asked for. We first provide each column + * with the minimum they need, and then distribute anything left. */ + bool finalize = false; + size_t extra; + + extra = table_effective_width - table_minimum_width; + + for (j = 0; j < display_columns; j++) + width[j] = (size_t) -1; + + for (;;) { + bool restart = false; + + for (j = 0; j < display_columns; j++) { + size_t delta, w; + + /* Did this column already get something assigned? If so, let's skip to the next */ + if (width[j] != (size_t) -1) + continue; + + if (weight_sum == 0) + w = minimum_width[j] + extra / (display_columns - j); /* avoid division by zero */ + else + w = minimum_width[j] + (extra * column_weight[j]) / weight_sum; + + if (w >= requested_width[j]) { + /* Never give more than requested. If we hit a column like this, there's more + * space to allocate to other columns which means we need to restart the + * iteration. However, if we hit a column like this, let's assign it the space + * it wanted for good early.*/ + + w = requested_width[j]; + restart = true; + + } else if (!finalize) + continue; + + width[j] = w; + + assert(w >= minimum_width[j]); + delta = w - minimum_width[j]; + + assert(delta <= extra); + extra -= delta; + + assert(weight_sum >= column_weight[j]); + weight_sum -= column_weight[j]; + + if (restart) + break; + } + + if (finalize) { + assert(!restart); + break; + } + + if (!restart) + finalize = true; + } + } + + /* Second pass: show output */ + for (i = t->header ? 0 : 1; i < n_rows; i++) { + TableData **row; + + if (sorted) + row = t->data + sorted[i]; + else + row = t->data + i * t->n_columns; + + for (j = 0; j < display_columns; j++) { + _cleanup_free_ char *buffer = NULL; + const char *field; + TableData *d; + size_t l; + + assert_se(d = row[t->display_map ? t->display_map[j] : j]); + + field = table_data_format(d); + if (!field) + return -ENOMEM; + + l = utf8_console_width(field); + if (l > width[j]) { + /* Field is wider than allocated space. Let's ellipsize */ + + buffer = ellipsize(field, width[j], d->ellipsize_percent); + if (!buffer) + return -ENOMEM; + + field = buffer; + + } else if (l < width[j]) { + /* Field is shorter than allocated space. Let's align with spaces */ + + buffer = align_string_mem(field, width[j], d->align_percent); + if (!buffer) + return -ENOMEM; + + field = buffer; + } + + if (j > 0) + fputc(' ', f); /* column separator */ + + if (d->color) + fputs(d->color, f); + + fputs(field, f); + + if (d->color) + fputs(ansi_normal(), f); + } + + fputc('\n', f); + } + + return fflush_and_check(f); +} + +int table_format(Table *t, char **ret) { + _cleanup_fclose_ FILE *f = NULL; + char *buf = NULL; + size_t sz = 0; + int r; + + f = open_memstream(&buf, &sz); + if (!f) + return -ENOMEM; + + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + + r = table_print(t, f); + if (r < 0) + return r; + + f = safe_fclose(f); + + *ret = buf; + + return 0; +} + +size_t table_get_rows(Table *t) { + if (!t) + return 0; + + assert(t->n_columns > 0); + return t->n_cells / t->n_columns; +} + +size_t table_get_columns(Table *t) { + if (!t) + return 0; + + assert(t->n_columns > 0); + return t->n_columns; +} diff --git a/src/basic/format-table.h b/src/basic/format-table.h new file mode 100644 index 0000000000..6dc2d16052 --- /dev/null +++ b/src/basic/format-table.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdbool.h> +#include <stdio.h> +#include <sys/types.h> + +#include "macro.h" + +typedef enum TableDataType { + TABLE_EMPTY, + TABLE_STRING, + TABLE_BOOLEAN, + TABLE_TIMESTAMP, + TABLE_TIMESPAN, + TABLE_SIZE, + TABLE_UINT32, + _TABLE_DATA_TYPE_MAX, + _TABLE_DATA_TYPE_INVALID = -1, +} TableDataType; + +typedef struct Table Table; +typedef struct TableCell TableCell; + +Table *table_new_internal(const char *first_header, ...) _sentinel_; +#define table_new(...) table_new_internal(__VA_ARGS__, NULL) +Table *table_new_raw(size_t n_columns); +Table *table_unref(Table *t); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Table*, table_unref); + +int table_add_cell_full(Table *t, TableCell **ret_cell, TableDataType type, const void *data, size_t minimum_width, size_t maximum_width, unsigned weight, unsigned align_percent, unsigned ellipsize_percent); +static inline int table_add_cell(Table *t, TableCell **ret_cell, TableDataType type, const void *data) { + return table_add_cell_full(t, ret_cell, type, data, (size_t) -1, (size_t) -1, (unsigned) -1, (unsigned) -1, (unsigned) -1); +} + +int table_dup_cell(Table *t, TableCell *cell); + +int table_set_minimum_width(Table *t, TableCell *cell, size_t minimum_width); +int table_set_maximum_width(Table *t, TableCell *cell, size_t maximum_width); +int table_set_weight(Table *t, TableCell *cell, unsigned weight); +int table_set_align_percent(Table *t, TableCell *cell, unsigned percent); +int table_set_ellipsize_percent(Table *t, TableCell *cell, unsigned percent); +int table_set_color(Table *t, TableCell *cell, const char *color); + +int table_add_many_internal(Table *t, TableDataType first_type, ...); +#define table_add_many(t, ...) table_add_many_internal(t, __VA_ARGS__, _TABLE_DATA_TYPE_MAX) + +void table_set_header(Table *table, bool b); +void table_set_width(Table *t, size_t width); +int table_set_display(Table *t, size_t first_column, ...); +int table_set_sort(Table *t, size_t first_column, ...); + +int table_print(Table *t, FILE *f); +int table_format(Table *t, char **ret); + +static inline TableCell* TABLE_HEADER_CELL(size_t i) { + return SIZE_TO_PTR(i + 1); +} + +size_t table_get_rows(Table *t); +size_t table_get_columns(Table *t); diff --git a/src/basic/format-util.h b/src/basic/format-util.h index d9a78f7811..160550cd68 100644 --- a/src/basic/format-util.h +++ b/src/basic/format-util.h @@ -1,24 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2015 Ronny Chevalier - - 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 <inttypes.h> diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 85c8070a1b..3a8b32d881 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <stddef.h> @@ -243,6 +225,22 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { return 0; } +int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != MODE_INVALID) + if (fchmod(fd, mode) < 0) + return -errno; + + if (uid != UID_INVALID || gid != GID_INVALID) + if (fchown(fd, uid, gid) < 0) + return -errno; + + return 0; +} + int fchmod_umask(int fd, mode_t m) { mode_t u; int r; @@ -254,6 +252,21 @@ int fchmod_umask(int fd, mode_t m) { return r; } +int fchmod_opath(int fd, mode_t m) { + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + /* This function operates also on fd that might have been opened with + * O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like + * fchownat() does. */ + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + + if (chmod(procfs_path, m) < 0) + return -errno; + + return 0; +} + int fd_warn_permissions(const char *path, int fd) { struct stat st; @@ -458,10 +471,8 @@ int get_files_in_directory(const char *path, char ***list) { n++; } - if (list) { - *list = l; - l = NULL; /* avoid freeing */ - } + if (list) + *list = TAKE_PTR(l); return n; } @@ -593,7 +604,7 @@ static bool safe_transition(const struct stat *a, const struct stat *b) { int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) { _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL; _cleanup_close_ int fd = -1; - unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */ + unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */ struct stat previous_stat; bool exists = true; char *todo; @@ -602,7 +613,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, assert(path); /* Either the file may be missing, or we return an fd to the final object, but both make no sense */ - if ((flags & (CHASE_NONEXISTENT|CHASE_OPEN)) == (CHASE_NONEXISTENT|CHASE_OPEN)) + if (FLAGS_SET(flags, CHASE_NONEXISTENT | CHASE_OPEN)) + return -EINVAL; + + if (FLAGS_SET(flags, CHASE_STEP | CHASE_OPEN)) return -EINVAL; if (isempty(path)) @@ -626,12 +640,43 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this * function what to do when encountering a symlink with an absolute path as directory: prefix it by the - * specified path. */ + * specified path. + * + * There are three ways to invoke this function: + * + * 1. Without CHASE_STEP or CHASE_OPEN: in this case the path is resolved and the normalized path is returned + * in `ret`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set 0 is returned if the file + * doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set >= 0 is returned if the destination was + * found, -ENOENT if it doesn't. + * + * 2. With CHASE_OPEN: in this case the destination is opened after chasing it as O_PATH and this file + * descriptor is returned as return value. This is useful to open files relative to some root + * directory. Note that the returned O_PATH file descriptors must be converted into a regular one (using + * fd_reopen() or such) before it can be used for reading/writing. CHASE_OPEN may not be combined with + * CHASE_NONEXISTENT. + * + * 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first + * symlink or ".." component of the path is resolved, and the resulting path is returned. This is useful if + * a caller wants to trace the a path through the file system verbosely. Returns < 0 on error, > 0 if the + * path is fully normalized, and == 0 for each normalization step. This may be combined with + * CHASE_NONEXISTENT, in which case 1 is returned when a component is not found. + * + * */ /* A root directory of "/" or "" is identical to none */ - if (isempty(original_root) || path_equal(original_root, "/")) + if (empty_or_root(original_root)) original_root = NULL; + if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN|CHASE_STEP)) == CHASE_OPEN) { + /* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set + * and doesn't care about any of the other special features we provide either. */ + r = open(path, O_PATH|O_CLOEXEC); + if (r < 0) + return -errno; + + return r; + } + if (original_root) { r = path_make_absolute_cwd(original_root, &root); if (r < 0) @@ -685,8 +730,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, /* Just a single slash? Then we reached the end. */ if (path_equal(first, "/")) { /* Preserve the trailing slash */ - if (!strextend(&done, "/", NULL)) - return -ENOMEM; + + if (flags & CHASE_TRAIL_SLASH) + if (!strextend(&done, "/", NULL)) + return -ENOMEM; break; } @@ -702,7 +749,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, /* If we already are at the top, then going up will not change anything. This is in-line with * how the kernel handles this. */ - if (isempty(done) || path_equal(done, "/")) + if (empty_or_root(done)) continue; parent = dirname_malloc(done); @@ -717,6 +764,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, free_and_replace(done, parent); + if (flags & CHASE_STEP) + goto chased_one; + fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH); if (fd_parent < 0) return -errno; @@ -732,8 +782,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, } safe_close(fd); - fd = fd_parent; - fd_parent = -1; + fd = TAKE_FD(fd_parent); continue; } @@ -834,14 +883,16 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, free(buffer); todo = buffer = joined; + if (flags & CHASE_STEP) + goto chased_one; + continue; } /* If this is not a symlink, then let's just add the name we read to what we already verified. */ - if (!done) { - done = first; - first = NULL; - } else { + if (!done) + done = TAKE_PTR(first); + else { /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ if (streq(done, "/")) *done = '\0'; @@ -852,8 +903,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, /* And iterate again, but go one directory further down. */ safe_close(fd); - fd = child; - child = -1; + fd = TAKE_FD(child); } if (!done) { @@ -863,25 +913,154 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - if (ret) { - *ret = done; - done = NULL; - } + if (ret) + *ret = TAKE_PTR(done); if (flags & CHASE_OPEN) { - int q; - /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by * opening /proc/self/fd/xyz. */ assert(fd >= 0); - q = fd; - fd = -1; - - return q; + return TAKE_FD(fd); } + if (flags & CHASE_STEP) + return 1; + return exists; + +chased_one: + if (ret) { + char *c; + + c = strjoin(strempty(done), todo); + if (!c) + return -ENOMEM; + + *ret = c; + } + + return 0; +} + +int chase_symlinks_and_open( + const char *path, + const char *root, + unsigned chase_flags, + int open_flags, + char **ret_path) { + + _cleanup_close_ int path_fd = -1; + _cleanup_free_ char *p = NULL; + int r; + + if (chase_flags & CHASE_NONEXISTENT) + return -EINVAL; + + if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { + /* Shortcut this call if none of the special features of this call are requested */ + r = open(path, open_flags); + if (r < 0) + return -errno; + + return r; + } + + path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); + if (path_fd < 0) + return path_fd; + + r = fd_reopen(path_fd, open_flags); + if (r < 0) + return r; + + if (ret_path) + *ret_path = TAKE_PTR(p); + + return r; +} + +int chase_symlinks_and_opendir( + const char *path, + const char *root, + unsigned chase_flags, + char **ret_path, + DIR **ret_dir) { + + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_ int path_fd = -1; + _cleanup_free_ char *p = NULL; + DIR *d; + + if (!ret_dir) + return -EINVAL; + if (chase_flags & CHASE_NONEXISTENT) + return -EINVAL; + + if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { + /* Shortcut this call if none of the special features of this call are requested */ + d = opendir(path); + if (!d) + return -errno; + + *ret_dir = d; + return 0; + } + + path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); + if (path_fd < 0) + return path_fd; + + xsprintf(procfs_path, "/proc/self/fd/%i", path_fd); + d = opendir(procfs_path); + if (!d) + return -errno; + + if (ret_path) + *ret_path = TAKE_PTR(p); + + *ret_dir = d; + return 0; +} + +int chase_symlinks_and_stat( + const char *path, + const char *root, + unsigned chase_flags, + char **ret_path, + struct stat *ret_stat) { + + _cleanup_close_ int path_fd = -1; + _cleanup_free_ char *p = NULL; + + assert(path); + assert(ret_stat); + + if (chase_flags & CHASE_NONEXISTENT) + return -EINVAL; + + if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { + /* Shortcut this call if none of the special features of this call are requested */ + if (stat(path, ret_stat) < 0) + return -errno; + + return 1; + } + + path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); + if (path_fd < 0) + return path_fd; + + if (fstat(path_fd, ret_stat) < 0) + return -errno; + + if (ret_path) + *ret_path = TAKE_PTR(p); + + if (chase_flags & CHASE_OPEN) + return TAKE_FD(path_fd); + + return 1; } int access_fd(int fd, int mode) { @@ -891,14 +1070,22 @@ int access_fd(int fd, int mode) { /* Like access() but operates on an already open fd */ xsprintf(p, "/proc/self/fd/%i", fd); - r = access(p, mode); if (r < 0) - r = -errno; + return -errno; return r; } +void unlink_tempfilep(char (*p)[]) { + /* If the file is created with mkstemp(), it will (almost always) + * change the suffix. Treat this as a sign that the file was + * successfully created. We ignore both the rare case where the + * original suffix is used and unlink failures. */ + if (!endswith(*p, ".XXXXXX")) + (void) unlink_noerrno(*p); +} + int unlinkat_deallocate(int fd, const char *name, int flags) { _cleanup_close_ int truncate_fd = -1; struct stat st; @@ -978,8 +1165,19 @@ int fsync_directory_of_file(int fd) { return r; r = fd_get_path(fd, &path); - if (r < 0) + if (r < 0) { + log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m", + fd, + r == -EOPNOTSUPP ? ", ignoring" : ""); + + if (r == -EOPNOTSUPP) + /* If /proc is not available, we're most likely running in some + * chroot environment, and syncing the directory is not very + * important in that case. Let's just silently do nothing. */ + return 0; + return r; + } if (!path_is_absolute(path)) return -EINVAL; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 82d7e765b3..28566773c6 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -1,25 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <fcntl.h> #include <limits.h> #include <stdbool.h> @@ -43,8 +25,10 @@ int readlink_value(const char *p, char **ret); int readlink_and_make_absolute(const char *p, char **r); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); +int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid); int fchmod_umask(int fd, mode_t mode); +int fchmod_opath(int fd, mode_t m); int fd_warn_permissions(const char *path, int fd); @@ -81,15 +65,24 @@ union inotify_event_buffer { int inotify_add_watch_fd(int fd, int what, uint32_t mask); enum { - CHASE_PREFIX_ROOT = 1U << 0, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */ - CHASE_NONEXISTENT = 1U << 1, /* If set, it's OK if the path doesn't actually exist. */ - CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */ - CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */ - CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */ + CHASE_PREFIX_ROOT = 1 << 0, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */ + CHASE_NONEXISTENT = 1 << 1, /* If set, it's OK if the path doesn't actually exist. */ + CHASE_NO_AUTOFS = 1 << 2, /* If set, return -EREMOTE if autofs mount point found */ + CHASE_SAFE = 1 << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */ + CHASE_OPEN = 1 << 4, /* If set, return an O_PATH object to the final component */ + CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */ + CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */ }; +/* How many iterations to execute before returning -ELOOP */ +#define CHASE_SYMLINKS_MAX 32 + int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret); +int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path); +int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir); +int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat); + /* Useful for usage with _cleanup_(), removes a directory and frees the pointer */ static inline void rmdir_and_free(char *p) { PROTECT_ERRNO; @@ -106,6 +99,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free); int access_fd(int fd, int mode); +void unlink_tempfilep(char (*p)[]); int unlinkat_deallocate(int fd, const char *name, int flags); int fsync_directory_of_file(int fd); diff --git a/src/basic/gcrypt-util.c b/src/basic/gcrypt-util.c index 34d0d399b7..f304a2bab6 100644 --- a/src/basic/gcrypt-util.c +++ b/src/basic/gcrypt-util.c @@ -1,24 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - 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/>. -***/ #if HAVE_GCRYPT #include <gcrypt.h> diff --git a/src/basic/gcrypt-util.h b/src/basic/gcrypt-util.h index 714cae673b..87eb606891 100644 --- a/src/basic/gcrypt-util.h +++ b/src/basic/gcrypt-util.h @@ -1,24 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2016 Zbigniew Jędrzejewski-Szmek - - 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/>. -***/ #pragma once diff --git a/src/basic/generate-af-list.sh b/src/basic/generate-af-list.sh index fa74198e58..39e2dad5e7 100755 --- a/src/basic/generate-af-list.sh +++ b/src/basic/generate-af-list.sh @@ -3,4 +3,4 @@ set -eu $1 -E -dM -include sys/socket.h - </dev/null | \ grep -Ev 'AF_UNSPEC|AF_MAX' | \ - awk '/^#define[ \t]+AF_[^ \t]+[ \t]+PF_[^ \t]/ { print $2; }' + awk '/^#define[ \t]+AF_[^ \t]+[ \t]+[AP]F_[^ \t]/ { print $2; }' diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c index 4ac56c91d0..9fac676f2b 100644 --- a/src/basic/glob-util.c +++ b/src/basic/glob-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <dirent.h> #include <errno.h> diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h index 911e6d2c1a..8e226c1ee2 100644 --- a/src/basic/glob-util.h +++ b/src/basic/glob-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <glob.h> #include <stdbool.h> #include <string.h> diff --git a/src/basic/gunicode.c b/src/basic/gunicode.c index 8aff4a0fc5..c51b1a7a18 100644 --- a/src/basic/gunicode.c +++ b/src/basic/gunicode.c @@ -1,7 +1,7 @@ /* gunicode.c - Unicode manipulation functions * * Copyright (C) 1999, 2000 Tom Tromey - * Copyright 2000, 2005 Red Hat, Inc. + * Copyright © 2000, 2005 Red Hat, Inc. */ #include "gunicode.h" diff --git a/src/basic/gunicode.h b/src/basic/gunicode.h index 5975bc8fc9..a16b7b6ff1 100644 --- a/src/basic/gunicode.h +++ b/src/basic/gunicode.h @@ -3,7 +3,7 @@ /* gunicode.h - Unicode manipulation functions * * Copyright (C) 1999, 2000 Tom Tromey - * Copyright 2000, 2005 Red Hat, Inc. + * Copyright © 2000, 2005 Red Hat, Inc. */ #include <stdbool.h> diff --git a/src/basic/hash-funcs.c b/src/basic/hash-funcs.c index 947bcfd584..db48437be7 100644 --- a/src/basic/hash-funcs.c +++ b/src/basic/hash-funcs.c @@ -1,23 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - 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 <string.h> @@ -37,7 +18,6 @@ const struct hash_ops string_hash_ops = { .compare = string_compare_func }; - void path_hash_func(const void *p, struct siphash *state) { const char *q = p; size_t n; diff --git a/src/basic/hash-funcs.h b/src/basic/hash-funcs.h index 945b4c251c..5e5989f021 100644 --- a/src/basic/hash-funcs.h +++ b/src/basic/hash-funcs.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #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" diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index d0873f7ae5..69a7d70b04 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -1,23 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - 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 <errno.h> #include <stdint.h> @@ -294,7 +275,7 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { }, }; -#ifdef VALGRIND +#if VALGRIND __attribute__((destructor)) static void cleanup_pools(void) { _cleanup_free_ char *t = NULL; int r; diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index b674910397..5c70c102d7 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #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 <limits.h> #include <stdbool.h> diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index fe7e4954ef..7748e8352c 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <ctype.h> #include <errno.h> @@ -90,33 +72,69 @@ char *hexmem(const void *p, size_t l) { return r; } -int unhexmem(const char *p, size_t l, void **mem, size_t *len) { - _cleanup_free_ uint8_t *r = NULL; - uint8_t *z; +static int unhex_next(const char **p, size_t *l) { + int r; + + assert(p); + assert(l); + + /* Find the next non-whitespace character, and decode it. We + * greedily skip all preceeding and all following whitespace. */ + + for (;;) { + if (*l == 0) + return -EPIPE; + + if (!strchr(WHITESPACE, **p)) + break; + + /* Skip leading whitespace */ + (*p)++, (*l)--; + } + + r = unhexchar(**p); + if (r < 0) + return r; + + for (;;) { + (*p)++, (*l)--; + + if (*l == 0 || !strchr(WHITESPACE, **p)) + break; + + /* Skip following whitespace */ + } + + return r; +} + +int unhexmem(const char *p, size_t l, void **ret, size_t *ret_len) { + _cleanup_free_ uint8_t *buf = NULL; const char *x; + uint8_t *z; - assert(mem); - assert(len); + assert(ret); + assert(ret_len); assert(p || l == 0); if (l == (size_t) -1) l = strlen(p); - if (l % 2 != 0) - return -EINVAL; - - z = r = malloc((l + 1) / 2 + 1); - if (!r) + /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */ + buf = malloc((l + 1) / 2 + 1); + if (!buf) return -ENOMEM; - for (x = p; x < p + l; x += 2) { + for (x = p, z = buf;;) { int a, b; - a = unhexchar(x[0]); + a = unhex_next(&x, &l); + if (a == -EPIPE) /* End of string */ + break; if (a < 0) return a; - b = unhexchar(x[1]); + b = unhex_next(&x, &l); if (b < 0) return b; @@ -125,9 +143,8 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) { *z = 0; - *mem = r; - r = NULL; - *len = (l + 1) / 2; + *ret_len = (size_t) (z - buf); + *ret = TAKE_PTR(buf); return 0; } @@ -195,7 +212,7 @@ char *base32hexmem(const void *p, size_t l, bool padding) { for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ - x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ + * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ @@ -295,7 +312,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l } /* a group of eight input bytes needs five output bytes, in case of - padding we need to add some extra bytes */ + * padding we need to add some extra bytes */ len = (l / 8) * 5; switch (l % 8) { @@ -323,7 +340,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l for (x = p; x < p + (l / 8) * 8; x += 8) { /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW - e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ + * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ a = unbase32hexchar(x[0]); if (a < 0) return -EINVAL; @@ -482,8 +499,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l *z = 0; - *mem = r; - r = NULL; + *mem = TAKE_PTR(r); *_len = len; return 0; @@ -583,7 +599,7 @@ static int base64_append_width( if (len <= 0) return len; - lines = (len + width - 1) / width; + lines = DIV_ROUND_UP(len, width); slen = strlen_ptr(sep); t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines); @@ -680,7 +696,7 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) { l = strlen(p); /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra - bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */ + * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */ len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0); buf = malloc(len + 1); @@ -748,11 +764,8 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) { *z = 0; - if (ret_size) - *ret_size = (size_t) (z - buf); - - *ret = buf; - buf = NULL; + *ret_size = (size_t) (z - buf); + *ret = TAKE_PTR(buf); return 0; } diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h index 08d0a52276..9477d16e37 100644 --- a/src/basic/hexdecoct.h +++ b/src/basic/hexdecoct.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <stddef.h> #include <stdio.h> diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index b59e5425a5..09fabe077b 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2015 Lennart Poettering - - 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 <errno.h> #include <limits.h> diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index edae52e3db..749481723d 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2015 Lennart Poettering - - 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 <stdbool.h> #include <stdio.h> diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 572e172b33..aed7601d50 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <arpa/inet.h> #include <endian.h> diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index acaae6d287..956c00a850 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <netinet/in.h> #include <stddef.h> #include <sys/socket.h> diff --git a/src/basic/io-util.c b/src/basic/io-util.c index a6e34cb762..1f64cc933b 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <limits.h> diff --git a/src/basic/io-util.h b/src/basic/io-util.h index d81610ad21..ed189b5820 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <stddef.h> #include <stdint.h> @@ -41,9 +22,8 @@ int fd_wait_for_event(int fd, int event, usec_t timeout); ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; +static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, size_t n) { + size_t j, r = 0; for (j = 0; j < n; j++) r += i[j].iov_len; @@ -51,8 +31,8 @@ static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { return r; } -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; +static inline size_t IOVEC_INCREMENT(struct iovec *i, size_t n, size_t k) { + size_t j; for (j = 0; j < n; j++) { size_t sub; diff --git a/src/basic/ioprio.h b/src/basic/ioprio.h index d8bb6eb497..3fb168dafe 100644 --- a/src/basic/ioprio.h +++ b/src/basic/ioprio.h @@ -10,8 +10,9 @@ /* * Gives us 8 prio classes with 13-bits of data for each class */ -#define IOPRIO_BITS (16) -#define IOPRIO_CLASS_SHIFT (13) +#define IOPRIO_BITS 16 +#define IOPRIO_N_CLASSES 8 +#define IOPRIO_CLASS_SHIFT 13 #define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) #define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) diff --git a/src/basic/journal-importer.c b/src/basic/journal-importer.c index 11054589e3..ca203bbbfc 100644 --- a/src/basic/journal-importer.c +++ b/src/basic/journal-importer.c @@ -1,30 +1,15 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Zbigniew Jędrzejewski-Szmek - - 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 <errno.h> #include <unistd.h> #include "alloc-util.h" +#include "escape.h" #include "fd-util.h" #include "io-util.h" +#include "journal-file.h" #include "journal-importer.h" +#include "journal-util.h" #include "parse-util.h" #include "string-util.h" #include "unaligned.h" @@ -245,56 +230,78 @@ static int get_data_newline(JournalImporter *imp) { assert(data); if (*data != '\n') { - log_error("expected newline, got '%c'", *data); + char buf[4]; + int l; + + l = cescape_char(*data, buf); + log_error("Expected newline, got '%.*s'", l, buf); return -EINVAL; } return 1; } -static int process_dunder(JournalImporter *imp, char *line, size_t n) { - const char *timestamp; +static int process_special_field(JournalImporter *imp, char *line) { + const char *value; + char buf[CELLESCAPE_DEFAULT_LENGTH]; int r; assert(line); - assert(n > 0); - assert(line[n-1] == '\n'); - - /* XXX: is it worth to support timestamps in extended format? - * We don't produce them, but who knows... */ - timestamp = startswith(line, "__CURSOR="); - if (timestamp) + value = startswith(line, "__CURSOR="); + if (value) /* ignore __CURSOR */ return 1; - timestamp = startswith(line, "__REALTIME_TIMESTAMP="); - if (timestamp) { - long long unsigned x; - line[n-1] = '\0'; - r = safe_atollu(timestamp, &x); + value = startswith(line, "__REALTIME_TIMESTAMP="); + if (value) { + uint64_t x; + + r = safe_atou64(value, &x); if (r < 0) - log_warning("Failed to parse __REALTIME_TIMESTAMP: '%s'", timestamp); - else - imp->ts.realtime = x; - return r < 0 ? r : 1; + return log_warning_errno(r, "Failed to parse __REALTIME_TIMESTAMP '%s': %m", + cellescape(buf, sizeof buf, value)); + else if (!VALID_REALTIME(x)) { + log_warning("__REALTIME_TIMESTAMP out of range, ignoring: %"PRIu64, x); + return -ERANGE; + } + + imp->ts.realtime = x; + return 1; } - timestamp = startswith(line, "__MONOTONIC_TIMESTAMP="); - if (timestamp) { - long long unsigned x; - line[n-1] = '\0'; - r = safe_atollu(timestamp, &x); + value = startswith(line, "__MONOTONIC_TIMESTAMP="); + if (value) { + uint64_t x; + + r = safe_atou64(value, &x); if (r < 0) - log_warning("Failed to parse __MONOTONIC_TIMESTAMP: '%s'", timestamp); - else - imp->ts.monotonic = x; - return r < 0 ? r : 1; + return log_warning_errno(r, "Failed to parse __MONOTONIC_TIMESTAMP '%s': %m", + cellescape(buf, sizeof buf, value)); + else if (!VALID_MONOTONIC(x)) { + log_warning("__MONOTONIC_TIMESTAMP out of range, ignoring: %"PRIu64, x); + return -ERANGE; + } + + imp->ts.monotonic = x; + return 1; + } + + /* Just a single underline, but it needs special treatment too. */ + value = startswith(line, "_BOOT_ID="); + if (value) { + r = sd_id128_from_string(value, &imp->boot_id); + if (r < 0) + return log_warning_errno(r, "Failed to parse _BOOT_ID '%s': %m", + cellescape(buf, sizeof buf, value)); + + /* store the field in the usual fashion too */ + return 0; } - timestamp = startswith(line, "__"); - if (timestamp) { - log_notice("Unknown dunder line %s", line); + value = startswith(line, "__"); + if (value) { + log_notice("Unknown dunder line __%s, ignoring.", cellescape(buf, sizeof buf, value)); return 1; } @@ -327,10 +334,6 @@ int journal_importer_process_data(JournalImporter *imp) { return 1; } - r = process_dunder(imp, line, n); - if (r != 0) - return r < 0 ? r : 0; - /* MESSAGE=xxx\n or COREDUMP\n @@ -341,6 +344,21 @@ int journal_importer_process_data(JournalImporter *imp) { /* chomp newline */ n--; + if (!journal_field_valid(line, sep - line, true)) { + char buf[64], *t; + + t = strndupa(line, sep - line); + log_debug("Ignoring invalid field: \"%s\"", + cellescape(buf, sizeof buf, t)); + + return 0; + } + + line[n] = '\0'; + r = process_special_field(imp, line); + if (r != 0) + return r < 0 ? r : 0; + r = iovw_put(&imp->iovw, line, n); if (r < 0) return r; diff --git a/src/basic/journal-importer.h b/src/basic/journal-importer.h index d11caa2396..f49ce734a1 100644 --- a/src/basic/journal-importer.h +++ b/src/basic/journal-importer.h @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2016 Zbigniew Jędrzejewski-Szmek - - 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/>. -***/ #pragma once @@ -24,6 +6,8 @@ #include <stdbool.h> #include <sys/uio.h> +#include "sd-id128.h" + #include "time-util.h" /* Make sure not to make this smaller than the maximum coredump size. @@ -58,6 +42,7 @@ typedef struct JournalImporter { int state; dual_timestamp ts; + sd_id128_t boot_id; } JournalImporter; void journal_importer_cleanup(JournalImporter *); diff --git a/src/basic/khash.c b/src/basic/khash.c index 6463faf3e1..847f2572a6 100644 --- a/src/basic/khash.c +++ b/src/basic/khash.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2016 Lennart Poettering - - 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 <linux/if_alg.h> #include <stdbool.h> @@ -216,8 +198,7 @@ int khash_dup(khash *h, khash **ret) { if (copy->fd < 0) return -errno; - *ret = copy; - copy = NULL; + *ret = TAKE_PTR(copy); return 0; } diff --git a/src/basic/khash.h b/src/basic/khash.h index e9c41a3f20..a3013b9d61 100644 --- a/src/basic/khash.h +++ b/src/basic/khash.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2016 Lennart Poettering - - 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 <inttypes.h> #include <sys/types.h> #include <sys/uio.h> diff --git a/src/basic/label.c b/src/basic/label.c index 18c9a23fea..12a7fb0945 100644 --- a/src/basic/label.c +++ b/src/basic/label.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <sys/stat.h> @@ -28,11 +10,11 @@ #include "selinux-util.h" #include "smack-util.h" -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { +int label_fix(const char *path, LabelFixFlags flags) { int r, q; - r = mac_selinux_fix(path, ignore_enoent, ignore_erofs); - q = mac_smack_fix(path, ignore_enoent, ignore_erofs); + r = mac_selinux_fix(path, flags); + q = mac_smack_fix(path, flags); if (r < 0) return r; @@ -60,7 +42,7 @@ int symlink_label(const char *old_path, const char *new_path) { if (r < 0) return r; - return mac_smack_fix(new_path, false, false); + return mac_smack_fix(new_path, 0); } int btrfs_subvol_make_label(const char *path) { @@ -78,5 +60,5 @@ int btrfs_subvol_make_label(const char *path) { if (r < 0) return r; - return mac_smack_fix(path, false, false); + return mac_smack_fix(path, 0); } diff --git a/src/basic/label.h b/src/basic/label.h index d73dacec4f..08fd109bcf 100644 --- a/src/basic/label.h +++ b/src/basic/label.h @@ -1,29 +1,15 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <sys/types.h> -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs); +typedef enum LabelFixFlags { + LABEL_IGNORE_ENOENT = 1 << 0, + LABEL_IGNORE_EROFS = 1 << 1, +} LabelFixFlags; + +int label_fix(const char *path, LabelFixFlags flags); int mkdir_label(const char *path, mode_t mode); int symlink_label(const char *old_path, const char *new_path); diff --git a/src/basic/list.h b/src/basic/list.h index 7006c3e273..643e0bea88 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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/>. -***/ - /* The head of the linked list. Use this in the structure that shall * contain the head of the linked list */ #define LIST_HEAD(t,name) \ diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 266cb29936..3ad352f22f 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <dirent.h> #include <errno.h> @@ -84,7 +66,7 @@ static int add_locales_from_archive(Set *locales) { _cleanup_close_ int fd = -1; size_t sz = 0; struct stat st; - unsigned i; + size_t i; int r; fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC); @@ -196,8 +178,7 @@ int get_locales(char ***ret) { strv_sort(l); - *ret = l; - l = NULL; + *ret = TAKE_PTR(l); return 0; } @@ -320,7 +301,7 @@ int get_keymaps(char ***ret) { return -ENOMEM; NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { - r = nftw(dir, nftw_cb, 20, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); + r = nftw(dir, nftw_cb, 20, FTW_PHYS|FTW_ACTIONRETVAL); if (r == FTW_STOP) log_debug("Directory not found %s", dir); @@ -341,8 +322,7 @@ int get_keymaps(char ***ret) { strv_sort(l); - *ret = l; - l = NULL; + *ret = TAKE_PTR(l); return 0; } @@ -369,6 +349,13 @@ bool keymap_is_valid(const char *name) { const char *special_glyph(SpecialGlyph code) { + /* A list of a number of interesting unicode glyphs we can use to decorate our output. It's probably wise to be + * conservative here, and primarily stick to the glyphs defined in the eurlatgr font, so that display still + * works reasonably well on the Linux console. For details see: + * + * http://git.altlinux.org/people/legion/packages/kbd.git?p=kbd.git;a=blob;f=data/consolefonts/README.eurlatgr + */ + static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = { /* ASCII fallback */ [false] = { @@ -380,10 +367,11 @@ const char *special_glyph(SpecialGlyph code) { [BLACK_CIRCLE] = "*", [ARROW] = "->", [MDASH] = "-", + [ELLIPSIS] = "..." }, /* UTF-8 */ - [ true ] = { + [true] = { [TREE_VERTICAL] = "\342\224\202 ", /* │ */ [TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ [TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ @@ -392,6 +380,7 @@ const char *special_glyph(SpecialGlyph code) { [BLACK_CIRCLE] = "\342\227\217", /* ● */ [ARROW] = "\342\206\222", /* → */ [MDASH] = "\342\200\223", /* – */ + [ELLIPSIS] = "\342\200\246", /* … */ }, }; diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index f75dcbc3d1..775fe8bc72 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <libintl.h> #include <stdbool.h> #include <locale.h> @@ -66,6 +47,7 @@ typedef enum { BLACK_CIRCLE, ARROW, MDASH, + ELLIPSIS, _SPECIAL_GLYPH_MAX } SpecialGlyph; diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index f4761a9d55..4bae23b243 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> diff --git a/src/basic/lockfile-util.h b/src/basic/lockfile-util.h index 1e86ad7442..c2abd9956f 100644 --- a/src/basic/lockfile-util.h +++ b/src/basic/lockfile-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - 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 <stddef.h> #include "macro.h" @@ -35,6 +16,4 @@ int make_lock_file(const char *p, int operation, LockFile *ret); int make_lock_file_for(const char *p, int operation, LockFile *ret); void release_lock_file(LockFile *f); -#define _cleanup_release_lock_file_ _cleanup_(release_lock_file) - #define LOCK_FILE_INIT { .fd = -1, .path = NULL } diff --git a/src/basic/log.c b/src/basic/log.c index 7a7f2cbec1..48c094b548 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> @@ -354,8 +336,8 @@ static int write_to_console( char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2]; struct iovec iovec[6] = {}; - unsigned n = 0; bool highlight; + size_t n = 0; if (console_fd < 0) return 0; @@ -699,9 +681,8 @@ int log_internalv_realm( if (_likely_(LOG_PRI(level) > log_max_level[realm])) return -error; - /* Make sure that %m maps to the specified error */ - if (error != 0) - errno = error; + /* Make sure that %m maps to the specified error (or "Success"). */ + errno = error; (void) vsnprintf(buffer, sizeof buffer, format, ap); @@ -749,9 +730,8 @@ static int log_object_internalv( if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD])) return -error; - /* Make sure that %m maps to the specified error */ - if (error != 0) - errno = error; + /* Make sure that %m maps to the specified error (or "Success"). */ + errno = error; /* Prepend the object name before the message */ if (object) { @@ -814,7 +794,7 @@ static void log_assert( log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer); } -noreturn void log_assert_failed_realm( +_noreturn_ void log_assert_failed_realm( LogRealm realm, const char *text, const char *file, @@ -826,7 +806,7 @@ noreturn void log_assert_failed_realm( abort(); } -noreturn void log_assert_failed_unreachable_realm( +_noreturn_ void log_assert_failed_unreachable_realm( LogRealm realm, const char *text, const char *file, @@ -874,8 +854,7 @@ int log_format_iovec( * since vasprintf() leaves it afterwards at * an undefined location */ - if (error != 0) - errno = error; + errno = error; va_copy(aq, ap); r = vasprintf(&m, format, aq); @@ -976,8 +955,7 @@ int log_struct_internal( while (format) { va_list aq; - if (error != 0) - errno = error; + errno = error; va_copy(aq, ap); (void) vsnprintf(buf, sizeof buf, format, aq); @@ -1054,13 +1032,9 @@ int log_struct_iovec_internal( return -error; } - for (i = 0; i < n_input_iovec; i++) { - if (input_iovec[i].iov_len < STRLEN("MESSAGE=")) - continue; - - if (memcmp(input_iovec[i].iov_base, "MESSAGE=", STRLEN("MESSAGE=")) == 0) + for (i = 0; i < n_input_iovec; i++) + if (memory_startswith(input_iovec[i].iov_base, input_iovec[i].iov_len, "MESSAGE=")) break; - } if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */ return -error; @@ -1275,8 +1249,7 @@ int log_syntax_internal( if (log_target == LOG_TARGET_NULL) return -error; - if (error != 0) - errno = error; + errno = error; va_start(ap, format); (void) vsnprintf(buffer, sizeof buffer, format, ap); @@ -1348,3 +1321,20 @@ int log_emergency_level(void) { return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR; } + +int log_dup_console(void) { + int copy; + + /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful + * whenever we want to continue logging through the original fd, but want to rearrange stderr. */ + + if (console_fd >= 3) + return 0; + + copy = fcntl(console_fd, F_DUPFD_CLOEXEC, 3); + if (copy < 0) + return -errno; + + console_fd = copy; + return 0; +} diff --git a/src/basic/log.h b/src/basic/log.h index efcf0f1bfc..e1f5fd30cd 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdarg.h> #include <stdbool.h> #include <stdlib.h> @@ -186,7 +167,7 @@ int log_dump_internal( char *buffer); /* Logging for various assertions */ -noreturn void log_assert_failed_realm( +_noreturn_ void log_assert_failed_realm( LogRealm realm, const char *text, const char *file, @@ -195,7 +176,7 @@ noreturn void log_assert_failed_realm( #define log_assert_failed(text, ...) \ log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__) -noreturn void log_assert_failed_unreachable_realm( +_noreturn_ void log_assert_failed_unreachable_realm( LogRealm realm, const char *text, const char *file, @@ -258,7 +239,7 @@ int log_emergency_level(void); /* Structured logging */ #define log_struct_errno(level, error, ...) \ log_struct_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \ - error, __FILE__, __LINE__, __func__, __VA_ARGS__) + error, __FILE__, __LINE__, __func__, __VA_ARGS__, NULL) #define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__) #define log_struct_iovec_errno(level, error, iovec, n_iovec) \ @@ -297,6 +278,8 @@ void log_set_open_when_needed(bool b); * stderr, the console or kmsg */ void log_set_prohibit_ipc(bool b); +int log_dup_console(void); + int log_syntax_internal( const char *unit, int level, diff --git a/src/basic/login-util.c b/src/basic/login-util.c index af4539453a..085ccd0915 100644 --- a/src/basic/login-util.c +++ b/src/basic/login-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Zbigniew Jędrzejewski-Szmek - - 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 <string.h> diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 1c558bfe20..e1e62e12b7 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Zbigniew Jędrzejewski-Szmek - - 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 <stdbool.h> #include <unistd.h> diff --git a/src/basic/macro.h b/src/basic/macro.h index 89bdd852a9..d1365f7058 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <inttypes.h> #include <stdbool.h> #include <sys/param.h> @@ -53,6 +34,26 @@ #else #define _fallthrough_ #endif +/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc + * compiler versions */ +#ifndef _noreturn_ +#if __STDC_VERSION__ >= 201112L +#define _noreturn_ _Noreturn +#else +#define _noreturn_ __attribute__((noreturn)) +#endif +#endif + +#if !defined(HAS_FEATURE_MEMORY_SANITIZER) +# if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# define HAS_FEATURE_MEMORY_SANITIZER 1 +# endif +# endif +# if !defined(HAS_FEATURE_MEMORY_SANITIZER) +# define HAS_FEATURE_MEMORY_SANITIZER 0 +# endif +#endif /* Temporarily disable some warnings */ #define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \ @@ -343,13 +344,15 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { ({ \ typeof(x) _x_ = (x); \ unsigned ans = 1; \ - while (_x_ /= 10) \ + while ((_x_ /= 10) != 0) \ ans++; \ ans; \ }) #define SET_FLAG(v, flag, b) \ (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) +#define FLAGS_SET(v, flags) \ + (((v) & (flags)) == (flags)) #define CASE_F(X) case X: #define CASE_F_1(CASE, X) CASE_F(X) @@ -414,21 +417,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #endif #endif -/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc - * compiler versions */ -#ifndef noreturn -#if __STDC_VERSION__ >= 201112L -#define noreturn _Noreturn -#else -#define noreturn __attribute__((noreturn)) -#endif -#endif - #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ func(*p); \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ + } #include "log.h" diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index e7eb895462..f88f0fc80c 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> @@ -168,8 +150,5 @@ int memfd_new_and_map(const char *name, size_t sz, void **p) { if (r < 0) return r; - r = fd; - fd = -1; - - return r; + return TAKE_FD(fd); } diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 1d66c98cce..5ebb519931 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <inttypes.h> #include <stddef.h> #include <stdint.h> diff --git a/src/basic/mempool.c b/src/basic/mempool.c index 0da8e1f775..a5ec8a1020 100644 --- a/src/basic/mempool.c +++ b/src/basic/mempool.c @@ -1,23 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010-2014 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 <stdint.h> #include <stdlib.h> @@ -28,12 +9,12 @@ struct pool { struct pool *next; - unsigned n_tiles; - unsigned n_used; + size_t n_tiles; + size_t n_used; }; void* mempool_alloc_tile(struct mempool *mp) { - unsigned i; + size_t i; /* When a tile is released we add it to the list and simply * place the next pointer at its offset 0. */ @@ -51,8 +32,7 @@ void* mempool_alloc_tile(struct mempool *mp) { if (_unlikely_(!mp->first_pool) || _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) { - unsigned n; - size_t size; + size_t size, n; struct pool *p; n = mp->first_pool ? mp->first_pool->n_tiles : 0; @@ -90,7 +70,7 @@ void mempool_free_tile(struct mempool *mp, void *p) { mp->freelist = p; } -#ifdef VALGRIND +#if VALGRIND void mempool_drop(struct mempool *mp) { struct pool *p = mp->first_pool; diff --git a/src/basic/mempool.h b/src/basic/mempool.h index c9235c8361..2a41cb358c 100644 --- a/src/basic/mempool.h +++ b/src/basic/mempool.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2011-2014 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 <stddef.h> @@ -42,7 +23,6 @@ static struct mempool pool_name = { \ .at_least = alloc_at_least, \ } - -#ifdef VALGRIND +#if VALGRIND void mempool_drop(struct mempool *mp); #endif diff --git a/src/basic/meson.build b/src/basic/meson.build index c71599db7b..31625b1785 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -1,19 +1,4 @@ # SPDX-License-Identifier: LGPL-2.1+ -# -# Copyright 2017 Zbigniew Jędrzejewski-Szmek -# -# 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/>. basic_sources = files(''' MurmurHash2.c @@ -90,6 +75,8 @@ basic_sources = files(''' fileio-label.h fileio.c fileio.h + format-table.c + format-table.h format-util.h fs-util.c fs-util.h @@ -140,6 +127,10 @@ basic_sources = files(''' nss-util.h ordered-set.c ordered-set.h + pager.c + pager.h + os-util.c + os-util.h parse-util.c parse-util.h path-util.c @@ -172,7 +163,6 @@ basic_sources = files(''' securebits.h selinux-util.c selinux-util.h - set.c set.h sigbus.c sigbus.h @@ -312,6 +302,9 @@ foreach item : [['af', af_list_txt, 'af', ''], endforeach basic_sources += [missing_h] + generated_gperf_headers +basic_gcrypt_sources = files( + 'gcrypt-util.c', + 'gcrypt-util.h') libbasic = static_library( 'basic', @@ -329,8 +322,7 @@ libbasic = static_library( # unnecessary linking to libgcrypt. libbasic_gcrypt = static_library( 'basic-gcrypt', - 'gcrypt-util.c', - 'gcrypt-util.h', + basic_gcrypt_sources, include_directories : includes, dependencies : [libgcrypt], c_args : ['-fvisibility=default']) diff --git a/src/basic/missing.h b/src/basic/missing.h index 1cc3f08e48..71a07d0574 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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/>. -***/ - /* Missing glibc definitions to access certain kernel APIs */ #include <errno.h> @@ -342,7 +323,6 @@ struct btrfs_ioctl_search_header { __u32 len; }; - struct btrfs_ioctl_search_args { struct btrfs_ioctl_search_key key; char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; @@ -1058,6 +1038,10 @@ struct input_mask { #define RTAX_QUICKACK 15 #endif +#ifndef RTA_EXPIRES +#define RTA_EXPIRES 23 +#endif + #ifndef IPV6_UNICAST_IF #define IPV6_UNICAST_IF 76 #endif @@ -1066,6 +1050,10 @@ struct input_mask { #define IPV6_MIN_MTU 1280 #endif +#ifndef IPV4_MIN_MTU +#define IPV4_MIN_MTU 68 +#endif + #ifndef IFF_MULTI_QUEUE #define IFF_MULTI_QUEUE 0x100 #endif @@ -1413,4 +1401,11 @@ struct statx { #define AT_STATX_DONT_SYNC 0x4000 #endif +/* The maximum thread/process name length including trailing NUL byte. This mimics the kernel definition of the same + * name, which we need in userspace at various places but is not defined in userspace currently, neither under this + * name nor any other. */ +#ifndef TASK_COMM_LEN +#define TASK_COMM_LEN 16 +#endif + #include "missing_syscall.h" diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index 34b8956a12..93c60458bf 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -1,26 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2016 Zbigniew Jędrzejewski-Szmek - - 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/>. -***/ - /* Missing glibc definitions to access certain kernel APIs */ #include <sys/types.h> @@ -269,7 +249,6 @@ static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long i # define kcmp missing_kcmp #endif - /* ======================================================================= */ #if !HAVE_KEYCTL @@ -416,8 +395,14 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { #if !HAVE_STATX # ifndef __NR_statx -# if defined __i386__ +# if defined __aarch64__ || defined __arm__ +# define __NR_statx 397 +# elif defined __alpha__ +# define __NR_statx 522 +# elif defined __i386__ || defined __powerpc64__ # define __NR_statx 383 +# elif defined __sparc__ +# define __NR_statx 360 # elif defined __x86_64__ # define __NR_statx 332 # else diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c index 6f3a46f467..1d51e92e9a 100644 --- a/src/basic/mkdir-label.c +++ b/src/basic/mkdir-label.c @@ -1,23 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Kay Sievers - - 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 <stdio.h> #include <sys/stat.h> @@ -44,11 +25,11 @@ int mkdir_label(const char *path, mode_t mode) { if (r < 0) return r; - return mac_smack_fix(path, false, false); + return mac_smack_fix(path, 0); } -int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink) { - return mkdir_safe_internal(path, mode, uid, gid, follow_symlink, mkdir_label); +int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { + return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_label); } int mkdir_parents_label(const char *path, mode_t mode) { diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index de4746c867..6ab1b4422b 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <stdbool.h> @@ -29,9 +11,10 @@ #include "mkdir.h" #include "path-util.h" #include "stat-util.h" +#include "stdio-util.h" #include "user-util.h" -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink, mkdir_func_t _mkdir) { +int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir) { struct stat st; int r; @@ -46,26 +29,47 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, boo if (lstat(path, &st) < 0) return -errno; - if (follow_symlink && S_ISLNK(st.st_mode)) { + if ((flags & MKDIR_FOLLOW_SYMLINK) && S_ISLNK(st.st_mode)) { _cleanup_free_ char *p = NULL; r = chase_symlinks(path, NULL, CHASE_NONEXISTENT, &p); if (r < 0) return r; if (r == 0) - return mkdir_safe_internal(p, mode, uid, gid, false, _mkdir); + return mkdir_safe_internal(p, mode, uid, gid, + flags & ~MKDIR_FOLLOW_SYMLINK, + _mkdir); if (lstat(p, &st) < 0) return -errno; } + if (!S_ISDIR(st.st_mode)) { + log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, + "Path \"%s\" already exists and is not a directory, refusing.", path); + return -ENOTDIR; + } if ((st.st_mode & 0007) > (mode & 0007) || (st.st_mode & 0070) > (mode & 0070) || - (st.st_mode & 0700) > (mode & 0700) || - (uid != UID_INVALID && st.st_uid != uid) || - (gid != GID_INVALID && st.st_gid != gid) || - !S_ISDIR(st.st_mode)) + (st.st_mode & 0700) > (mode & 0700)) { + log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, + "Directory \"%s\" already exists, but has mode %04o that is too permissive (%04o was requested), refusing.", + path, st.st_mode & 0777, mode); + return -EEXIST; + } + if ((uid != UID_INVALID && st.st_uid != uid) || + (gid != GID_INVALID && st.st_gid != gid)) { + char u[DECIMAL_STR_MAX(uid_t)] = "-", g[DECIMAL_STR_MAX(gid_t)] = "-"; + + if (uid != UID_INVALID) + xsprintf(u, UID_FMT, uid); + if (gid != UID_INVALID) + xsprintf(g, GID_FMT, gid); + log_full(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, + "Directory \"%s\" already exists, but is owned by "UID_FMT":"GID_FMT" (%s:%s was requested), refusing.", + path, st.st_uid, st.st_gid, u, g); return -EEXIST; + } return 0; } @@ -76,8 +80,8 @@ int mkdir_errno_wrapper(const char *pathname, mode_t mode) { return 0; } -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink) { - return mkdir_safe_internal(path, mode, uid, gid, follow_symlink, mkdir_errno_wrapper); +int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) { + return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_errno_wrapper); } int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h index d6c2d579a3..8e83fb102b 100644 --- a/src/basic/mkdir.h +++ b/src/basic/mkdir.h @@ -1,40 +1,26 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Kay Sievers - - 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 <sys/types.h> +typedef enum MkdirFlags { + MKDIR_FOLLOW_SYMLINK = 1 << 0, + MKDIR_WARN_MODE = 1 << 1, +} MkdirFlags; + int mkdir_errno_wrapper(const char *pathname, mode_t mode); -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink); +int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags); int mkdir_parents(const char *path, mode_t mode); int mkdir_p(const char *path, mode_t mode); /* mandatory access control(MAC) versions */ -int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink); +int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags); int mkdir_parents_label(const char *path, mode_t mode); int mkdir_p_label(const char *path, mode_t mode); /* internally used */ typedef int (*mkdir_func_t)(const char *pathname, mode_t mode); -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink, mkdir_func_t _mkdir); +int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir); int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); diff --git a/src/basic/module-util.h b/src/basic/module-util.h index 07956dbffd..8fa121ed98 100644 --- a/src/basic/module-util.h +++ b/src/basic/module-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2017 Zbigniew Jędrzejewski-Szmek - - 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 <libkmod.h> #include "macro.h" diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 8151b3a4e4..ebe41a4c6c 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <stdio_ext.h> @@ -81,10 +63,8 @@ int name_to_handle_at_loop( if (name_to_handle_at(fd, path, h, &mnt_id, flags) >= 0) { - if (ret_handle) { - *ret_handle = h; - h = NULL; - } + if (ret_handle) + *ret_handle = TAKE_PTR(h); if (ret_mnt_id) *ret_mnt_id = mnt_id; @@ -296,7 +276,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) { * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we * look at needs to be /usr, not /. */ if (flags & AT_SYMLINK_FOLLOW) { - r = chase_symlinks(t, root, 0, &canonical); + r = chase_symlinks(t, root, CHASE_TRAIL_SLASH, &canonical); if (r < 0) return r; @@ -428,7 +408,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl if (!cleaned) return -ENOMEM; - path_kill_slashes(cleaned); + path_simplify(cleaned, false); done = set_new(&path_hash_ops); if (!done) @@ -715,24 +695,33 @@ int repeat_unmount(const char *path, int flags) { } const char* mode_to_inaccessible_node(mode_t mode) { - /* This function maps a node type to the correspondent inaccessible node type. - * Character and block inaccessible devices may not be created (because major=0 and minor=0), - * in such case we map character and block devices to the inaccessible node type socket. */ + /* This function maps a node type to a corresponding inaccessible file node. These nodes are created during + * early boot by PID 1. In some cases we lacked the privs to create the character and block devices (maybe + * because we run in an userns environment, or miss CAP_SYS_MKNOD, or run with a devices policy that excludes + * device nodes with major and minor of 0), but that's fine, in that case we use an AF_UNIX file node instead, + * which is not the same, but close enough for most uses. And most importantly, the kernel allows bind mounts + * from socket nodes to any non-directory file nodes, and that's the most important thing that matters. */ + switch(mode & S_IFMT) { case S_IFREG: return "/run/systemd/inaccessible/reg"; + case S_IFDIR: return "/run/systemd/inaccessible/dir"; + case S_IFCHR: if (access("/run/systemd/inaccessible/chr", F_OK) == 0) return "/run/systemd/inaccessible/chr"; return "/run/systemd/inaccessible/sock"; + case S_IFBLK: if (access("/run/systemd/inaccessible/blk", F_OK) == 0) return "/run/systemd/inaccessible/blk"; return "/run/systemd/inaccessible/sock"; + case S_IFIFO: return "/run/systemd/inaccessible/fifo"; + case S_IFSOCK: return "/run/systemd/inaccessible/sock"; } @@ -871,7 +860,6 @@ const char *mount_propagation_flags_to_string(unsigned long flags) { return NULL; } - int mount_propagation_flags_from_string(const char *name, unsigned long *ret) { if (isempty(name)) @@ -951,8 +939,7 @@ int mount_option_mangle( } *ret_mount_flags = mount_flags; - *ret_remaining_options = ret; - ret = NULL; + *ret_remaining_options = TAKE_PTR(ret); return 0; } diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index fea3e938a8..3cfea3bb20 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <fcntl.h> #include <mntent.h> #include <stdbool.h> diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h index 4fc676395f..2045175d1c 100644 --- a/src/basic/nss-util.h +++ b/src/basic/nss-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <grp.h> #include <netdb.h> #include <nss.h> @@ -116,8 +97,7 @@ enum nss_status _nss_##module##_gethostbyname_r( \ NULL, \ NULL); \ return ret; \ -} \ -struct __useless_struct_to_allow_trailing_semicolon__ +} #define NSS_GETHOSTBYADDR_FALLBACKS(module) \ enum nss_status _nss_##module##_gethostbyaddr_r( \ @@ -133,8 +113,7 @@ enum nss_status _nss_##module##_gethostbyaddr_r( \ buffer, buflen, \ errnop, h_errnop, \ NULL); \ -} \ -struct __useless_struct_to_allow_trailing_semicolon__ +} #define NSS_GETPW_PROTOTYPES(module) \ enum nss_status _nss_##module##_getpwnam_r( \ diff --git a/src/basic/ordered-set.c b/src/basic/ordered-set.c index afcf2dbd1d..ed9ba776a4 100644 --- a/src/basic/ordered-set.c +++ b/src/basic/ordered-set.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2016 Lennart Poettering - - 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 "ordered-set.h" #include "strv.h" diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h index c4dbd79249..e7c054d8e4 100644 --- a/src/basic/ordered-set.h +++ b/src/basic/ordered-set.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2015 Lennart Poettering - - 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 "hashmap.h" typedef struct OrderedSet OrderedSet; @@ -61,6 +42,14 @@ static inline bool ordered_set_iterate(OrderedSet *s, Iterator *i, void **value) return ordered_hashmap_iterate((OrderedHashmap*) s, i, value, NULL); } +static inline void* ordered_set_remove(OrderedSet *s, void *p) { + return ordered_hashmap_remove((OrderedHashmap*) s, p); +} + +static inline void* ordered_set_steal_first(OrderedSet *s) { + return ordered_hashmap_steal_first((OrderedHashmap*) s); +} + int ordered_set_consume(OrderedSet *s, void *p); int ordered_set_put_strdup(OrderedSet *s, const char *p); int ordered_set_put_strdupv(OrderedSet *s, char **l); diff --git a/src/basic/os-util.c b/src/basic/os-util.c new file mode 100644 index 0000000000..207594cef8 --- /dev/null +++ b/src/basic/os-util.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "os-util.h" +#include "strv.h" +#include "fileio.h" +#include "string-util.h" + +int path_is_os_tree(const char *path) { + int r; + + assert(path); + + /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir + * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from + * the case where just the os-release file is missing. */ + if (laccess(path, F_OK) < 0) + return -errno; + + /* We use {/etc|/usr/lib}/os-release as flag file if something is an OS */ + r = open_os_release(path, NULL, NULL); + if (r == -ENOENT) /* We got nothing */ + return 0; + if (r < 0) + return r; + + return 1; +} + +int open_os_release(const char *root, char **ret_path, int *ret_fd) { + _cleanup_free_ char *q = NULL; + const char *p; + int k; + + FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") { + k = chase_symlinks(p, root, CHASE_PREFIX_ROOT|(ret_fd ? CHASE_OPEN : 0), (ret_path ? &q : NULL)); + if (k != -ENOENT) + break; + } + if (k < 0) + return k; + + if (ret_fd) { + int real_fd; + + /* Convert the O_PATH fd into a proper, readable one */ + real_fd = fd_reopen(k, O_RDONLY|O_CLOEXEC|O_NOCTTY); + safe_close(k); + if (real_fd < 0) + return real_fd; + + *ret_fd = real_fd; + } + + if (ret_path) + *ret_path = TAKE_PTR(q); + + return 0; +} + +int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) { + _cleanup_free_ char *p = NULL; + _cleanup_close_ int fd = -1; + FILE *f; + int r; + + if (!ret_file) + return open_os_release(root, ret_path, NULL); + + r = open_os_release(root, ret_path ? &p : NULL, &fd); + if (r < 0) + return r; + + f = fdopen(fd, "re"); + if (!f) + return -errno; + fd = -1; + + *ret_file = f; + + if (ret_path) + *ret_path = TAKE_PTR(p); + + return 0; +} + +int parse_os_release(const char *root, ...) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; + va_list ap; + int r; + + r = fopen_os_release(root, &p, &f); + if (r < 0) + return r; + + va_start(ap, root); + r = parse_env_filev(f, p, NEWLINE, ap); + va_end(ap); + + return r; +} + +int load_os_release_pairs(const char *root, char ***ret) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; + int r; + + r = fopen_os_release(root, &p, &f); + if (r < 0) + return r; + + return load_env_file_pairs(f, p, NEWLINE, ret); +} diff --git a/src/basic/os-util.h b/src/basic/os-util.h new file mode 100644 index 0000000000..6b9e033941 --- /dev/null +++ b/src/basic/os-util.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdio.h> + +int path_is_os_tree(const char *path); + +int open_os_release(const char *root, char **ret_path, int *ret_fd); +int fopen_os_release(const char *root, char **ret_path, FILE **ret_file); + +int parse_os_release(const char *root, ...); +int load_os_release_pairs(const char *root, char ***ret); diff --git a/src/basic/pager.c b/src/basic/pager.c new file mode 100644 index 0000000000..f241261119 --- /dev/null +++ b/src/basic/pager.c @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <errno.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/prctl.h> +#include <unistd.h> + +#include "copy.h" +#include "fd-util.h" +#include "locale-util.h" +#include "log.h" +#include "macro.h" +#include "pager.h" +#include "process-util.h" +#include "signal-util.h" +#include "string-util.h" +#include "strv.h" +#include "terminal-util.h" + +static pid_t pager_pid = 0; + +static int stored_stdout = -1; +static int stored_stderr = -1; +static bool stdout_redirected = false; +static bool stderr_redirected = false; + +_noreturn_ static void pager_fallback(void) { + int r; + + r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, 0); + if (r < 0) { + log_error_errno(r, "Internal pager failed: %m"); + _exit(EXIT_FAILURE); + } + + _exit(EXIT_SUCCESS); +} + +int pager_open(bool no_pager, bool jump_to_end) { + _cleanup_close_pair_ int fd[2] = { -1, -1 }; + const char *pager; + int r; + + if (no_pager) + return 0; + + if (pager_pid > 0) + return 1; + + if (terminal_is_dumb()) + return 0; + + if (!is_main_thread()) + return -EPERM; + + pager = getenv("SYSTEMD_PAGER"); + if (!pager) + pager = getenv("PAGER"); + + /* If the pager is explicitly turned off, honour it */ + if (pager && STR_IN_SET(pager, "", "cat")) + return 0; + + /* Determine and cache number of columns/lines before we spawn the pager so that we get the value from the + * actual tty */ + (void) columns(); + (void) lines(); + + if (pipe2(fd, O_CLOEXEC) < 0) + return log_error_errno(errno, "Failed to create pager pipe: %m"); + + r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pager_pid); + if (r < 0) + return r; + if (r == 0) { + const char* less_opts, *less_charset; + + /* In the child start the pager */ + + (void) dup2(fd[0], STDIN_FILENO); + safe_close_pair(fd); + + /* Initialize a good set of less options */ + less_opts = getenv("SYSTEMD_LESS"); + if (!less_opts) + less_opts = "FRSXMK"; + if (jump_to_end) + less_opts = strjoina(less_opts, " +G"); + if (setenv("LESS", less_opts, 1) < 0) + _exit(EXIT_FAILURE); + + /* Initialize a good charset for less. This is + * particularly important if we output UTF-8 + * characters. */ + less_charset = getenv("SYSTEMD_LESSCHARSET"); + if (!less_charset && is_locale_utf8()) + less_charset = "utf-8"; + if (less_charset && + setenv("LESSCHARSET", less_charset, 1) < 0) + _exit(EXIT_FAILURE); + + if (pager) { + execlp(pager, pager, NULL); + execl("/bin/sh", "sh", "-c", pager, NULL); + } + + /* Debian's alternatives command for pagers is + * called 'pager'. Note that we do not call + * sensible-pagers here, since that is just a + * shell script that implements a logic that + * is similar to this one anyway, but is + * Debian-specific. */ + execlp("pager", "pager", NULL); + + execlp("less", "less", NULL); + execlp("more", "more", NULL); + + pager_fallback(); + /* not reached */ + } + + /* Return in the parent */ + stored_stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 3); + if (dup2(fd[1], STDOUT_FILENO) < 0) { + stored_stdout = safe_close(stored_stdout); + return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); + } + stdout_redirected = true; + + stored_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); + if (dup2(fd[1], STDERR_FILENO) < 0) { + stored_stderr = safe_close(stored_stderr); + return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); + } + stderr_redirected = true; + + return 1; +} + +void pager_close(void) { + + if (pager_pid <= 0) + return; + + /* Inform pager that we are done */ + (void) fflush(stdout); + if (stdout_redirected) + if (stored_stdout < 0 || dup2(stored_stdout, STDOUT_FILENO) < 0) + (void) close(STDOUT_FILENO); + stored_stdout = safe_close(stored_stdout); + (void) fflush(stderr); + if (stderr_redirected) + if (stored_stderr < 0 || dup2(stored_stderr, STDERR_FILENO) < 0) + (void) close(STDERR_FILENO); + stored_stderr = safe_close(stored_stderr); + stdout_redirected = stderr_redirected = false; + + (void) kill(pager_pid, SIGCONT); + (void) wait_for_terminate(pager_pid, NULL); + pager_pid = 0; +} + +bool pager_have(void) { + return pager_pid > 0; +} + +int show_man_page(const char *desc, bool null_stdio) { + const char *args[4] = { "man", NULL, NULL, NULL }; + char *e = NULL; + pid_t pid; + size_t k; + int r; + + k = strlen(desc); + + if (desc[k-1] == ')') + e = strrchr(desc, '('); + + if (e) { + char *page = NULL, *section = NULL; + + page = strndupa(desc, e - desc); + section = strndupa(e + 1, desc + k - e - 2); + + args[1] = section; + args[2] = page; + } else + args[1] = desc; + + r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0)|FORK_LOG, &pid); + if (r < 0) + return r; + if (r == 0) { + /* Child */ + execvp(args[0], (char**) args); + log_error_errno(errno, "Failed to execute man: %m"); + _exit(EXIT_FAILURE); + } + + return wait_for_terminate_and_check(NULL, pid, 0); +} diff --git a/src/basic/pager.h b/src/basic/pager.h new file mode 100644 index 0000000000..e0fd34af97 --- /dev/null +++ b/src/basic/pager.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdbool.h> + +#include "macro.h" + +int pager_open(bool no_pager, bool jump_to_end); +void pager_close(void); +bool pager_have(void) _pure_; + +int show_man_page(const char *page, bool null_stdio); diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index fa5b4a353a..6becf85878 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <inttypes.h> @@ -24,12 +6,14 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/socket.h> #include "alloc-util.h" #include "errno-list.h" #include "extract-word.h" #include "locale-util.h" #include "macro.h" +#include "missing.h" #include "parse-util.h" #include "process-util.h" #include "string-util.h" @@ -106,6 +90,30 @@ int parse_ifindex(const char *s, int *ret) { return 0; } +int parse_mtu(int family, const char *s, uint32_t *ret) { + uint64_t u; + size_t m; + int r; + + r = parse_size(s, 1024, &u); + if (r < 0) + return r; + + if (u > UINT32_MAX) + return -ERANGE; + + if (family == AF_INET6) + m = IPV6_MIN_MTU; /* This is 1280 */ + else + m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */ + + if (u < m) + return -ERANGE; + + *ret = (uint32_t) u; + return 0; +} + int parse_size(const char *t, uint64_t base, uint64_t *size) { /* Soo, sometimes we want to parse IEC binary suffixes, and @@ -324,8 +332,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) { return -EINVAL; *error = e; - *name = n; - n = NULL; + *name = TAKE_PTR(n); return 0; } @@ -371,12 +378,13 @@ finish: } -int safe_atou(const char *s, unsigned *ret_u) { +int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) { char *x = NULL; unsigned long l; assert(s); assert(ret_u); + assert(base <= 16); /* strtoul() is happy to parse negative values, and silently * converts them to unsigned values without generating an @@ -389,7 +397,7 @@ int safe_atou(const char *s, unsigned *ret_u) { s += strspn(s, WHITESPACE); errno = 0; - l = strtoul(s, &x, 0); + l = strtoul(s, &x, base); if (errno > 0) return -errno; if (!x || x == s || *x != 0) @@ -487,17 +495,18 @@ int safe_atou8(const char *s, uint8_t *ret) { return 0; } -int safe_atou16(const char *s, uint16_t *ret) { +int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) { char *x = NULL; unsigned long l; assert(s); assert(ret); + assert(base <= 16); s += strspn(s, WHITESPACE); errno = 0; - l = strtoul(s, &x, 0); + l = strtoul(s, &x, base); if (errno > 0) return -errno; if (!x || x == s || *x != 0) @@ -531,30 +540,6 @@ int safe_atoi16(const char *s, int16_t *ret) { return 0; } -int safe_atoux16(const char *s, uint16_t *ret) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret); - - s += strspn(s, WHITESPACE); - - errno = 0; - l = strtoul(s, &x, 16); - if (errno > 0) - return -errno; - if (!x || x == s || *x != 0) - return -EINVAL; - if (s[0] == '-') - return -ERANGE; - if ((unsigned long) (uint16_t) l != l) - return -ERANGE; - - *ret = (uint16_t) l; - return 0; -} - int safe_atod(const char *s, double *ret_d) { _cleanup_(freelocalep) locale_t loc = (locale_t) 0; char *x = NULL; @@ -642,6 +627,58 @@ int parse_percent(const char *p) { return v; } +int parse_permille_unbounded(const char *p) { + const char *pc, *pm, *dot, *n; + int r, q, v; + + pm = endswith(p, "‰"); + if (pm) { + n = strndupa(p, pm - p); + r = safe_atoi(n, &v); + if (r < 0) + return r; + } else { + pc = endswith(p, "%"); + if (!pc) + return -EINVAL; + + dot = memchr(p, '.', pc - p); + if (dot) { + if (dot + 2 != pc) + return -EINVAL; + if (dot[1] < '0' || dot[1] > '9') + return -EINVAL; + q = dot[1] - '0'; + n = strndupa(p, dot - p); + } else { + q = 0; + n = strndupa(p, pc - p); + } + r = safe_atoi(n, &v); + if (r < 0) + return r; + if (v > (INT_MAX - q) / 10) + return -ERANGE; + + v = v * 10 + q; + } + + if (v < 0) + return -ERANGE; + + return v; +} + +int parse_permille(const char *p) { + int v; + + v = parse_permille_unbounded(p); + if (v > 1000) + return -ERANGE; + + return v; +} + int parse_nice(const char *p, int *ret) { int n, r; @@ -686,3 +723,20 @@ int parse_dev(const char *s, dev_t *ret) { *ret = d; return 0; } + +int parse_oom_score_adjust(const char *s, int *ret) { + int r, v; + + assert(s); + assert(ret); + + r = safe_atoi(s, &v); + if (r < 0) + return r; + + if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX) + return -ERANGE; + + *ret = v; + return 0; +} diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 727422056a..f3267f4cfe 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <inttypes.h> #include <limits.h> #include <stddef.h> @@ -35,6 +16,7 @@ int parse_dev(const char *s, dev_t *ret); int parse_pid(const char *s, pid_t* ret_pid); int parse_mode(const char *s, mode_t *ret); int parse_ifindex(const char *s, int *ret); +int parse_mtu(int family, const char *s, uint32_t *ret); int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_range(const char *t, unsigned *lower, unsigned *upper); @@ -44,17 +26,29 @@ int parse_syscall_and_errno(const char *in, char **name, int *error); #define FORMAT_BYTES_MAX 8 char *format_bytes(char *buf, size_t l, uint64_t t); -int safe_atou(const char *s, unsigned *ret_u); +int safe_atou_full(const char *s, unsigned base, unsigned *ret_u); + +static inline int safe_atou(const char *s, unsigned *ret_u) { + return safe_atou_full(s, 0, ret_u); +} + int safe_atoi(const char *s, int *ret_i); int safe_atollu(const char *s, unsigned long long *ret_u); int safe_atolli(const char *s, long long int *ret_i); int safe_atou8(const char *s, uint8_t *ret); -int safe_atou16(const char *s, uint16_t *ret); -int safe_atoi16(const char *s, int16_t *ret); +int safe_atou16_full(const char *s, unsigned base, uint16_t *ret); + +static inline int safe_atou16(const char *s, uint16_t *ret) { + return safe_atou16_full(s, 0, ret); +} + +static inline int safe_atoux16(const char *s, uint16_t *ret) { + return safe_atou16_full(s, 16, ret); +} -int safe_atoux16(const char *s, uint16_t *ret); +int safe_atoi16(const char *s, int16_t *ret); static inline int safe_atou32(const char *s, uint32_t *ret_u) { assert_cc(sizeof(uint32_t) == sizeof(unsigned)); @@ -115,6 +109,11 @@ int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); int parse_percent_unbounded(const char *p); int parse_percent(const char *p); +int parse_permille_unbounded(const char *p); +int parse_permille(const char *p); + int parse_nice(const char *p, int *ret); int parse_ip_port(const char *s, uint16_t *ret); + +int parse_oom_score_adjust(const char *s, int *ret); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index df94629385..d214c72916 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 <errno.h> #include <limits.h> @@ -45,6 +27,7 @@ #include "string-util.h" #include "strv.h" #include "time-util.h" +#include "utf8.h" bool path_is_absolute(const char *p) { return p[0] == '/'; @@ -140,8 +123,8 @@ int path_make_absolute_cwd(const char *p, char **ret) { } int path_make_relative(const char *from_dir, const char *to_path, char **_r) { - char *r, *p; - unsigned n_parents; + char *f, *t, *r, *p; + unsigned n_parents = 0; assert(from_dir); assert(to_path); @@ -149,85 +132,81 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) { /* Strips the common part, and adds ".." elements as necessary. */ - if (!path_is_absolute(from_dir)) + if (!path_is_absolute(from_dir) || !path_is_absolute(to_path)) return -EINVAL; - if (!path_is_absolute(to_path)) - return -EINVAL; + f = strdupa(from_dir); + t = strdupa(to_path); + + path_simplify(f, true); + path_simplify(t, true); /* Skip the common part. */ for (;;) { size_t a, b; - from_dir += strspn(from_dir, "/"); - to_path += strspn(to_path, "/"); + f += *f == '/'; + t += *t == '/'; - if (!*from_dir) { - if (!*to_path) + if (!*f) { + if (!*t) /* from_dir equals to_path. */ r = strdup("."); else /* from_dir is a parent directory of to_path. */ - r = strdup(to_path); + r = strdup(t); if (!r) return -ENOMEM; - path_kill_slashes(r); - *_r = r; return 0; } - if (!*to_path) + if (!*t) break; - a = strcspn(from_dir, "/"); - b = strcspn(to_path, "/"); + a = strcspn(f, "/"); + b = strcspn(t, "/"); - if (a != b) + if (a != b || memcmp(f, t, a) != 0) break; - if (memcmp(from_dir, to_path, a) != 0) - break; - - from_dir += a; - to_path += b; + f += a; + t += b; } /* If we're here, then "from_dir" has one or more elements that need to * be replaced with "..". */ /* Count the number of necessary ".." elements. */ - for (n_parents = 0;;) { + for (; *f;) { size_t w; - from_dir += strspn(from_dir, "/"); - - if (!*from_dir) - break; - - w = strcspn(from_dir, "/"); + w = strcspn(f, "/"); /* If this includes ".." we can't do a simple series of "..", refuse */ - if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.') + if (w == 2 && f[0] == '.' && f[1] == '.') return -EINVAL; - /* Count number of elements, except if they are "." */ - if (w != 1 || from_dir[0] != '.') - n_parents++; + /* Count number of elements */ + n_parents++; - from_dir += w; + f += w; + f += *f == '/'; } - r = new(char, n_parents * 3 + strlen(to_path) + 1); + r = new(char, n_parents * 3 + strlen(t) + 1); if (!r) return -ENOMEM; for (p = r; n_parents > 0; n_parents--) p = mempcpy(p, "../", 3); - strcpy(p, to_path); - path_kill_slashes(r); + if (*t) + strcpy(p, t); + else + /* Remove trailing slash */ + *(--p) = 0; *_r = r; return 0; @@ -248,7 +227,7 @@ int path_strv_make_absolute_cwd(char **l) { if (r < 0) return r; - path_kill_slashes(t); + path_simplify(t, false); free_and_replace(*s, t); } @@ -290,8 +269,7 @@ char **path_strv_resolve(char **l, const char *root) { r = chase_symlinks(t, root, 0, &u); if (r == -ENOENT) { if (root) { - u = orig; - orig = NULL; + u = TAKE_PTR(orig); free(t); } else u = t; @@ -349,17 +327,30 @@ char **path_strv_resolve_uniq(char **l, const char *root) { return strv_uniq(l); } -char *path_kill_slashes(char *path) { +char *path_simplify(char *path, bool kill_dots) { char *f, *t; - bool slash = false; + bool slash = false, ignore_slash = false, absolute; + + assert(path); - /* Removes redundant inner and trailing slashes. Modifies the - * passed string in-place. + /* Removes redundant inner and trailing slashes. Also removes unnecessary dots + * if kill_dots is true. Modifies the passed string in-place. * - * ///foo///bar/ becomes /foo/bar + * ///foo//./bar/. becomes /foo/./bar/. (if kill_dots is false) + * ///foo//./bar/. becomes /foo/bar (if kill_dots is true) + * .//./foo//./bar/. becomes ./foo/bar (if kill_dots is false) + * .//./foo//./bar/. becomes foo/bar (if kill_dots is true) */ - for (f = path, t = path; *f; f++) { + absolute = path_is_absolute(path); + + f = path; + if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/')) { + ignore_slash = true; + f++; + } + + for (t = path; *f; f++) { if (*f == '/') { slash = true; @@ -367,17 +358,21 @@ char *path_kill_slashes(char *path) { } if (slash) { + if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/')) + continue; + slash = false; - *(t++) = '/'; + if (ignore_slash) + ignore_slash = false; + else + *(t++) = '/'; } *(t++) = *f; } - /* Special rule, if we are talking of the root directory, a - trailing slash is good */ - - if (t == path && slash) + /* Special rule, if we are talking of the root directory, a trailing slash is good */ + if (absolute && t == path) *(t++) = '/'; *t = 0; @@ -544,7 +539,7 @@ int find_binary(const char *name, char **ret) { /* Found it! */ if (ret) { - *ret = path_kill_slashes(j); + *ret = path_simplify(j, false); j = NULL; } @@ -654,7 +649,7 @@ char *prefix_root(const char *root, const char *path) { while (path[0] == '/' && path[1] == '/') path++; - if (isempty(root) || path_equal(root, "/")) + if (empty_or_root(root)) return strdup(path); l = strlen(root) + 1 + strlen(path) + 1; @@ -698,12 +693,12 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar if (r < 0) return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path); - path_kill_slashes(p); - if (suppress_root && path_equal(p, "/")) + path_simplify(p, false); + if (suppress_root && empty_or_root(p)) p = mfree(p); - free(*arg); - *arg = p; + free_and_replace(*arg, p); + return 0; } @@ -729,16 +724,23 @@ char* dirname_malloc(const char *path) { } const char *last_path_component(const char *path) { - /* Finds the last component of the path, preserving the - * optional trailing slash that signifies a directory. + + /* Finds the last component of the path, preserving the optional trailing slash that signifies a directory. + * * a/b/c → c * a/b/c/ → c/ + * x → x + * x/ → x/ + * /y → y + * /y/ → y/ * / → / * // → / * /foo/a → a * /foo/a/ → a/ - * This is different than basename, which returns "" when - * a trailing slash is present. + * + * Also, the empty string is mapped to itself. + * + * This is different than basename(), which returns "" when a trailing slash is present. */ unsigned l, k; @@ -879,17 +881,36 @@ bool hidden_or_backup_file(const char *filename) { bool is_device_path(const char *path) { - /* Returns true on paths that refer to a device, either in - * sysfs or in /dev */ + /* Returns true on paths that likely refer to a device, either by path in sysfs or to something in /dev */ + + return PATH_STARTSWITH_SET(path, "/dev/", "/sys/"); +} + +bool valid_device_node_path(const char *path) { + + /* Some superficial checks whether the specified path is a valid device node path, all without looking at the + * actual device node. */ + + if (!PATH_STARTSWITH_SET(path, "/dev/", "/run/systemd/inaccessible/")) + return false; + + if (endswith(path, "/")) /* can't be a device node if it ends in a slash */ + return false; - return path_startswith(path, "/dev/") || - path_startswith(path, "/sys/"); + return path_is_normalized(path); } -bool is_deviceallow_pattern(const char *path) { - return path_startswith(path, "/dev/") || - startswith(path, "block-") || - startswith(path, "char-"); +bool valid_device_allow_pattern(const char *path) { + assert(path); + + /* Like valid_device_node_path(), but also allows full-subsystem expressions, like DeviceAllow= and DeviceDeny= + * accept it */ + + if (startswith(path, "block-") || + startswith(path, "char-")) + return true; + + return valid_device_node_path(path); } int systemd_installation_has_version(const char *root, unsigned minimal_version) { @@ -925,7 +946,7 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version) if (r < 0) return r; - assert_se((c = endswith(path, "*.so"))); + assert_se(c = endswith(path, "*.so")); *c = '\0'; /* truncate the glob part */ STRV_FOREACH(name, names) { @@ -972,3 +993,61 @@ bool dot_or_dot_dot(const char *path) { return path[2] == 0; } + +bool empty_or_root(const char *root) { + + /* For operations relative to some root directory, returns true if the specified root directory is redundant, + * i.e. either / or NULL or the empty string or any equivalent. */ + + if (!root) + return true; + + return root[strspn(root, "/")] == 0; +} + +int path_simplify_and_warn( + char *path, + unsigned flag, + const char *unit, + const char *filename, + unsigned line, + const char *lvalue) { + + bool absolute, fatal = flag & PATH_CHECK_FATAL; + + assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)); + + if (!utf8_is_valid(path)) { + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path); + return -EINVAL; + } + + if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) { + absolute = path_is_absolute(path); + + if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "%s= path is not absolute%s: %s", + lvalue, fatal ? "" : ", ignoring", path); + return -EINVAL; + } + + if (absolute && (flag & PATH_CHECK_RELATIVE)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "%s= path is absolute%s: %s", + lvalue, fatal ? "" : ", ignoring", path); + return -EINVAL; + } + } + + path_simplify(path, true); + + if (!path_is_normalized(path)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "%s= path is not normalized%s: %s", + lvalue, fatal ? "" : ", ignoring", path); + return -EINVAL; + } + + return 0; +} diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 73f1769fd9..8277c6b916 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 <alloca.h> #include <stdbool.h> #include <stddef.h> @@ -28,19 +9,32 @@ #include "string-util.h" #include "time-util.h" +#define PATH_SPLIT_SBIN_BIN(x) x "sbin:" x "bin" +#define PATH_SPLIT_SBIN_BIN_NULSTR(x) x "sbin\0" x "bin\0" + +#define PATH_NORMAL_SBIN_BIN(x) x "bin" +#define PATH_NORMAL_SBIN_BIN_NULSTR(x) x "bin\0" + #if HAVE_SPLIT_BIN -# define PATH_SBIN_BIN(x) x "sbin:" x "bin" +# define PATH_SBIN_BIN(x) PATH_SPLIT_SBIN_BIN(x) +# define PATH_SBIN_BIN_NULSTR(x) PATH_SPLIT_SBIN_BIN_NULSTR(x) #else -# define PATH_SBIN_BIN(x) x "bin" +# define PATH_SBIN_BIN(x) PATH_NORMAL_SBIN_BIN(x) +# define PATH_SBIN_BIN_NULSTR(x) PATH_NORMAL_SBIN_BIN_NULSTR(x) #endif #define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/") +#define DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/usr/local/") PATH_SBIN_BIN_NULSTR("/usr/") #define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/") +#define DEFAULT_PATH_SPLIT_USR_NULSTR DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/") +#define DEFAULT_PATH_COMPAT PATH_SPLIT_SBIN_BIN("/usr/local/") ":" PATH_SPLIT_SBIN_BIN("/usr/") ":" PATH_SPLIT_SBIN_BIN("/") #if HAVE_SPLIT_USR # define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR +# define DEFAULT_PATH_NULSTR DEFAULT_PATH_SPLIT_USR_NULSTR #else # define DEFAULT_PATH DEFAULT_PATH_NORMAL +# define DEFAULT_PATH_NULSTR DEFAULT_PATH_NORMAL_NULSTR #endif bool is_path(const char *p) _pure_; @@ -50,12 +44,12 @@ char* path_make_absolute(const char *p, const char *prefix); int safe_getcwd(char **ret); int path_make_absolute_cwd(const char *p, char **ret); int path_make_relative(const char *from_dir, const char *to_path, char **_r); -char* path_kill_slashes(char *path); char* path_startswith(const char *path, const char *prefix) _pure_; int path_compare(const char *a, const char *b) _pure_; bool path_equal(const char *a, const char *b) _pure_; bool path_equal_or_files_same(const char *a, const char *b, int flags); char* path_join(const char *root, const char *path, const char *rest); +char* path_simplify(char *path, bool kill_dots); static inline bool path_equal_ptr(const char *a, const char *b) { return !!a == !!b && (!a || path_equal(a, b)); @@ -101,11 +95,11 @@ int mkfs_exists(const char *fstype); * the tree, to root. Also returns "" (and not "/"!) for the root * directory. Excludes the specified directory itself */ #define PATH_FOREACH_PREFIX(prefix, path) \ - for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) + for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) /* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */ #define PATH_FOREACH_PREFIX_MORE(prefix, path) \ - for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) + for (char *_slash = ({ path_simplify(strcpy(prefix, path), false); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) char *prefix_root(const char *root, const char *path); @@ -118,7 +112,7 @@ char *prefix_root(const char *root, const char *path); size_t _l; \ while (_path[0] == '/' && _path[1] == '/') \ _path ++; \ - if (isempty(_root) || path_equal(_root, "/")) \ + if (empty_or_root(_root)) \ _ret = _path; \ else { \ _l = strlen(_root) + 1 + strlen(_path) + 1; \ @@ -147,7 +141,9 @@ char *file_in_same_dir(const char *path, const char *filename); bool hidden_or_backup_file(const char *filename) _pure_; bool is_device_path(const char *path); -bool is_deviceallow_pattern(const char *path); + +bool valid_device_node_path(const char *path); +bool valid_device_allow_pattern(const char *path); int systemd_installation_has_version(const char *root, unsigned minimal_version); @@ -162,3 +158,16 @@ static inline const char *skip_dev_prefix(const char *p) { return e ?: p; } + +bool empty_or_root(const char *root); +static inline const char *empty_to_root(const char *path) { + return isempty(path) ? "/" : path; +} + +enum { + PATH_CHECK_FATAL = 1 << 0, /* If not set, then error message is appended with 'ignoring'. */ + PATH_CHECK_ABSOLUTE = 1 << 1, + PATH_CHECK_RELATIVE = 1 << 2, +}; + +int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue); diff --git a/src/basic/prioq.c b/src/basic/prioq.c index 2a1f1af878..ef28a086d1 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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/>. -***/ /* * Priority Queue diff --git a/src/basic/prioq.h b/src/basic/prioq.h index a222955dfe..e036175260 100644 --- a/src/basic/prioq.h +++ b/src/basic/prioq.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <stdbool.h> #include "hashmap.h" diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index c5d1fb1d41..add481c2ae 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <stddef.h> @@ -204,10 +186,8 @@ int proc_cmdline_get_key(const char *key, unsigned flags, char **value) { } } - if (value) { - *value = ret; - ret = NULL; - } + if (value) + *value = TAKE_PTR(ret); return found; } diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h index 16ccfbc2cb..4a9e6e0f62 100644 --- a/src/basic/proc-cmdline.h +++ b/src/basic/proc-cmdline.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include "log.h" diff --git a/src/basic/process-util.c b/src/basic/process-util.c index aa9846db5d..0a4f917cbd 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <ctype.h> #include <errno.h> @@ -30,6 +12,7 @@ #include <stdlib.h> #include <string.h> #include <sys/mman.h> +#include <sys/mount.h> #include <sys/personality.h> #include <sys/prctl.h> #include <sys/types.h> @@ -88,20 +71,31 @@ int get_process_state(pid_t pid) { return (unsigned char) state; } -int get_process_comm(pid_t pid, char **name) { +int get_process_comm(pid_t pid, char **ret) { + _cleanup_free_ char *escaped = NULL, *comm = NULL; const char *p; int r; - assert(name); + assert(ret); assert(pid >= 0); + escaped = new(char, TASK_COMM_LEN); + if (!escaped) + return -ENOMEM; + p = procfs_file_alloca(pid, "comm"); - r = read_one_line_file(p, name); + r = read_one_line_file(p, &comm); if (r == -ENOENT) return -ESRCH; + if (r < 0) + return r; - return r; + /* Escape unprintable characters, just in case, but don't grow the string beyond the underlying size */ + cellescape(escaped, TASK_COMM_LEN, comm); + + *ret = TAKE_PTR(escaped); + return 0; } int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { @@ -259,15 +253,10 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * memcpy(ans, "[...]", max_length-1); ans[max_length-1] = 0; } else { - char *e; - t[max_length - 6] = 0; /* Chop off final spaces */ - e = strchr(t, 0); - while (e > t && isspace(e[-1])) - e--; - *e = 0; + delete_trailing_chars(t, WHITESPACE); ans = strjoin("[", t, "...]"); } @@ -308,7 +297,7 @@ int rename_process(const char name[]) { * can use PR_SET_NAME, which sets the thread name for the calling thread. */ if (prctl(PR_SET_NAME, name) < 0) log_debug_errno(errno, "PR_SET_NAME failed: %m"); - if (l > 15) /* Linux process names can be 15 chars at max */ + if (l >= TASK_COMM_LEN) /* Linux process names can be 15 chars at max */ truncated = true; /* Second step, change glibc's ID of the process name. */ @@ -623,8 +612,7 @@ int get_process_environ(pid_t pid, char **env) { } else outcome[sz] = '\0'; - *env = outcome; - outcome = NULL; + *env = TAKE_PTR(outcome); return 0; } @@ -753,14 +741,17 @@ int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) { /* * Return values: - * < 0 : wait_for_terminate_with_timeout() failed to get the state of the - * process, the process timed out, the process was terminated by a - * signal, or failed for an unknown reason. + * + * < 0 : wait_for_terminate_with_timeout() failed to get the state of the process, the process timed out, the process + * was terminated by a signal, or failed for an unknown reason. + * * >=0 : The process terminated normally with no failures. * - * Success is indicated by a return value of zero, a timeout is indicated - * by ETIMEDOUT, and all other child failure states are indicated by error - * is indicated by a non-zero value. + * Success is indicated by a return value of zero, a timeout is indicated by ETIMEDOUT, and all other child failure + * states are indicated by error is indicated by a non-zero value. + * + * This call assumes SIGCHLD has been blocked already, in particular before the child to wait for has been forked off + * to remain entirely race-free. */ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) { sigset_t mask; @@ -894,7 +885,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) { do { char line[LINE_MAX]; - unsigned i; + size_t i; for (i = 0; i < sizeof(line)-1; i++) { int c; @@ -987,7 +978,7 @@ bool is_main_thread(void) { return cached > 0; } -noreturn void freeze(void) { +_noreturn_ void freeze(void) { log_close(); @@ -1358,6 +1349,16 @@ int safe_fork_full( } } + if (FLAGS_SET(flags, FORK_NEW_MOUNTNS | FORK_MOUNTNS_SLAVE)) { + + /* Optionally, make sure we never propagate mounts to the host. */ + + if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) { + log_full_errno(prio, errno, "Failed to remount root directory as MS_SLAVE: %m"); + _exit(EXIT_FAILURE); + } + } + if (flags & FORK_CLOSE_ALL_FDS) { /* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */ log_close(); @@ -1389,9 +1390,9 @@ int safe_fork_full( return 0; } -int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *ret_pid, const char *path, ...) { +int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) { bool stdout_is_tty, stderr_is_tty; - unsigned n, i; + size_t n, i; va_list ap; char **l; int r; @@ -1447,7 +1448,7 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *r va_end(ap); /* Allocate strv */ - l = alloca(sizeof(char *) * (n + 1)); + l = newa(char*, n + 1); /* Fill in arguments */ va_start(ap, path); @@ -1459,6 +1460,15 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *r _exit(EXIT_FAILURE); } +int set_oom_score_adjust(int value) { + char t[DECIMAL_STR_MAX(int)]; + + sprintf(t, "%i", value); + + return write_string_file("/proc/self/oom_score_adj", t, + WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER); +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", @@ -1466,7 +1476,7 @@ static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_IDLE] = "idle" }; -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES); static const char *const sigchld_code_table[] = { [CLD_EXITED] = "exited", diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 93029e36e5..a5bb072b25 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <alloca.h> #include <errno.h> #include <sched.h> @@ -64,8 +45,8 @@ int get_process_ppid(pid_t pid, pid_t *ppid); int wait_for_terminate(pid_t pid, siginfo_t *status); typedef enum WaitFlags { - WAIT_LOG_ABNORMAL = 1U << 0, - WAIT_LOG_NON_ZERO_EXIT_STATUS = 1U << 1, + WAIT_LOG_ABNORMAL = 1 << 0, + WAIT_LOG_NON_ZERO_EXIT_STATUS = 1 << 1, /* A shortcut for requesting the most complete logging */ WAIT_LOG = WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS, @@ -91,7 +72,7 @@ int pid_from_same_root_fs(pid_t pid); bool is_main_thread(void); -noreturn void freeze(void); +_noreturn_ void freeze(void); bool oom_score_adjust_is_valid(int oa); @@ -168,14 +149,15 @@ void reset_cached_pid(void); int must_be_root(void); typedef enum ForkFlags { - FORK_RESET_SIGNALS = 1U << 0, - FORK_CLOSE_ALL_FDS = 1U << 1, - FORK_DEATHSIG = 1U << 2, - FORK_NULL_STDIO = 1U << 3, - FORK_REOPEN_LOG = 1U << 4, - FORK_LOG = 1U << 5, - FORK_WAIT = 1U << 6, - FORK_NEW_MOUNTNS = 1U << 7, + FORK_RESET_SIGNALS = 1 << 0, + FORK_CLOSE_ALL_FDS = 1 << 1, + FORK_DEATHSIG = 1 << 2, + FORK_NULL_STDIO = 1 << 3, + FORK_REOPEN_LOG = 1 << 4, + FORK_LOG = 1 << 5, + FORK_WAIT = 1 << 6, + FORK_NEW_MOUNTNS = 1 << 7, + FORK_MOUNTNS_SLAVE = 1 << 8, } ForkFlags; int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid); @@ -184,7 +166,9 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) { return safe_fork_full(name, NULL, 0, flags, ret_pid); } -int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *pid, const char *path, ...); +int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...); + +int set_oom_score_adjust(int value); #if SIZEOF_PID_T == 4 /* The highest possibly (theoretic) pid_t value on this architecture. */ @@ -204,3 +188,11 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *p #endif assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX) + +/* Like TAKE_PTR() but for child PIDs, resetting them to 0 */ +#define TAKE_PID(pid) \ + ({ \ + pid_t _pid_ = (pid); \ + (pid) = 0; \ + _pid_; \ + }) diff --git a/src/basic/random-util.c b/src/basic/random-util.c index 7457815fa2..91481559db 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <elf.h> #include <errno.h> @@ -48,7 +30,7 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) { static int have_syscall = -1; _cleanup_close_ int fd = -1; - unsigned already_done = 0; + size_t already_done = 0; int r; /* Gathers some randomness from the kernel. This call will never block. If @@ -59,7 +41,7 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) { * for us. */ /* Use the getrandom() syscall unless we know we don't have it. */ - if (have_syscall != 0) { + if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) { r = getrandom(p, n, GRND_NONBLOCK); if (r > 0) { have_syscall = true; @@ -122,7 +104,6 @@ void initialize_srand(void) { #endif x = 0; - x ^= (unsigned) now(CLOCK_REALTIME); x ^= (unsigned) gettid(); diff --git a/src/basic/random-util.h b/src/basic/random-util.h index dd8701515e..9a103f0e94 100644 --- a/src/basic/random-util.h +++ b/src/basic/random-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <stddef.h> #include <stdint.h> diff --git a/src/basic/ratelimit.c b/src/basic/ratelimit.c index 5b684e261a..4e04e04426 100644 --- a/src/basic/ratelimit.c +++ b/src/basic/ratelimit.c @@ -1,23 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <sys/time.h> @@ -27,7 +8,7 @@ /* Modelled after Linux' lib/ratelimit.c by Dave Young * <hidave.darkstar@gmail.com>, which is licensed GPLv2. */ -bool ratelimit_test(RateLimit *r) { +bool ratelimit_below(RateLimit *r) { usec_t ts; assert(r); diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h index 19acf9c854..de91def28d 100644 --- a/src/basic/ratelimit.h +++ b/src/basic/ratelimit.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include "time-util.h" @@ -56,4 +37,4 @@ typedef struct RateLimit { _r->begin = 0; \ } while (false) -bool ratelimit_test(RateLimit *r); +bool ratelimit_below(RateLimit *r); diff --git a/src/basic/raw-clone.h b/src/basic/raw-clone.h index 8c95380305..1f134ba7f2 100644 --- a/src/basic/raw-clone.h +++ b/src/basic/raw-clone.h @@ -2,24 +2,10 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2016 Michael Karcher - 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/>. + Copyright © 2016 Michael Karcher ***/ +#include <errno.h> #include <sched.h> #include <sys/syscall.h> @@ -51,27 +37,36 @@ static inline pid_t raw_clone(unsigned long flags) { /* On s390/s390x and cris the order of the first and second arguments * of the raw clone() system call is reversed. */ ret = (pid_t) syscall(__NR_clone, NULL, flags); -#elif defined(__sparc__) && defined(__arch64__) +#elif defined(__sparc__) { /** - * sparc64 always returns the other process id in %o0, and + * sparc always returns the other process id in %o0, and * a boolean flag whether this is the child or the parent in * %o1. Inline assembly is needed to get the flag returned * in %o1. */ - int in_child, child_pid; + int in_child, child_pid, error; - asm volatile("mov %2, %%g1\n\t" - "mov %3, %%o0\n\t" + asm volatile("mov %3, %%g1\n\t" + "mov %4, %%o0\n\t" "mov 0 , %%o1\n\t" +#if defined(__arch64__) "t 0x6d\n\t" +#else + "t 0x10\n\t" +#endif + "addx %%g0, 0, %2\n\t" "mov %%o1, %0\n\t" "mov %%o0, %1" : - "=r"(in_child), "=r"(child_pid) : + "=r"(in_child), "=r"(child_pid), "=r"(error) : "i"(__NR_clone), "r"(flags) : - "%o1", "%o0", "%g1" ); + "%o1", "%o0", "%g1" "cc" ); - ret = in_child ? 0 : child_pid; + if (error) { + errno = child_pid; + ret = -1; + } else + ret = in_child ? 0 : child_pid; } #else ret = (pid_t) syscall(__NR_clone, flags, NULL); diff --git a/src/basic/reboot-util.h b/src/basic/reboot-util.h index d4aa441290..d459333efc 100644 --- a/src/basic/reboot-util.h +++ b/src/basic/reboot-util.h @@ -4,9 +4,9 @@ int update_reboot_parameter_and_warn(const char *parameter); typedef enum RebootFlags { - REBOOT_LOG = 1U << 0, /* log about what we are going to do and all errors */ - REBOOT_DRY_RUN = 1U << 1, /* return 0 right before actually doing the reboot */ - REBOOT_FALLBACK = 1U << 2, /* fallback to plain reboot() if argument-based reboot doesn't work, isn't configured or doesn't apply otherwise */ + REBOOT_LOG = 1 << 0, /* log about what we are going to do and all errors */ + REBOOT_DRY_RUN = 1 << 1, /* return 0 right before actually doing the reboot */ + REBOOT_FALLBACK = 1 << 2, /* fallback to plain reboot() if argument-based reboot doesn't work, isn't configured or doesn't apply otherwise */ } RebootFlags; int reboot_with_parameter(RebootFlags flags); diff --git a/src/basic/refcnt.h b/src/basic/refcnt.h index ae2e446d6c..d2be6086d2 100644 --- a/src/basic/refcnt.h +++ b/src/basic/refcnt.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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/>. -***/ - /* A type-safe atomic refcounter. * * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */ diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c index c73ed9777e..fd2b5c104f 100644 --- a/src/basic/replace-var.c +++ b/src/basic/replace-var.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - 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 <errno.h> #include <stddef.h> diff --git a/src/basic/replace-var.h b/src/basic/replace-var.h index 3d5906198e..e6a489feee 100644 --- a/src/basic/replace-var.h +++ b/src/basic/replace-var.h @@ -1,23 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - 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/>. -***/ - char *replace_var(const char *text, char *(*lookup)(const char *variable, void *userdata), void *userdata); diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 00648211d3..be1ba615ec 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <sys/resource.h> @@ -46,6 +28,11 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) { if (getrlimit(resource, &highest) < 0) return -errno; + /* If the hard limit is unbounded anyway, then the EPERM had other reasons, let's propagate the original EPERM + * then */ + if (highest.rlim_max == RLIM_INFINITY) + return -EPERM; + fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); @@ -55,6 +42,32 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) { return 0; } +int setrlimit_closest_all(const struct rlimit *const *rlim, int *which_failed) { + int i, r; + + assert(rlim); + + /* On failure returns the limit's index that failed in *which_failed, but only if non-NULL */ + + for (i = 0; i < _RLIMIT_MAX; i++) { + if (!rlim[i]) + continue; + + r = setrlimit_closest(i, rlim[i]); + if (r < 0) { + if (which_failed) + *which_failed = i; + + return r; + } + } + + if (which_failed) + *which_failed = -1; + + return 0; +} + static int rlimit_parse_u64(const char *val, rlim_t *ret) { uint64_t u; int r; @@ -302,22 +315,48 @@ int rlimit_format(const struct rlimit *rl, char **ret) { } static const char* const rlimit_table[_RLIMIT_MAX] = { - [RLIMIT_CPU] = "LimitCPU", - [RLIMIT_FSIZE] = "LimitFSIZE", - [RLIMIT_DATA] = "LimitDATA", - [RLIMIT_STACK] = "LimitSTACK", - [RLIMIT_CORE] = "LimitCORE", - [RLIMIT_RSS] = "LimitRSS", - [RLIMIT_NOFILE] = "LimitNOFILE", - [RLIMIT_AS] = "LimitAS", - [RLIMIT_NPROC] = "LimitNPROC", - [RLIMIT_MEMLOCK] = "LimitMEMLOCK", - [RLIMIT_LOCKS] = "LimitLOCKS", - [RLIMIT_SIGPENDING] = "LimitSIGPENDING", - [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", - [RLIMIT_NICE] = "LimitNICE", - [RLIMIT_RTPRIO] = "LimitRTPRIO", - [RLIMIT_RTTIME] = "LimitRTTIME" + [RLIMIT_AS] = "AS", + [RLIMIT_CORE] = "CORE", + [RLIMIT_CPU] = "CPU", + [RLIMIT_DATA] = "DATA", + [RLIMIT_FSIZE] = "FSIZE", + [RLIMIT_LOCKS] = "LOCKS", + [RLIMIT_MEMLOCK] = "MEMLOCK", + [RLIMIT_MSGQUEUE] = "MSGQUEUE", + [RLIMIT_NICE] = "NICE", + [RLIMIT_NOFILE] = "NOFILE", + [RLIMIT_NPROC] = "NPROC", + [RLIMIT_RSS] = "RSS", + [RLIMIT_RTPRIO] = "RTPRIO", + [RLIMIT_RTTIME] = "RTTIME", + [RLIMIT_SIGPENDING] = "SIGPENDING", + [RLIMIT_STACK] = "STACK", }; DEFINE_STRING_TABLE_LOOKUP(rlimit, int); + +int rlimit_from_string_harder(const char *s) { + const char *suffix; + + /* The official prefix */ + suffix = startswith(s, "RLIMIT_"); + if (suffix) + return rlimit_from_string(suffix); + + /* Our own unit file setting prefix */ + suffix = startswith(s, "Limit"); + if (suffix) + return rlimit_from_string(suffix); + + return rlimit_from_string(s); +} + +void rlimit_free_all(struct rlimit **rl) { + int i; + + if (!rl) + return; + + for (i = 0; i < _RLIMIT_MAX; i++) + rl[i] = mfree(rl[i]); +} diff --git a/src/basic/rlimit-util.h b/src/basic/rlimit-util.h index 4494b89c76..c2ea6f846b 100644 --- a/src/basic/rlimit-util.h +++ b/src/basic/rlimit-util.h @@ -1,37 +1,22 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <sys/resource.h> #include "macro.h" const char *rlimit_to_string(int i) _const_; int rlimit_from_string(const char *s) _pure_; +int rlimit_from_string_harder(const char *s) _pure_; int setrlimit_closest(int resource, const struct rlimit *rlim); +int setrlimit_closest_all(const struct rlimit * const *rlim, int *which_failed); int rlimit_parse_one(int resource, const char *val, rlim_t *ret); int rlimit_parse(int resource, const char *val, struct rlimit *ret); int rlimit_format(const struct rlimit *rl, char **ret); +void rlimit_free_all(struct rlimit **rl); + #define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim }) diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index 2839f37cd9..54f6dc2059 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2015 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> @@ -26,6 +8,7 @@ #include <sys/statfs.h> #include <unistd.h> +#include "alloc-util.h" #include "btrfs-util.h" #include "cgroup-util.h" #include "dirent-util.h" @@ -62,13 +45,15 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { } if (is_physical_fs(&sfs)) { - /* We refuse to clean physical file systems - * with this call, unless explicitly - * requested. This is extra paranoia just to - * be sure we never ever remove non-state - * data */ + /* We refuse to clean physical file systems with this call, + * unless explicitly requested. This is extra paranoia just + * to be sure we never ever remove non-state data. */ + _cleanup_free_ char *path = NULL; + + (void) fd_get_path(fd, &path); + log_error("Attempted to remove disk file system under \"%s\", and we can't allow that.", + strna(path)); - log_error("Attempted to remove disk file system, and we can't allow that."); safe_close(fd); return -EPERM; } @@ -184,11 +169,11 @@ int rm_rf(const char *path, RemoveFlags flags) { * call. This is extra paranoia to never cause a really * seriously broken system. */ if (path_equal_or_files_same(path, "/", AT_SYMLINK_NOFOLLOW)) { - log_error("Attempted to remove entire root file system, and we can't allow that."); + log_error("Attempted to remove entire root file system (\"%s\"), and we can't allow that.", path); return -EPERM; } - if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) { + if (FLAGS_SET(flags, REMOVE_SUBVOLUME | REMOVE_ROOT | REMOVE_PHYSICAL)) { /* Try to remove as subvolume first */ r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (r >= 0) @@ -202,7 +187,6 @@ int rm_rf(const char *path, RemoveFlags flags) { fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); if (fd < 0) { - if (!IN_SET(errno, ENOTDIR, ELOOP)) return -errno; @@ -211,7 +195,7 @@ int rm_rf(const char *path, RemoveFlags flags) { return -errno; if (is_physical_fs(&s)) { - log_error("Attempted to remove disk file system, and we can't allow that."); + log_error("Attempted to remove files from a disk file system under \"%s\", refusing.", path); return -EPERM; } } diff --git a/src/basic/rm-rf.h b/src/basic/rm-rf.h index 6e63d3feab..0a2d7f0358 100644 --- a/src/basic/rm-rf.h +++ b/src/basic/rm-rf.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2015 Lennart Poettering - - 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 <sys/stat.h> #include "util.h" diff --git a/src/basic/securebits-util.c b/src/basic/securebits-util.c index 441d386f9e..ad091f6d95 100644 --- a/src/basic/securebits-util.c +++ b/src/basic/securebits-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2017 Yu Watanabe - - 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 <errno.h> #include <stdio.h> @@ -48,8 +30,7 @@ int secure_bits_to_string_alloc(int i, char **s) { if (len != 0) str[len - 1] = '\0'; - *s = str; - str = NULL; + *s = TAKE_PTR(str); return 0; } diff --git a/src/basic/securebits-util.h b/src/basic/securebits-util.h index 069d215488..10a221d6a0 100644 --- a/src/basic/securebits-util.h +++ b/src/basic/securebits-util.h @@ -1,24 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2017 Yu Watanabe - - 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 "securebits.h" diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 0c6e99b1d7..e15bd7e1fa 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <malloc.h> @@ -34,10 +16,12 @@ #endif #include "alloc-util.h" +#include "fd-util.h" #include "log.h" #include "macro.h" #include "path-util.h" #include "selinux-util.h" +#include "stdio-util.h" #include "time-util.h" #include "util.h" @@ -51,7 +35,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free); static int cached_use = -1; static struct selabel_handle *label_hnd = NULL; -#define log_enforcing(...) log_full_errno(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, errno, __VA_ARGS__) +#define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__) +#define log_enforcing_errno(r, ...) log_full_errno(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, r, __VA_ARGS__) #endif bool mac_selinux_use(void) { @@ -89,7 +74,7 @@ int mac_selinux_init(void) { label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); if (!label_hnd) { - log_enforcing("Failed to initialize SELinux context: %m"); + log_enforcing_errno(errno, "Failed to initialize SELinux context: %m"); r = security_getenforce() == 1 ? -errno : 0; } else { char timespan[FORMAT_TIMESPAN_MAX]; @@ -120,9 +105,12 @@ void mac_selinux_finish(void) { #endif } -int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { +int mac_selinux_fix(const char *path, LabelFixFlags flags) { #if HAVE_SELINUX + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_freecon_ char* fcon = NULL; + _cleanup_close_ int fd = -1; struct stat st; int r; @@ -132,37 +120,55 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { if (!label_hnd) return 0; - r = lstat(path, &st); - if (r >= 0) { - _cleanup_freecon_ char* fcon = NULL; + /* Open the file as O_PATH, to pin it while we determine and adjust the label */ + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) { + if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) + return 0; - r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); + return -errno; + } + + if (fstat(fd, &st) < 0) + return -errno; + + if (selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode) < 0) { + r = -errno; /* If there's no label to set, then exit without warning */ - if (r < 0 && errno == ENOENT) + if (r == -ENOENT) return 0; - if (r >= 0) { - r = lsetfilecon_raw(path, fcon); - - /* If the FS doesn't support labels, then exit without warning */ - if (r < 0 && errno == EOPNOTSUPP) - return 0; - } + goto fail; } - if (r < 0) { - /* Ignore ENOENT in some cases */ - if (ignore_enoent && errno == ENOENT) + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + if (setfilecon_raw(procfs_path, fcon) < 0) { + _cleanup_freecon_ char *oldcon = NULL; + + r = -errno; + + /* If the FS doesn't support labels, then exit without warning */ + if (r == -EOPNOTSUPP) return 0; - if (ignore_erofs && errno == EROFS) + /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */ + if (r == -EROFS && (flags & LABEL_IGNORE_EROFS)) return 0; - log_enforcing("Unable to fix SELinux security context of %s: %m", path); - if (security_getenforce() == 1) - return -errno; + /* If the old label is identical to the new one, suppress any kind of error */ + if (getfilecon_raw(procfs_path, &oldcon) >= 0 && streq(fcon, oldcon)) + return 0; + + goto fail; } + + return 0; + +fail: + log_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", path); + if (security_getenforce() == 1) + return r; #endif return 0; @@ -178,7 +184,7 @@ int mac_selinux_apply(const char *path, const char *label) { assert(label); if (setfilecon(path, label) < 0) { - log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path); + log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path); if (security_getenforce() > 0) return -errno; } @@ -304,7 +310,6 @@ char* mac_selinux_free(char *label) { if (!mac_selinux_use()) return NULL; - freecon(label); #endif @@ -339,12 +344,12 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) { if (errno == ENOENT) return 0; - log_enforcing("Failed to determine SELinux security context for %s: %m", path); + log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path); } else { if (setfscreatecon_raw(filecon) >= 0) return 0; /* Success! */ - log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path); + log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, path); } if (security_getenforce() > 0) @@ -375,7 +380,7 @@ int mac_selinux_create_socket_prepare(const char *label) { assert(label); if (setsockcreatecon(label) < 0) { - log_enforcing("Failed to set SELinux security context %s for sockets: %m", label); + log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label); if (security_getenforce() == 1) return -errno; @@ -447,13 +452,13 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { if (errno == ENOENT) goto skipped; - log_enforcing("Failed to determine SELinux security context for %s: %m", path); + log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path); if (security_getenforce() > 0) return -errno; } else { if (setfscreatecon_raw(fcon) < 0) { - log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path); + log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path); if (security_getenforce() > 0) return -errno; } else diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 9780dca81e..08314057fb 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -1,30 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <sys/socket.h> #include <sys/types.h> #include "macro.h" +#include "label.h" bool mac_selinux_use(void); void mac_selinux_retest(void); @@ -32,7 +14,7 @@ void mac_selinux_retest(void); int mac_selinux_init(void); void mac_selinux_finish(void); -int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs); +int mac_selinux_fix(const char *path, LabelFixFlags flags); int mac_selinux_apply(const char *path, const char *label); int mac_selinux_get_create_label_from_exe(const char *exe, char **label); diff --git a/src/basic/set.c b/src/basic/set.c deleted file mode 100644 index e554e825eb..0000000000 --- a/src/basic/set.c +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2017 Lennart Poettering - - 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 "set.h" - -int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...) { - _cleanup_set_free_ Set *s = NULL; - int r; - - assert(ret); - - s = set_new(hash_ops HASHMAP_DEBUG_PASS_ARGS); - if (!s) - return -ENOMEM; - - if (add) { - va_list ap; - - r = set_put(s, add); - if (r < 0) - return r; - - va_start(ap, add); - - for (;;) { - void *arg = va_arg(ap, void*); - - if (!arg) - break; - - r = set_put(s, arg); - if (r < 0) { - va_end(ap); - return r; - } - } - - va_end(ap); - } - - *ret = s; - s = NULL; - - return 0; -} diff --git a/src/basic/set.h b/src/basic/set.h index 156ab4b081..664713810d 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 "extract-word.h" #include "hashmap.h" #include "macro.h" @@ -149,5 +130,3 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); #define _cleanup_set_free_ _cleanup_(set_freep) #define _cleanup_set_free_free_ _cleanup_(set_free_freep) - -int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...); diff --git a/src/basic/sigbus.c b/src/basic/sigbus.c index 2416929e36..70afba6bcf 100644 --- a/src/basic/sigbus.c +++ b/src/basic/sigbus.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <errno.h> #include <signal.h> diff --git a/src/basic/sigbus.h b/src/basic/sigbus.h index 90b0c9632e..459e19fcaa 100644 --- a/src/basic/sigbus.h +++ b/src/basic/sigbus.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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/>. -***/ - void sigbus_install(void); void sigbus_reset(void); diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index 27caabe471..fb8a63fb9a 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2015 Lennart Poettering - - 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 <errno.h> #include <stdarg.h> @@ -242,36 +224,65 @@ const char *signal_to_string(int signo) { } int signal_from_string(const char *s) { - int signo; - int offset = 0; - unsigned u; + const char *p; + int signo, r; + /* Check that the input is a signal number. */ + if (safe_atoi(s, &signo) >= 0) { + if (SIGNAL_VALID(signo)) + return signo; + else + return -ERANGE; + } + + /* Drop "SIG" prefix. */ + if (startswith(s, "SIG")) + s += 3; + + /* Check that the input is a signal name. */ signo = __signal_from_string(s); if (signo > 0) return signo; - if (startswith(s, "RTMIN+")) { - s += 6; - offset = SIGRTMIN; - } - if (safe_atou(s, &u) >= 0) { - signo = (int) u + offset; - if (SIGNAL_VALID(signo)) - return signo; + /* Check that the input is RTMIN or + * RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */ + p = startswith(s, "RTMIN"); + if (p) { + if (*p == '\0') + return SIGRTMIN; + if (*p != '+') + return -EINVAL; + + r = safe_atoi(p, &signo); + if (r < 0) + return r; + + if (signo < 0 || signo > SIGRTMAX - SIGRTMIN) + return -ERANGE; + + return signo + SIGRTMIN; } - return -EINVAL; -} -int signal_from_string_try_harder(const char *s) { - int signo; - assert(s); + /* Check that the input is RTMAX or + * RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */ + p = startswith(s, "RTMAX"); + if (p) { + if (*p == '\0') + return SIGRTMAX; + if (*p != '-') + return -EINVAL; + + r = safe_atoi(p, &signo); + if (r < 0) + return r; - signo = signal_from_string(s); - if (signo <= 0) - if (startswith(s, "SIG")) - return signal_from_string(s+3); + if (signo > 0 || signo < SIGRTMIN - SIGRTMAX) + return -ERANGE; - return signo; + return signo + SIGRTMAX; + } + + return -EINVAL; } void nop_signal_handler(int sig) { diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index f6c3396ebe..92f2804cd2 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2015 Lennart Poettering - - 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 <signal.h> #include "macro.h" @@ -37,8 +18,6 @@ int sigprocmask_many(int how, sigset_t *old, ...); const char *signal_to_string(int i) _const_; int signal_from_string(const char *s) _pure_; -int signal_from_string_try_harder(const char *s); - void nop_signal_handler(int sig); static inline void block_signals_reset(sigset_t *ss) { diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index f0018f013f..9d31b7717f 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -1,38 +1,26 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - This file is part of systemd. - - Copyright 2013 Intel Corporation + Copyright © 2013 Intel Corporation Author: Auke Kok <auke-jan.h.kok@intel.com> - - 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 <errno.h> +#include <fcntl.h> #include <string.h> #include <sys/stat.h> #include <sys/xattr.h> #include <unistd.h> #include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" #include "log.h" #include "macro.h" #include "path-util.h" #include "process-util.h" #include "smack-util.h" +#include "stdio-util.h" #include "string-table.h" #include "xattr-util.h" @@ -134,7 +122,10 @@ int mac_smack_apply_pid(pid_t pid, const char *label) { return r; } -int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { +int mac_smack_fix(const char *path, LabelFixFlags flags) { + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_ int fd = -1; + const char *label; struct stat st; int r; @@ -143,50 +134,72 @@ int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { if (!mac_smack_use()) return 0; + /* Path must be in /dev. Note that this check is pretty sloppy, as we might be called with non-normalized paths + * and hence not detect all cases of /dev. */ + + if (path_is_absolute(path)) { + if (!path_startswith(path, "/dev")) + return 0; + } else { + _cleanup_free_ char *cwd = NULL; + + r = safe_getcwd(&cwd); + if (r < 0) + return r; + + if (!path_startswith(cwd, "/dev")) + return 0; + } + + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); + if (fd < 0) { + if ((flags & LABEL_IGNORE_ENOENT) && errno == ENOENT) + return 0; + + return -errno; + } + + if (fstat(fd, &st) < 0) + return -errno; + /* - * Path must be in /dev and must exist + * Label directories and character devices "*". + * Label symlinks "_". + * Don't change anything else. */ - if (!path_startswith(path, "/dev")) + + if (S_ISDIR(st.st_mode)) + label = SMACK_STAR_LABEL; + else if (S_ISLNK(st.st_mode)) + label = SMACK_FLOOR_LABEL; + else if (S_ISCHR(st.st_mode)) + label = SMACK_STAR_LABEL; + else return 0; - r = lstat(path, &st); - if (r >= 0) { - const char *label; - - /* - * Label directories and character devices "*". - * Label symlinks "_". - * Don't change anything else. - */ - - if (S_ISDIR(st.st_mode)) - label = SMACK_STAR_LABEL; - else if (S_ISLNK(st.st_mode)) - label = SMACK_FLOOR_LABEL; - else if (S_ISCHR(st.st_mode)) - label = SMACK_STAR_LABEL; - else - return 0; + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + if (setxattr(procfs_path, "security.SMACK64", label, strlen(label), 0) < 0) { + _cleanup_free_ char *old_label = NULL; - r = lsetxattr(path, "security.SMACK64", label, strlen(label), 0); + r = -errno; /* If the FS doesn't support labels, then exit without warning */ - if (r < 0 && errno == EOPNOTSUPP) + if (r == -EOPNOTSUPP) return 0; - } - if (r < 0) { - /* Ignore ENOENT in some cases */ - if (ignore_enoent && errno == ENOENT) + /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */ + if (r == -EROFS && (flags & LABEL_IGNORE_EROFS)) return 0; - if (ignore_erofs && errno == EROFS) + /* If the old label is identical to the new one, suppress any kind of error */ + if (getxattr_malloc(procfs_path, "security.SMACK64", &old_label, false) >= 0 && + streq(old_label, label)) return 0; - r = log_debug_errno(errno, "Unable to fix SMACK label of %s: %m", path); + return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", path); } - return r; + return 0; } int mac_smack_copy(const char *dest, const char *src) { @@ -232,7 +245,7 @@ int mac_smack_apply_pid(pid_t pid, const char *label) { return 0; } -int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { +int mac_smack_fix(const char *path, LabelFixFlags flags) { return 0; } diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index e4d46d7736..fd59787ecb 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -2,48 +2,34 @@ #pragma once /*** - This file is part of systemd. - - Copyright 2013 Intel Corporation + Copyright © 2013 Intel Corporation Author: Auke Kok <auke-jan.h.kok@intel.com> - - 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 <stdbool.h> #include <sys/types.h> +#include "label.h" #include "macro.h" #define SMACK_FLOOR_LABEL "_" #define SMACK_STAR_LABEL "*" typedef enum SmackAttr { - SMACK_ATTR_ACCESS = 0, - SMACK_ATTR_EXEC = 1, - SMACK_ATTR_MMAP = 2, - SMACK_ATTR_TRANSMUTE = 3, - SMACK_ATTR_IPIN = 4, - SMACK_ATTR_IPOUT = 5, + SMACK_ATTR_ACCESS, + SMACK_ATTR_EXEC, + SMACK_ATTR_MMAP, + SMACK_ATTR_TRANSMUTE, + SMACK_ATTR_IPIN, + SMACK_ATTR_IPOUT, _SMACK_ATTR_MAX, _SMACK_ATTR_INVALID = -1, } SmackAttr; bool mac_smack_use(void); -int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs); +int mac_smack_fix(const char *path, LabelFixFlags flags); const char* smack_attr_to_string(SmackAttr i) _const_; SmackAttr smack_attr_from_string(const char *s) _pure_; diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 97f3ebe2af..35e14e567c 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <netinet/in.h> diff --git a/src/basic/socket-protocol-list.c b/src/basic/socket-protocol-list.c index 9ab93d1c7e..8041b84958 100644 --- a/src/basic/socket-protocol-list.c +++ b/src/basic/socket-protocol-list.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <netinet/in.h> #include <string.h> diff --git a/src/basic/socket-protocol-list.h b/src/basic/socket-protocol-list.h index 12fd053382..458904dbb3 100644 --- a/src/basic/socket-protocol-list.h +++ b/src/basic/socket-protocol-list.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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/>. -***/ - const char *socket_protocol_to_name(int id); int socket_protocol_from_name(const char *name); diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index b91b093132..a913102e13 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <arpa/inet.h> #include <errno.h> @@ -677,7 +659,6 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ return -EOPNOTSUPP; } - *ret = p; return 0; } @@ -804,7 +785,7 @@ static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIN DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); -SocketAddressBindIPv6Only parse_socket_address_bind_ipv6_only_or_bool(const char *n) { +SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *n) { int r; r = parse_boolean(n); @@ -985,8 +966,7 @@ int getpeersec(int fd, char **ret) { if (isempty(s)) return -EOPNOTSUPP; - *ret = s; - s = NULL; + *ret = TAKE_PTR(s); return 0; } @@ -1018,8 +998,7 @@ int getpeergroups(int fd, gid_t **ret) { if ((socklen_t) (int) n != n) return -E2BIG; - *ret = d; - d = NULL; + *ret = TAKE_PTR(d); return (int) n; } @@ -1079,7 +1058,7 @@ int receive_one_fd(int transport_fd, int flags) { * combination with send_one_fd(). */ - if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0) + if (recvmsg(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags) < 0) return -errno; CMSG_FOREACH(cmsg, &mh) { @@ -1142,7 +1121,6 @@ int flush_accept(int fd) { }; int r; - /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */ for (;;) { diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 2e5694b126..8e23cf2dbd 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <netinet/ether.h> #include <netinet/in.h> #include <stdbool.h> @@ -129,7 +110,7 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret); const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_; SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_; -SocketAddressBindIPv6Only parse_socket_address_bind_ipv6_only_or_bool(const char *s); +SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *s); int netlink_family_to_string_alloc(int b, char **s); int netlink_family_from_string(const char *s) _pure_; diff --git a/src/basic/special.h b/src/basic/special.h index c058b1d852..379a3d7979 100644 --- a/src/basic/special.h +++ b/src/basic/special.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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/>. -***/ - #define SPECIAL_DEFAULT_TARGET "default.target" /* Shutdown targets */ @@ -37,6 +18,7 @@ #define SPECIAL_SUSPEND_TARGET "suspend.target" #define SPECIAL_HIBERNATE_TARGET "hibernate.target" #define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target" +#define SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET "suspend-then-hibernate.target" /* Special boot targets */ #define SPECIAL_RESCUE_TARGET "rescue.target" diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 3689f6e983..07154e25bb 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 <dirent.h> #include <errno.h> @@ -145,32 +127,6 @@ int path_is_read_only_fs(const char *path) { return false; } -int path_is_os_tree(const char *path) { - int r; - - assert(path); - - /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir - * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from - * the case where just the os-release file is missing. */ - if (laccess(path, F_OK) < 0) - return -errno; - - /* We use /usr/lib/os-release as flag file if something is an OS */ - r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL); - if (r == -ENOENT) { - - /* Also check for the old location in /etc, just in case. */ - r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL); - if (r == -ENOENT) - return 0; /* We got nothing */ - } - if (r < 0) - return r; - - return 1; -} - int files_same(const char *filea, const char *fileb, int flags) { struct stat a, b; @@ -254,7 +210,8 @@ int fd_is_network_ns(int fd) { if (r <= 0) return r; - if (ioctl(fd, NS_GET_NSTYPE) < 0) + r = ioctl(fd, NS_GET_NSTYPE); + if (r < 0) return -errno; return r == CLONE_NEWNET; diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 4b941f6104..f8014ed30b 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - 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 <stdbool.h> #include <stddef.h> #include <sys/stat.h> @@ -48,7 +29,6 @@ int null_or_empty_path(const char *fn); int null_or_empty_fd(int fd); int path_is_read_only_fs(const char *path); -int path_is_os_tree(const char *path); int files_same(const char *filea, const char *fileb, int flags); diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h index d3fed365d8..73c03274c7 100644 --- a/src/basic/stdio-util.h +++ b/src/basic/stdio-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <printf.h> #include <stdarg.h> #include <stdio.h> diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index bc3e56cf71..e2ed776a09 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2012 Kay Sievers <kay@vrfy.org> - - 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 <errno.h> #include <stdlib.h> @@ -24,6 +6,7 @@ #include "alloc-util.h" #include "strbuf.h" +#include "util.h" /* * Strbuf stores given strings in a single continuous allocated memory @@ -46,33 +29,31 @@ struct strbuf *strbuf_new(void) { struct strbuf *str; - str = new0(struct strbuf, 1); + str = new(struct strbuf, 1); if (!str) return NULL; + *str = (struct strbuf) { + .buf = new0(char, 1), + .root = new0(struct strbuf_node, 1), + .len = 1, + .nodes_count = 1, + }; + if (!str->buf || !str->root) { + free(str->buf); + free(str->root); + return mfree(str); + } - str->buf = new0(char, 1); - if (!str->buf) - goto err; - str->len = 1; - - str->root = new0(struct strbuf_node, 1); - if (!str->root) - goto err; - str->nodes_count = 1; return str; -err: - free(str->buf); - free(str->root); - return mfree(str); } -static void strbuf_node_cleanup(struct strbuf_node *node) { +static struct strbuf_node* strbuf_node_cleanup(struct strbuf_node *node) { size_t i; for (i = 0; i < node->children_count; i++) strbuf_node_cleanup(node->children[i].child); free(node->children); - free(node); + return mfree(node); } /* clean up trie data, leave only the string buffer */ @@ -80,16 +61,12 @@ void strbuf_complete(struct strbuf *str) { if (!str) return; if (str->root) - strbuf_node_cleanup(str->root); - str->root = NULL; + str->root = strbuf_node_cleanup(str->root); } /* clean up everything */ void strbuf_cleanup(struct strbuf *str) { - if (!str) - return; - if (str->root) - strbuf_node_cleanup(str->root); + strbuf_complete(str); free(str->buf); free(str); } @@ -138,13 +115,15 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { return -EINVAL; /* search string; start from last character to find possibly matching tails */ - if (len == 0) - return 0; + str->in_count++; + if (len == 0) { + str->dedup_count++; + return 0; + } str->in_len += len; node = str->root; - c = s[len-1]; for (depth = 0; depth <= len; depth++) { struct strbuf_child_entry search; @@ -158,15 +137,11 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { c = s[len - 1 - depth]; - /* bsearch is not allowed on a NULL sequence */ - if (node->children_count == 0) - break; - /* lookup child node */ search.c = c; - child = bsearch(&search, node->children, node->children_count, - sizeof(struct strbuf_child_entry), - (__compar_fn_t) strbuf_children_cmp); + child = bsearch_safe(&search, node->children, node->children_count, + sizeof(struct strbuf_child_entry), + (__compar_fn_t) strbuf_children_cmp); if (!child) break; node = child->child; @@ -183,11 +158,13 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { str->buf[str->len++] = '\0'; /* new node */ - node_child = new0(struct strbuf_node, 1); + node_child = new(struct strbuf_node, 1); if (!node_child) return -ENOMEM; - node_child->value_off = off; - node_child->value_len = len; + *node_child = (struct strbuf_node) { + .value_off = off, + .value_len = len, + }; /* extend array, add new entry, sort for bisection */ child = reallocarray(node->children, node->children_count + 1, sizeof(struct strbuf_child_entry)); diff --git a/src/basic/strbuf.h b/src/basic/strbuf.h index d5888a06dc..75ed30b05b 100644 --- a/src/basic/strbuf.h +++ b/src/basic/strbuf.h @@ -1,29 +1,13 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2012 Kay Sievers <kay@vrfy.org> - - 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 <stddef.h> #include <stdint.h> #include <sys/types.h> +#include "macro.h" + struct strbuf { char *buf; size_t len; @@ -53,3 +37,4 @@ struct strbuf *strbuf_new(void); ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len); void strbuf_complete(struct strbuf *str); void strbuf_cleanup(struct strbuf *str); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct strbuf*, strbuf_cleanup); diff --git a/src/basic/string-table.c b/src/basic/string-table.c index d4b7c69bdc..34931b03d8 100644 --- a/src/basic/string-table.c +++ b/src/basic/string-table.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 "string-table.h" #include "string-util.h" diff --git a/src/basic/string-table.h b/src/basic/string-table.h index 4306b90f46..9bd7879355 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -2,25 +2,6 @@ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <stddef.h> #include <stdio.h> @@ -90,16 +71,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return (type) -1; \ } \ - #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_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) #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_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) #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) @@ -111,10 +89,24 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k /* For string conversions where numbers are also acceptable */ #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \ - struct __useless_struct_to_allow_trailing_semicolon__ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static) + +#define DUMP_STRING_TABLE(name,type,max) \ + do { \ + type _k; \ + flockfile(stdout); \ + for (_k = 0; _k < (max); _k++) { \ + const char *_t; \ + _t = name##_to_string(_k); \ + if (!_t) \ + continue; \ + fputs_unlocked(_t, stdout); \ + fputc_unlocked('\n', stdout); \ + } \ + funlockfile(stdout); \ + } while(false) diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 9f2c01d864..0a40683493 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <stdarg.h> @@ -27,12 +9,15 @@ #include <string.h> #include "alloc-util.h" +#include "escape.h" #include "gunicode.h" +#include "locale-util.h" #include "macro.h" #include "string-util.h" #include "terminal-util.h" #include "utf8.h" #include "util.h" +#include "fileio.h" int strcmp_ptr(const char *a, const char *b) { @@ -279,23 +264,12 @@ char *strjoin_real(const char *x, ...) { } char *strstrip(char *s) { - char *e; - if (!s) return NULL; - /* Drops trailing whitespace. Modifies the string in - * place. Returns pointer to first non-space character */ - - s += strspn(s, WHITESPACE); - - for (e = strchr(s, 0); e > s; e --) - if (!strchr(WHITESPACE, e[-1])) - break; - - *e = 0; + /* Drops trailing whitespace. Modifies the string in place. Returns pointer to first non-space character */ - return s; + return delete_trailing_chars(skip_leading_chars(s, WHITESPACE), WHITESPACE); } char *delete_chars(char *s, const char *bad) { @@ -464,94 +438,154 @@ bool string_has_cc(const char *p, const char *ok) { return false; } +static int write_ellipsis(char *buf, bool unicode) { + if (unicode || is_locale_utf8()) { + buf[0] = 0xe2; /* tri-dot ellipsis: … */ + buf[1] = 0x80; + buf[2] = 0xa6; + } else { + buf[0] = '.'; + buf[1] = '.'; + buf[2] = '.'; + } + + return 3; +} + static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *r; + size_t x, need_space, suffix_len; + char *t; assert(s); assert(percent <= 100); - assert(new_length >= 3); + assert(new_length != (size_t) -1); - if (old_length <= 3 || old_length <= new_length) + if (old_length <= new_length) return strndup(s, old_length); - r = new0(char, new_length+3); - if (!r) + /* Special case short ellipsations */ + switch (new_length) { + + case 0: + return strdup(""); + + case 1: + if (is_locale_utf8()) + return strdup("…"); + else + return strdup("."); + + case 2: + if (!is_locale_utf8()) + return strdup(".."); + + break; + + default: + break; + } + + /* Calculate how much space the ellipsis will take up. If we are in UTF-8 mode we only need space for one + * character ("…"), otherwise for three characters ("..."). Note that in both cases we need 3 bytes of storage, + * either for the UTF-8 encoded character or for three ASCII characters. */ + need_space = is_locale_utf8() ? 1 : 3; + + t = new(char, new_length+3); + if (!t) return NULL; - x = (new_length * percent) / 100; + assert(new_length >= need_space); - if (x > new_length - 3) - x = new_length - 3; + x = ((new_length - need_space) * percent + 50) / 100; + assert(x <= new_length - need_space); - memcpy(r, s, x); - r[x] = 0xe2; /* tri-dot ellipsis: … */ - r[x+1] = 0x80; - r[x+2] = 0xa6; - memcpy(r + x + 3, - s + old_length - (new_length - x - 1), - new_length - x - 1); + memcpy(t, s, x); + write_ellipsis(t + x, false); + suffix_len = new_length - x - need_space; + memcpy(t + x + 3, s + old_length - suffix_len, suffix_len); + *(t + x + 3 + suffix_len) = '\0'; - return r; + return t; } char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *e; + size_t x, k, len, len2; const char *i, *j; - unsigned k, len, len2; + char *e; int r; + /* Note that 'old_length' refers to bytes in the string, while 'new_length' refers to character cells taken up + * on screen. This distinction doesn't matter for ASCII strings, but it does matter for non-ASCII UTF-8 + * strings. + * + * Ellipsation is done in a locale-dependent way: + * 1. If the string passed in is fully ASCII and the current locale is not UTF-8, three dots are used ("...") + * 2. Otherwise, a unicode ellipsis is used ("…") + * + * In other words: you'll get a unicode ellipsis as soon as either the string contains non-ASCII characters or + * the current locale is UTF-8. + */ + assert(s); assert(percent <= 100); if (new_length == (size_t) -1) return strndup(s, old_length); - assert(new_length >= 3); + if (new_length == 0) + return strdup(""); - /* if no multibyte characters use ascii_ellipsize_mem for speed */ - if (ascii_is_valid(s)) + /* If no multibyte characters use ascii_ellipsize_mem for speed */ + if (ascii_is_valid_n(s, old_length)) return ascii_ellipsize_mem(s, old_length, new_length, percent); - if (old_length <= 3 || old_length <= new_length) - return strndup(s, old_length); - - x = (new_length * percent) / 100; - - if (x > new_length - 3) - x = new_length - 3; + x = ((new_length - 1) * percent) / 100; + assert(x <= new_length - 1); k = 0; - for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { + for (i = s; i < s + old_length; i = utf8_next_char(i)) { char32_t c; + int w; r = utf8_encoded_to_unichar(i, &c); if (r < 0) return NULL; - k += unichar_iswide(c) ? 2 : 1; - } - if (k > x) /* last character was wide and went over quota */ - x++; + w = unichar_iswide(c) ? 2 : 1; + if (k + w <= x) + k += w; + else + break; + } - for (j = s + old_length; k < new_length && j > i; ) { + for (j = s + old_length; j > i; ) { char32_t c; + int w; + const char *jj; - j = utf8_prev_char(j); - r = utf8_encoded_to_unichar(j, &c); + jj = utf8_prev_char(j); + r = utf8_encoded_to_unichar(jj, &c); if (r < 0) return NULL; - k += unichar_iswide(c) ? 2 : 1; + + w = unichar_iswide(c) ? 2 : 1; + if (k + w <= new_length) { + k += w; + j = jj; + } else + break; } assert(i <= j); /* we don't actually need to ellipsize */ if (i == j) - return memdup(s, old_length + 1); + return memdup_suffix0(s, old_length); - /* make space for ellipsis */ - j = utf8_next_char(j); + /* make space for ellipsis, if possible */ + if (j < s + old_length) + j = utf8_next_char(j); + else if (i > s) + i = utf8_prev_char(i); len = i - s; len2 = s + old_length - j; @@ -565,21 +599,81 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne */ memcpy(e, s, len); - e[len] = 0xe2; /* tri-dot ellipsis: … */ - e[len + 1] = 0x80; - e[len + 2] = 0xa6; - - memcpy(e + len + 3, j, len2 + 1); + write_ellipsis(e + len, true); + memcpy(e + len + 3, j, len2); + *(e + len + 3 + len2) = '\0'; return e; } -char *ellipsize(const char *s, size_t length, unsigned percent) { +char *cellescape(char *buf, size_t len, const char *s) { + /* Escape and ellipsize s into buffer buf of size len. Only non-control ASCII + * characters are copied as they are, everything else is escaped. The result + * is different then if escaping and ellipsization was performed in two + * separate steps, because each sequence is either stored in full or skipped. + * + * This function should be used for logging about strings which expected to + * be plain ASCII in a safe way. + * + * An ellipsis will be used if s is too long. It was always placed at the + * very end. + */ - if (length == (size_t) -1) - return strdup(s); + size_t i = 0, last_char_width[4] = {}, k = 0, j; + + assert(len > 0); /* at least a terminating NUL */ + + for (;;) { + char four[4]; + int w; + + if (*s == 0) /* terminating NUL detected? then we are done! */ + goto done; + + w = cescape_char(*s, four); + if (i + w + 1 > len) /* This character doesn't fit into the buffer anymore? In that case let's + * ellipsize at the previous location */ + break; + + /* OK, there was space, let's add this escaped character to the buffer */ + memcpy(buf + i, four, w); + i += w; + + /* And remember its width in the ring buffer */ + last_char_width[k] = w; + k = (k + 1) % 4; + + s++; + } + + /* Ellipsation is necessary. This means we might need to truncate the string again to make space for 4 + * characters ideally, but the buffer is shorter than that in the first place take what we can get */ + for (j = 0; j < ELEMENTSOF(last_char_width); j++) { - return ellipsize_mem(s, strlen(s), length, percent); + if (i + 4 <= len) /* nice, we reached our space goal */ + break; + + k = k == 0 ? 3 : k - 1; + if (last_char_width[k] == 0) /* bummer, we reached the beginning of the strings */ + break; + + assert(i >= last_char_width[k]); + i -= last_char_width[k]; + } + + if (i + 4 <= len) /* yay, enough space */ + i += write_ellipsis(buf + i, false); + else if (i + 3 <= len) { /* only space for ".." */ + buf[i++] = '.'; + buf[i++] = '.'; + } else if (i + 2 <= len) /* only space for a single "." */ + buf[i++] = '.'; + else + assert(i + 1 <= len); + + done: + buf[i] = '\0'; + return buf; } bool nulstr_contains(const char *nulstr, const char *needle) { @@ -664,7 +758,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { enum { STATE_OTHER, STATE_ESCAPE, - STATE_BRACKET + STATE_CSI, + STATE_CSO, } state = STATE_OTHER; char *obuf = NULL; size_t osz = 0, isz, shift[2] = {}; @@ -673,7 +768,17 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { assert(ibuf); assert(*ibuf); - /* Strips ANSI color and replaces TABs by 8 spaces */ + /* This does three things: + * + * 1. Replaces TABs by 8 spaces + * 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences + * 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' … BEL sequences + * + * Everything else will be left as it is. In particular other ANSI sequences are left as they are, as are any + * other special characters. Truncated ANSI sequences are left-as is too. This call is supposed to suppress the + * most basic formatting noise, but nothing else. + * + * Why care for CSO sequences? Well, to undo what terminal_urlify() and friends generate. */ isz = _isz ? *_isz : strlen(*ibuf); @@ -708,8 +813,11 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { fputc('\x1B', f); advance_offsets(i - *ibuf, highlight, shift, 1); break; - } else if (*i == '[') { - state = STATE_BRACKET; + } else if (*i == '[') { /* ANSI CSI */ + state = STATE_CSI; + begin = i + 1; + } else if (*i == ']') { /* ANSI CSO */ + state = STATE_CSO; begin = i + 1; } else { fputc('\x1B', f); @@ -720,10 +828,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { break; - case STATE_BRACKET: + case STATE_CSI: - if (i >= *ibuf + isz || /* EOT */ - (!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) { + if (i >= *ibuf + isz || /* EOT … */ + !strchr("01234567890;m", *i)) { /* … or invalid chars in sequence */ fputc('\x1B', f); fputc('[', f); advance_offsets(i - *ibuf, highlight, shift, 2); @@ -731,11 +839,26 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { i = begin-1; } else if (*i == 'm') state = STATE_OTHER; + + break; + + case STATE_CSO: + + if (i >= *ibuf + isz || /* EOT … */ + (*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */ + fputc('\x1B', f); + fputc(']', f); + advance_offsets(i - *ibuf, highlight, shift, 2); + state = STATE_OTHER; + i = begin-1; + } else if (*i == '\a') + state = STATE_OTHER; + break; } } - if (ferror(f)) { + if (fflush_and_check(f) < 0) { fclose(f); return mfree(obuf); } diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 08eda4fce0..c0cc4e78d7 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <alloca.h> #include <stdbool.h> #include <stddef.h> @@ -71,7 +52,7 @@ static inline const char *empty_to_null(const char *p) { return isempty(p) ? NULL : p; } -static inline const char *strdash_if_empty(const char *str) { +static inline const char *empty_to_dash(const char *str) { return isempty(str) ? "-" : str; } @@ -122,7 +103,7 @@ char *strjoin_real(const char *x, ...) _sentinel_; const char *_appendees_[] = { a, __VA_ARGS__ }; \ char *_d_, *_p_; \ size_t _len_ = 0; \ - unsigned _i_; \ + size_t _i_; \ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ _len_ += strlen(_appendees_[_i_]); \ _p_ = _d_ = alloca(_len_ + 1); \ @@ -169,7 +150,14 @@ static inline bool _pure_ in_charset(const char *s, const char* charset) { bool string_has_cc(const char *p, const char *ok) _pure_; char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent); -char *ellipsize(const char *s, size_t length, unsigned percent); +static inline char *ellipsize(const char *s, size_t length, unsigned percent) { + return ellipsize_mem(s, strlen(s), length, percent); +} + +char *cellescape(char *buf, size_t len, const char *s); + +/* This limit is arbitrary, enough to give some idea what the string contains */ +#define CELLESCAPE_DEFAULT_LENGTH 64 bool nulstr_contains(const char *nulstr, const char *needle); @@ -222,3 +210,21 @@ static inline size_t strlen_ptr(const char *s) { return strlen(s); } + +/* Like startswith(), but operates on arbitrary memory blocks */ +static inline void *memory_startswith(const void *p, size_t sz, const char *token) { + size_t n; + + assert(token); + + n = strlen(token); + if (sz < n) + return NULL; + + assert(p); + + if (memcmp(p, token, n) != 0) + return NULL; + + return (uint8_t*) p + n; +} diff --git a/src/basic/strv.c b/src/basic/strv.c index e80ff4a62c..b3716233b5 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <fnmatch.h> @@ -120,8 +102,8 @@ char **strv_copy(char * const *l) { return r; } -unsigned strv_length(char * const *l) { - unsigned n = 0; +size_t strv_length(char * const *l) { + size_t n = 0; if (!l) return 0; @@ -134,8 +116,8 @@ unsigned strv_length(char * const *l) { char **strv_new_ap(const char *x, va_list ap) { const char *s; - char **a; - unsigned n = 0, i = 0; + _cleanup_strv_free_ char **a = NULL; + size_t n = 0, i = 0; va_list aq; /* As a special trick we ignore all listed strings that equal @@ -165,7 +147,7 @@ char **strv_new_ap(const char *x, va_list ap) { if (x != STRV_IGNORE) { a[i] = strdup(x); if (!a[i]) - goto fail; + return NULL; i++; } @@ -176,7 +158,7 @@ char **strv_new_ap(const char *x, va_list ap) { a[i] = strdup(s); if (!a[i]) - goto fail; + return NULL; i++; } @@ -184,11 +166,7 @@ char **strv_new_ap(const char *x, va_list ap) { a[i] = NULL; - return a; - -fail: - strv_free(a); - return NULL; + return TAKE_PTR(a); } char **strv_new(const char *x, ...) { @@ -270,7 +248,7 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { char **strv_split(const char *s, const char *separator) { const char *word, *state; size_t l; - unsigned n, i; + size_t n, i; char **r; assert(s); @@ -300,7 +278,7 @@ char **strv_split(const char *s, const char *separator) { char **strv_split_newlines(const char *s) { char **l; - unsigned n; + size_t n; assert(s); @@ -341,8 +319,7 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract if (!GREEDY_REALLOC(l, allocated, n + 2)) return -ENOMEM; - l[n++] = word; - word = NULL; + l[n++] = TAKE_PTR(word); l[n] = NULL; } @@ -353,8 +330,7 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract return -ENOMEM; } - *t = l; - l = NULL; + *t = TAKE_PTR(l); return (int) n; } @@ -395,7 +371,7 @@ char *strv_join(char **l, const char *separator) { int strv_push(char ***l, char *value) { char **c; - unsigned n, m; + size_t n, m; if (!value) return 0; @@ -420,7 +396,7 @@ int strv_push(char ***l, char *value) { int strv_push_pair(char ***l, char *a, char *b) { char **c; - unsigned n, m; + size_t n, m; if (!a && !b) return 0; @@ -446,9 +422,9 @@ int strv_push_pair(char ***l, char *a, char *b) { return 0; } -int strv_insert(char ***l, unsigned position, char *value) { +int strv_insert(char ***l, size_t position, char *value) { char **c; - unsigned n, m, i; + size_t n, m, i; if (!value) return 0; @@ -616,7 +592,7 @@ char **strv_parse_nulstr(const char *s, size_t l) { */ const char *p; - unsigned c = 0, i = 0; + size_t c = 0, i = 0; char **v; assert(s || l <= 0); @@ -780,7 +756,7 @@ int strv_extendf(char ***l, const char *format, ...) { } char **strv_reverse(char **l) { - unsigned n, i; + size_t n, i; n = strv_length(l); if (n <= 1) diff --git a/src/basic/strv.h b/src/basic/strv.h index f169ac5d4f..51d03db940 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <fnmatch.h> #include <stdarg.h> #include <stdbool.h> @@ -45,7 +26,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase); void strv_clear(char **l); char **strv_copy(char * const *l); -unsigned strv_length(char * const *l) _pure_; +size_t strv_length(char * const *l) _pure_; int strv_extend_strv(char ***a, char **b, bool filter_duplicates); int strv_extend_strv_concat(char ***a, char **b, const char *suffix); @@ -54,7 +35,7 @@ int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_extend_front(char ***l, const char *value); int strv_push(char ***l, char *value); int strv_push_pair(char ***l, char *a, char *b); -int strv_insert(char ***l, unsigned position, char *value); +int strv_insert(char ***l, size_t position, char *value); static inline int strv_push_prepend(char ***l, char *value) { return strv_insert(l, 0, value); @@ -126,7 +107,7 @@ void strv_print(char **l); if (!first) \ _l = (char**) &first; \ else { \ - unsigned _n; \ + size_t _n; \ va_list _ap; \ \ _n = 1; \ diff --git a/src/basic/strxcpyx.c b/src/basic/strxcpyx.c index b440a9a725..6277f56b80 100644 --- a/src/basic/strxcpyx.c +++ b/src/basic/strxcpyx.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Kay Sievers - - 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/>. -***/ /* * Concatenates/copies strings. In any case, terminates in all cases diff --git a/src/basic/strxcpyx.h b/src/basic/strxcpyx.h index 0554454fd2..458f9f2568 100644 --- a/src/basic/strxcpyx.h +++ b/src/basic/strxcpyx.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Kay Sievers - - 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 <stddef.h> diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c index 4f4e2354b6..21461fa581 100644 --- a/src/basic/syslog-util.c +++ b/src/basic/syslog-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <string.h> #include <syslog.h> diff --git a/src/basic/syslog-util.h b/src/basic/syslog-util.h index 8f44e3f8ef..8f419e8151 100644 --- a/src/basic/syslog-util.h +++ b/src/basic/syslog-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> int log_facility_unshifted_to_string_alloc(int i, char **s); diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index eacfd14677..f4af0e6522 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -1,45 +1,30 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> #include <limits.h> +#include <linux/kd.h> +#include <linux/tiocl.h> +#include <linux/vt.h> +#include <poll.h> +#include <signal.h> #include <stdarg.h> #include <stddef.h> #include <stdlib.h> #include <string.h> #include <sys/inotify.h> +#include <sys/ioctl.h> #include <sys/socket.h> #include <sys/sysmacros.h> #include <sys/time.h> -#include <linux/kd.h> -#include <linux/tiocl.h> -#include <linux/vt.h> -#include <poll.h> -#include <signal.h> -#include <sys/ioctl.h> #include <sys/types.h> +#include <sys/utsname.h> #include <termios.h> #include <unistd.h> #include "alloc-util.h" +#include "copy.h" +#include "def.h" #include "env-util.h" #include "fd-util.h" #include "fileio.h" @@ -47,6 +32,7 @@ #include "io-util.h" #include "log.h" #include "macro.h" +#include "pager.h" #include "parse-util.h" #include "path-util.h" #include "proc-cmdline.h" @@ -496,10 +482,7 @@ int acquire_terminal( fd = safe_close(fd); } - r = fd; - fd = -1; - - return r; + return TAKE_FD(fd); } int release_terminal(void) { @@ -707,10 +690,9 @@ int vtnr_from_tty(const char *tty) { tty = active; } - if (tty == active) { - *ret = active; - active = NULL; - } else { + if (tty == active) + *ret = TAKE_PTR(active); + else { char *tmp; tmp = strdup(tty); @@ -778,8 +760,7 @@ int get_kernel_consoles(char ***ret) { goto fallback; } - *ret = l; - l = NULL; + *ret = TAKE_PTR(l); return 0; @@ -788,8 +769,7 @@ fallback: if (r < 0) return r; - *ret = l; - l = NULL; + *ret = TAKE_PTR(l); return 0; } @@ -899,8 +879,17 @@ void reset_terminal_feature_caches(void) { } bool on_tty(void) { + + /* We check both stdout and stderr, so that situations where pipes on the shell are used are reliably + * recognized, regardless if only the output or the errors are piped to some place. Since on_tty() is generally + * used to default to a safer, non-interactive, non-color mode of operation it's probably good to be defensive + * here, and check for both. Note that we don't check for STDIN_FILENO, because it should fine to use fancy + * terminal functionality when outputting stuff, even if the input is piped to us. */ + if (cached_on_tty < 0) - cached_on_tty = isatty(STDOUT_FILENO) > 0; + cached_on_tty = + isatty(STDOUT_FILENO) > 0 && + isatty(STDERR_FILENO) > 0; return cached_on_tty; } @@ -1288,3 +1277,175 @@ int vt_reset_keyboard(int fd) { return 0; } + +static bool urlify_enabled(void) { + static int cached_urlify_enabled = -1; + + /* Unfortunately 'less' doesn't support links like this yet 😭, hence let's disable this as long as there's a + * pager in effect. Let's drop this check as soon as less got fixed a and enough time passed so that it's safe + * to assume that a link-enabled 'less' version has hit most installations. */ + + if (cached_urlify_enabled < 0) { + int val; + + val = getenv_bool("SYSTEMD_URLIFY"); + if (val >= 0) + cached_urlify_enabled = val; + else + cached_urlify_enabled = colors_enabled() && !pager_have(); + } + + return cached_urlify_enabled; +} + +int terminal_urlify(const char *url, const char *text, char **ret) { + char *n; + + assert(url); + + /* Takes an URL and a pretty string and formats it as clickable link for the terminal. See + * https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda for details. */ + + if (isempty(text)) + text = url; + + if (urlify_enabled()) + n = strjoin("\x1B]8;;", url, "\a", text, "\x1B]8;;\a"); + else + n = strdup(text); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +int terminal_urlify_path(const char *path, const char *text, char **ret) { + _cleanup_free_ char *absolute = NULL; + struct utsname u; + const char *url; + int r; + + assert(path); + + /* Much like terminal_urlify() above, but takes a file system path as input + * and turns it into a proper file:// URL first. */ + + if (isempty(path)) + return -EINVAL; + + if (isempty(text)) + text = path; + + if (!urlify_enabled()) { + char *n; + + n = strdup(text); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; + } + + if (uname(&u) < 0) + return -errno; + + if (!path_is_absolute(path)) { + r = path_make_absolute_cwd(path, &absolute); + if (r < 0) + return r; + + path = absolute; + } + + /* As suggested by https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda, let's include the local + * hostname here. Note that we don't use gethostname_malloc() or gethostname_strict() since we are interested + * in the raw string the kernel has set, whatever it may be, under the assumption that terminals are not overly + * careful with validating the strings either. */ + + url = strjoina("file://", u.nodename, path); + + return terminal_urlify(url, text, ret); +} + +static int cat_file(const char *filename, bool newline) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *urlified = NULL; + int r; + + f = fopen(filename, "re"); + if (!f) + return -errno; + + r = terminal_urlify_path(filename, NULL, &urlified); + if (r < 0) + return r; + + printf("%s%s# %s%s\n", + newline ? "\n" : "", + ansi_highlight_blue(), + urlified, + ansi_normal()); + fflush(stdout); + + for (;;) { + _cleanup_free_ char *line = NULL; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read \"%s\": %m", filename); + if (r == 0) + break; + + puts(line); + } + + return 0; +} + +int cat_files(const char *file, char **dropins, CatFlags flags) { + char **path; + int r; + + if (file) { + r = cat_file(file, false); + if (r == -ENOENT && (flags & CAT_FLAGS_MAIN_FILE_OPTIONAL)) + printf("%s# config file %s not found%s\n", + ansi_highlight_magenta(), + file, + ansi_normal()); + else if (r < 0) + return log_warning_errno(r, "Failed to cat %s: %m", file); + } + + STRV_FOREACH(path, dropins) { + r = cat_file(*path, file || path != dropins); + if (r < 0) + return log_warning_errno(r, "Failed to cat %s: %m", *path); + } + + return 0; +} + +void print_separator(void) { + + /* Outputs a separator line that resolves to whitespace when copied from the terminal. We do that by outputting + * one line filled with spaces with ANSI underline set, followed by a second (empty) line. */ + + if (underline_enabled()) { + size_t i, c; + + c = columns(); + + flockfile(stdout); + fputs_unlocked(ANSI_UNDERLINE, stdout); + + for (i = 0; i < c; i++) + fputc_unlocked(' ', stdout); + + fputs_unlocked(ANSI_NORMAL "\n\n", stdout); + funlockfile(stdout); + } else + fputs("\n\n", stdout); +} diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index b57157e3bb..c0bd0e67a6 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdarg.h> #include <stdbool.h> #include <stdio.h> @@ -80,16 +61,16 @@ int open_terminal(const char *name, int mode); /* Flags for tweaking the way we become the controlling process of a terminal. */ typedef enum AcquireTerminalFlags { /* Try to become the controlling process of the TTY. If we can't return -EPERM. */ - ACQUIRE_TERMINAL_TRY = 0, + ACQUIRE_TERMINAL_TRY = 0, /* Tell the kernel to forcibly make us the controlling process of the TTY. Returns -EPERM if the kernel doesn't allow that. */ - ACQUIRE_TERMINAL_FORCE = 1, + ACQUIRE_TERMINAL_FORCE = 1, /* If we can't become the controlling process of the TTY right-away, then wait until we can. */ - ACQUIRE_TERMINAL_WAIT = 2, + ACQUIRE_TERMINAL_WAIT = 2, /* Pick one of the above, and then OR this flag in, in order to request permissive behaviour, if we can't become controlling process then don't mind */ - ACQUIRE_TERMINAL_PERMISSIVE = 4, + ACQUIRE_TERMINAL_PERMISSIVE = 1 << 2, } AcquireTerminalFlags; int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout); @@ -133,22 +114,20 @@ bool dev_console_colors_enabled(void); #define DEFINE_ANSI_FUNC(name, NAME) \ static inline const char *ansi_##name(void) { \ return colors_enabled() ? ANSI_##NAME : ""; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ + } #define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME, REPLACEMENT) \ static inline const char *ansi_##name(void) { \ return underline_enabled() ? ANSI_##NAME : \ colors_enabled() ? ANSI_##REPLACEMENT : ""; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - + } DEFINE_ANSI_FUNC(highlight, HIGHLIGHT); DEFINE_ANSI_FUNC(highlight_red, HIGHLIGHT_RED); DEFINE_ANSI_FUNC(highlight_green, HIGHLIGHT_GREEN); DEFINE_ANSI_FUNC(highlight_yellow, HIGHLIGHT_YELLOW); DEFINE_ANSI_FUNC(highlight_blue, HIGHLIGHT_BLUE); +DEFINE_ANSI_FUNC(highlight_magenta, HIGHLIGHT_MAGENTA); DEFINE_ANSI_FUNC(normal, NORMAL); DEFINE_ANSI_FUNC_UNDERLINE(underline, UNDERLINE, NORMAL); @@ -172,3 +151,14 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode); int vt_default_utf8(void); int vt_reset_keyboard(int fd); + +int terminal_urlify(const char *url, const char *text, char **ret); +int terminal_urlify_path(const char *path, const char *text, char **ret); + +typedef enum CatFlags { + CAT_FLAGS_MAIN_FILE_OPTIONAL = 1 << 0, +} CatFlags; + +int cat_files(const char *file, char **dropins, CatFlags flags); + +void print_separator(void); diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 4a341e208f..fe201c398d 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <limits.h> @@ -34,11 +16,13 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "io-util.h" #include "log.h" #include "macro.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "stat-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -293,8 +277,11 @@ static char *format_timestamp_internal( return NULL; /* Timestamp is unset */ /* Let's not format times with years > 9999 */ - if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) - return NULL; + if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) { + assert(l >= strlen("--- XXXX-XX-XX XX:XX:XX") + 1); + strcpy(buf, "--- XXXX-XX-XX XX:XX:XX"); + return buf; + } sec = (time_t) (t / USEC_PER_SEC); /* Round down */ @@ -447,7 +434,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { { "us", 1 }, }; - unsigned i; + size_t i; char *p = buf; bool something = false; @@ -492,7 +479,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { /* Let's see if we should shows this in dot notation */ if (t < USEC_PER_MINUTE && b > 0) { usec_t cc; - int j; + signed char j; j = 0; for (cc = table[i].usec; cc > 1; cc /= 10) @@ -625,10 +612,9 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { time_t x; usec_t x_usec, plus = 0, minus = 0, ret; int r, weekday = -1, dst = -1; - unsigned i; + size_t i; - /* - * Allowed syntaxes: + /* Allowed syntaxes: * * 2012-09-22 16:34:22 * 2012-09-22 16:34 (seconds will be set to 0) @@ -642,7 +628,6 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { * +5min * -5days * @2147483647 (seconds since epoch) - * */ assert(t); @@ -701,10 +686,10 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { tzset(); /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only - * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because - * there are no nice APIs available to cover this. By accepting the local time zone strings, we make - * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't - * support arbitrary timezone specifications. */ + * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because + * there are no nice APIs available to cover this. By accepting the local time zone strings, we make + * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't + * support arbitrary timezone specifications. */ for (j = 0; j <= 1; j++) { @@ -890,7 +875,7 @@ int parse_timestamp(const char *t, usec_t *usec) { int r; last_space = strrchr(t, ' '); - if (last_space != NULL && timezone_is_valid(last_space + 1)) + if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG)) tz = last_space + 1; if (!tz || endswith_no_case(t, " UTC")) @@ -916,10 +901,10 @@ int parse_timestamp(const char *t, usec_t *usec) { tzset(); /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation. - * Otherwise just cut it off */ + * Otherwise just cut it off. */ with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]); - /*cut off the timezone if we dont need it*/ + /* Cut off the timezone if we dont need it. */ if (with_tz) t = strndupa(t, last_space - t); @@ -973,7 +958,7 @@ static char* extract_multiplier(char *p, usec_t *multiplier) { { "us", 1ULL }, { "µs", 1ULL }, }; - unsigned i; + size_t i; for (i = 0; i < ELEMENTSOF(table); i++) { char *e; @@ -1147,8 +1132,8 @@ int parse_nsec(const char *t, nsec_t *nsec) { for (;;) { long long l, z = 0; + size_t n = 0, i; char *e; - unsigned i, n = 0; p += strspn(p, WHITESPACE); @@ -1283,16 +1268,17 @@ int get_timezones(char ***ret) { } else if (errno != ENOENT) return -errno; - *ret = zones; - zones = NULL; + *ret = TAKE_PTR(zones); return 0; } -bool timezone_is_valid(const char *name) { +bool timezone_is_valid(const char *name, int log_level) { bool slash = false; const char *p, *t; - struct stat st; + _cleanup_close_ int fd = -1; + char buf[4]; + int r; if (isempty(name)) return false; @@ -1320,12 +1306,34 @@ bool timezone_is_valid(const char *name) { if (slash) return false; + if (p - name >= PATH_MAX) + return false; + t = strjoina("/usr/share/zoneinfo/", name); - if (stat(t, &st) < 0) + + fd = open(t, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t); + return false; + } + + r = fd_verify_regular(fd); + if (r < 0) { + log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t); + return false; + } + + r = loop_read_exact(fd, buf, 4, false); + if (r < 0) { + log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t); return false; + } - if (!S_ISREG(st.st_mode)) + /* Magic from tzfile(5) */ + if (memcmp(buf, "TZif", 4) != 0) { + log_full(log_level, "Timezone file '%s' has wrong magic bytes", t); return false; + } return true; } @@ -1396,7 +1404,7 @@ int get_timezone(char **tz) { if (!e) return -EINVAL; - if (!timezone_is_valid(e)) + if (!timezone_is_valid(e, LOG_DEBUG)) return -EINVAL; z = strdup(e); @@ -1453,3 +1461,27 @@ bool in_utc_timezone(void) { return timezone == 0 && daylight == 0; } + +int time_change_fd(void) { + + /* We only care for the cancellation event, hence we set the timeout to the latest possible value. */ + static const struct itimerspec its = { + .it_value.tv_sec = TIME_T_MAX, + }; + + _cleanup_close_ int fd; + + assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX)); + + /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever CLOCK_REALTIME makes a jump relative to + * CLOCK_MONOTONIC. */ + + fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (fd < 0) + return -errno; + + if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) + return -errno; + + return TAKE_FD(fd); +} diff --git a/src/basic/time-util.h b/src/basic/time-util.h index a8c5a8375b..344f2dc52e 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <inttypes.h> #include <stdbool.h> #include <stddef.h> @@ -141,7 +122,7 @@ int parse_nsec(const char *t, nsec_t *nsec); bool ntp_synced(void); int get_timezones(char ***l); -bool timezone_is_valid(const char *name); +bool timezone_is_valid(const char *name, int log_level); bool clock_boottime_supported(void); bool clock_supported(clockid_t clock); @@ -196,5 +177,7 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) { /* With a 32bit time_t we can't go beyond 2038... */ #define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000) #else -#error "Yuck, time_t is neither 4 not 8 bytes wide?" +#error "Yuck, time_t is neither 4 nor 8 bytes wide?" #endif + +int time_change_fd(void); diff --git a/src/basic/umask-util.h b/src/basic/umask-util.h index 638b37d7de..e964292eaf 100644 --- a/src/basic/umask-util.h +++ b/src/basic/umask-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <sys/stat.h> #include <sys/types.h> diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h index 73302b4239..8a1d06445e 100644 --- a/src/basic/unaligned.h +++ b/src/basic/unaligned.h @@ -1,24 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen - - 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 <endian.h> #include <stdint.h> diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index 387533f597..ac6a9b37e8 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 "alloc-util.h" #include "bus-label.h" @@ -106,6 +88,7 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { [UNIT_STUB] = "stub", [UNIT_LOADED] = "loaded", [UNIT_NOT_FOUND] = "not-found", + [UNIT_BAD_SETTING] = "bad-setting", [UNIT_ERROR] = "error", [UNIT_MERGED] = "merged", [UNIT_MASKED] = "masked" diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index c142e069a6..d7e2d74669 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include "macro.h" @@ -43,8 +24,9 @@ typedef enum UnitType { typedef enum UnitLoadState { UNIT_STUB = 0, UNIT_LOADED, - UNIT_NOT_FOUND, - UNIT_ERROR, + UNIT_NOT_FOUND, /* error condition #1: unit file not found */ + UNIT_BAD_SETTING, /* error condition #2: we couldn't parse some essential unit file setting */ + UNIT_ERROR, /* error condition #3: other "system" error, catchall for the rest */ UNIT_MERGED, UNIT_MASKED, _UNIT_LOAD_STATE_MAX, diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index 0fa0472ee1..1b81fe268f 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <stddef.h> @@ -254,25 +236,43 @@ int unit_name_change_suffix(const char *n, const char *suffix, char **ret) { } int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) { - char *s; + UnitType type; assert(prefix); assert(suffix); assert(ret); + if (suffix[0] != '.') + return -EINVAL; + + type = unit_type_from_string(suffix + 1); + if (type < 0) + return -EINVAL; + + return unit_name_build_from_type(prefix, instance, type, ret); +} + +int unit_name_build_from_type(const char *prefix, const char *instance, UnitType type, char **ret) { + const char *ut; + char *s; + + assert(prefix); + assert(type >= 0); + assert(type < _UNIT_TYPE_MAX); + assert(ret); + if (!unit_prefix_is_valid(prefix)) return -EINVAL; if (instance && !unit_instance_is_valid(instance)) return -EINVAL; - if (!unit_suffix_is_valid(suffix)) - return -EINVAL; + ut = unit_type_to_string(type); if (!instance) - s = strappend(prefix, suffix); + s = strjoin(prefix, ".", ut); else - s = strjoin(prefix, "@", instance, suffix); + s = strjoin(prefix, "@", instance, ".", ut); if (!s) return -ENOMEM; @@ -363,8 +363,7 @@ int unit_name_unescape(const char *f, char **ret) { *t = 0; - *ret = r; - r = NULL; + *ret = TAKE_PTR(r); return 0; } @@ -379,9 +378,9 @@ int unit_name_path_escape(const char *f, char **ret) { if (!p) return -ENOMEM; - path_kill_slashes(p); + path_simplify(p, false); - if (STR_IN_SET(p, "/", "")) + if (empty_or_root(p)) s = strdup("-"); else { if (!path_is_normalized(p)) @@ -569,28 +568,32 @@ int unit_name_to_path(const char *name, char **ret) { return unit_name_path_unescape(prefix, ret); } -static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) { +static bool do_escape_mangle(const char *f, bool allow_globs, char *t) { const char *valid_chars; + bool mangled = false; assert(f); - assert(IN_SET(allow_globs, UNIT_NAME_GLOB, UNIT_NAME_NOGLOB)); assert(t); - /* We'll only escape the obvious characters here, to play - * safe. */ + /* We'll only escape the obvious characters here, to play safe. + * + * Returns true if any characters were mangled, false otherwise. + */ - valid_chars = allow_globs == UNIT_NAME_GLOB ? VALID_CHARS_GLOB : VALID_CHARS_WITH_AT; + valid_chars = allow_globs ? VALID_CHARS_GLOB : VALID_CHARS_WITH_AT; - for (; *f; f++) { - if (*f == '/') + for (; *f; f++) + if (*f == '/') { *(t++) = '-'; - else if (!strchr(valid_chars, *f)) + mangled = true; + } else if (!strchr(valid_chars, *f)) { t = do_escape_char(*f, t); - else + mangled = true; + } else *(t++) = *f; - } + *t = 0; - return t; + return mangled; } /** @@ -600,9 +603,10 @@ static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t * * If @allow_globs, globs characters are preserved. Otherwise, they are escaped. */ -int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) { - char *s, *t; +int unit_name_mangle_with_suffix(const char *name, UnitNameMangle flags, const char *suffix, char **ret) { + char *s; int r; + bool mangled; assert(name); assert(suffix); @@ -619,7 +623,7 @@ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, c goto good; /* Already a fully valid globbing expression? If so, no mangling is necessary either... */ - if (allow_globs == UNIT_NAME_GLOB && + if ((flags & UNIT_NAME_MANGLE_GLOB) && string_is_glob(name) && in_charset(name, VALID_CHARS_GLOB)) goto good; @@ -644,13 +648,16 @@ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, c if (!s) return -ENOMEM; - t = do_escape_mangle(name, allow_globs, s); - *t = 0; + mangled = do_escape_mangle(name, flags & UNIT_NAME_MANGLE_GLOB, s); + if (mangled) + log_full(flags & UNIT_NAME_MANGLE_WARN ? LOG_NOTICE : LOG_DEBUG, + "Invalid unit name \"%s\" was escaped as \"%s\" (maybe you should use systemd-escape?)", + name, s); /* Append a suffix if it doesn't have any, but only if this is not a glob, so that we can allow "foo.*" as a * valid glob. */ - if ((allow_globs != UNIT_NAME_GLOB || !string_is_glob(s)) && unit_name_to_type(s) < 0) - strcpy(t, suffix); + if ((!(flags & UNIT_NAME_MANGLE_GLOB) || !string_is_glob(s)) && unit_name_to_type(s) < 0) + strcat(s, suffix); *ret = s; return 1; @@ -698,7 +705,7 @@ int slice_build_parent_slice(const char *slice, char **ret) { return 1; } -int slice_build_subslice(const char *slice, const char*name, char **ret) { +int slice_build_subslice(const char *slice, const char *name, char **ret) { char *subslice; assert(slice); diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index b47327dcaf..61abcd585b 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include "macro.h" @@ -53,6 +34,7 @@ UnitType unit_name_to_type(const char *n) _pure_; int unit_name_change_suffix(const char *n, const char *suffix, char **ret); int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret); +int unit_name_build_from_type(const char *prefix, const char *instance, UnitType, char **ret); char *unit_name_escape(const char *f); int unit_name_unescape(const char *f, char **ret); @@ -68,14 +50,14 @@ int unit_name_from_path_instance(const char *prefix, const char *path, const cha int unit_name_to_path(const char *name, char **ret); typedef enum UnitNameMangle { - UNIT_NAME_NOGLOB, - UNIT_NAME_GLOB, + UNIT_NAME_MANGLE_GLOB = 1, + UNIT_NAME_MANGLE_WARN = 2, } UnitNameMangle; -int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret); +int unit_name_mangle_with_suffix(const char *name, UnitNameMangle flags, const char *suffix, char **ret); -static inline int unit_name_mangle(const char *name, UnitNameMangle allow_globs, char **ret) { - return unit_name_mangle_with_suffix(name, allow_globs, ".service", ret); +static inline int unit_name_mangle(const char *name, UnitNameMangle flags, char **ret) { + return unit_name_mangle_with_suffix(name, flags, ".service", ret); } int slice_build_parent_slice(const char *slice, char **ret); diff --git a/src/basic/user-util.c b/src/basic/user-util.c index ceb71b61e8..a562a397c7 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <alloca.h> #include <errno.h> @@ -234,8 +216,7 @@ int get_user_creds_clean( (isempty(*shell) || is_nologin_shell(*shell))) *shell = NULL; - if (home && - (isempty(*home) || path_equal(*home, "/"))) + if (home && empty_or_root(*home)) *home = NULL; return 0; @@ -734,3 +715,111 @@ bool synthesize_nobody(void) { return cache; #endif } + +int putpwent_sane(const struct passwd *pw, FILE *stream) { + assert(pw); + assert(stream); + + errno = 0; + if (putpwent(pw, stream) != 0) + return errno > 0 ? -errno : -EIO; + + return 0; +} + +int putspent_sane(const struct spwd *sp, FILE *stream) { + assert(sp); + assert(stream); + + errno = 0; + if (putspent(sp, stream) != 0) + return errno > 0 ? -errno : -EIO; + + return 0; +} + +int putgrent_sane(const struct group *gr, FILE *stream) { + assert(gr); + assert(stream); + + errno = 0; + if (putgrent(gr, stream) != 0) + return errno > 0 ? -errno : -EIO; + + return 0; +} + +#if ENABLE_GSHADOW +int putsgent_sane(const struct sgrp *sg, FILE *stream) { + assert(sg); + assert(stream); + + errno = 0; + if (putsgent(sg, stream) != 0) + return errno > 0 ? -errno : -EIO; + + return 0; +} +#endif + +int fgetpwent_sane(FILE *stream, struct passwd **pw) { + struct passwd *p; + + assert(pw); + assert(stream); + + errno = 0; + p = fgetpwent(stream); + if (!p && errno != ENOENT) + return errno > 0 ? -errno : -EIO; + + *pw = p; + return !!p; +} + +int fgetspent_sane(FILE *stream, struct spwd **sp) { + struct spwd *s; + + assert(sp); + assert(stream); + + errno = 0; + s = fgetspent(stream); + if (!s && errno != ENOENT) + return errno > 0 ? -errno : -EIO; + + *sp = s; + return !!s; +} + +int fgetgrent_sane(FILE *stream, struct group **gr) { + struct group *g; + + assert(gr); + assert(stream); + + errno = 0; + g = fgetgrent(stream); + if (!g && errno != ENOENT) + return errno > 0 ? -errno : -EIO; + + *gr = g; + return !!g; +} + +#if ENABLE_GSHADOW +int fgetsgent_sane(FILE *stream, struct sgrp **sg) { + struct sgrp *s; + + assert(sg); + assert(stream); + + errno = 0; + s = fgetsgent(stream); + if (!s && errno != ENOENT) + return errno > 0 ? -errno : -EIO; + + *sg = s; + return !!s; +} +#endif diff --git a/src/basic/user-util.h b/src/basic/user-util.h index e1259a1582..b74f168859 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -1,25 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <grp.h> +#include <gshadow.h> +#include <pwd.h> +#include <shadow.h> #include <stdbool.h> #include <stdint.h> #include <sys/types.h> @@ -110,3 +95,14 @@ static inline bool valid_shell(const char *p) { int maybe_setgroups(size_t size, const gid_t *list); bool synthesize_nobody(void); + +int fgetpwent_sane(FILE *stream, struct passwd **pw); +int fgetspent_sane(FILE *stream, struct spwd **sp); +int fgetgrent_sane(FILE *stream, struct group **gr); +int putpwent_sane(const struct passwd *pw, FILE *stream); +int putspent_sane(const struct spwd *sp, FILE *stream); +int putgrent_sane(const struct group *gr, FILE *stream); +#ifdef ENABLE_GSHADOW +int fgetsgent_sane(FILE *stream, struct sgrp **sg); +int putsgent_sane(const struct sgrp *sg, FILE *stream); +#endif diff --git a/src/basic/utf8.c b/src/basic/utf8.c index b17f420264..a5ce1a2944 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -1,23 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2008-2011 Kay Sievers - Copyright 2012 Lennart Poettering - - 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/>. -***/ /* Parts of this file are based on the GLIB utf8 validation functions. The * original license text follows. */ @@ -48,6 +29,7 @@ #include <string.h> #include "alloc-util.h" +#include "gunicode.h" #include "hexdecoct.h" #include "macro.h" #include "utf8.h" @@ -259,6 +241,9 @@ char *utf8_escape_non_printable(const char *str) { char *ascii_is_valid(const char *str) { const char *p; + /* Check whether the string consists of valid ASCII bytes, + * i.e values between 0 and 127, inclusive. */ + assert(str); for (p = str; *p; p++) @@ -268,6 +253,21 @@ char *ascii_is_valid(const char *str) { return (char*) str; } +char *ascii_is_valid_n(const char *str, size_t len) { + size_t i; + + /* Very similar to ascii_is_valid(), but checks exactly len + * bytes and rejects any NULs in that range. */ + + assert(str); + + for (i = 0; i < len; i++) + if ((unsigned char) str[i] >= 128 || str[i] == 0) + return NULL; + + return (char*) str; +} + /** * utf8_encode_unichar() - Encode single UCS-4 character as UTF-8 * @out_utf8: output buffer of at least 4 bytes or NULL @@ -427,3 +427,23 @@ size_t utf8_n_codepoints(const char *str) { return n; } + +size_t utf8_console_width(const char *str) { + size_t n = 0; + + /* Returns the approximate width a string will take on screen when printed on a character cell + * terminal/console. */ + + while (*str != 0) { + char32_t c; + + if (utf8_encoded_to_unichar(str, &c) < 0) + return (size_t) -1; + + str = utf8_next_char(str); + + n += unichar_iswide(c) ? 2 : 1; + } + + return n; +} diff --git a/src/basic/utf8.h b/src/basic/utf8.h index 7128615181..e8af7a576b 100644 --- a/src/basic/utf8.h +++ b/src/basic/utf8.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - 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 <stdbool.h> #include <stddef.h> #include <stdint.h> @@ -35,6 +16,7 @@ bool unichar_is_valid(char32_t c); const char *utf8_is_valid(const char *s) _pure_; char *ascii_is_valid(const char *s) _pure_; +char *ascii_is_valid_n(const char *str, size_t len); bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_; #define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true) @@ -61,3 +43,4 @@ static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t t } size_t utf8_n_codepoints(const char *str); +size_t utf8_console_width(const char *str); diff --git a/src/basic/util.c b/src/basic/util.c index 7863a14fb2..8f2d6061da 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <alloca.h> #include <errno.h> @@ -181,11 +163,13 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, const void *p; int comparison; + assert(!size_multiply_overflow(nmemb, size)); + l = 0; u = nmemb; while (l < u) { idx = (l + u) / 2; - p = (const char *) base + idx * size; + p = (const uint8_t*) base + idx * size; comparison = compar(key, p, arg); if (comparison < 0) u = idx; @@ -275,7 +259,7 @@ int container_get_leader(const char *machine, pid_t *pid) { return -EINVAL; p = strjoina("/run/systemd/machines/", machine); - r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); + r = parse_env_file(NULL, p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); if (r == -ENOENT) return -EHOSTDOWN; if (r < 0) @@ -416,6 +400,7 @@ uint64_t physical_memory(void) { uint64_t mem, lim; size_t ps; long sc; + int r; /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of * memory. @@ -429,13 +414,40 @@ uint64_t physical_memory(void) { ps = page_size(); mem = (uint64_t) sc * (uint64_t) ps; - if (cg_get_root_path(&root) < 0) + r = cg_get_root_path(&root); + if (r < 0) { + log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m"); return mem; + } - if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value)) + r = cg_all_unified(); + if (r < 0) { + log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m"); return mem; + } + if (r > 0) { + r = cg_get_attribute("memory", root, "memory.max", &value); + if (r < 0) { + log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m"); + return mem; + } - if (safe_atou64(value, &lim) < 0) + if (streq(value, "max")) + return mem; + } else { + r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value); + if (r < 0) { + log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m"); + return mem; + } + } + + r = safe_atou64(value, &lim); + if (r < 0) { + log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value); + return mem; + } + if (lim == UINT64_MAX) return mem; /* Make sure the limit is a multiple of our own page size */ @@ -476,6 +488,7 @@ uint64_t system_tasks_max(void) { uint64_t a = TASKS_MAX, b = TASKS_MAX; _cleanup_free_ char *root = NULL; + int r; /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this * limit: @@ -486,13 +499,24 @@ uint64_t system_tasks_max(void) { * * And then pick the smallest of the three */ - (void) procfs_tasks_get_limit(&a); + r = procfs_tasks_get_limit(&a); + if (r < 0) + log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m"); - if (cg_get_root_path(&root) >= 0) { + r = cg_get_root_path(&root); + if (r < 0) + log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m"); + else { _cleanup_free_ char *value = NULL; - if (cg_get_attribute("pids", root, "pids.max", &value) >= 0) - (void) safe_atou64(value, &b); + r = cg_get_attribute("pids", root, "pids.max", &value); + if (r < 0) + log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m"); + else if (!streq(value, "max")) { + r = safe_atou64(value, &b); + if (r < 0) + log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m"); + } } return MIN3(TASKS_MAX, diff --git a/src/basic/util.h b/src/basic/util.h index 6f8d8bef34..9699d228f9 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <alloca.h> #include <errno.h> #include <fcntl.h> @@ -92,6 +73,19 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, void *arg); /** + * Normal bsearch requires base to be nonnull. Here were require + * that only if nmemb > 0. + */ +static inline void* bsearch_safe(const void *key, const void *base, + size_t nmemb, size_t size, comparison_fn_t compar) { + if (nmemb <= 0) + return NULL; + + assert(base); + return bsearch(key, base, nmemb, size, compar); +} + +/** * Normal qsort requires base to be nonnull. Here were require * that only if nmemb > 0. */ @@ -103,6 +97,22 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_ qsort(base, nmemb, size, compar); } +/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so + * is the prototype for the comparison function */ +#define typesafe_qsort(p, n, func) \ + ({ \ + int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \ + qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \ + }) + +static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void *userdata) { + if (nmemb <= 1) + return; + + assert(base); + qsort_r(base, nmemb, size, compar, userdata); +} + /** * Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ diff --git a/src/basic/verbs.c b/src/basic/verbs.c index 4f3cd91465..1893ea3733 100644 --- a/src/basic/verbs.c +++ b/src/basic/verbs.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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 <errno.h> #include <getopt.h> @@ -94,7 +76,7 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { if (name) found = streq(name, verbs[i].verb); else - found = !!(verbs[i].flags & VERB_DEFAULT); + found = verbs[i].flags & VERB_DEFAULT; if (found) { verb = &verbs[i]; diff --git a/src/basic/verbs.h b/src/basic/verbs.h index d9259fc45f..e174255a76 100644 --- a/src/basic/verbs.h +++ b/src/basic/verbs.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - 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/>. -***/ - #define VERB_ANY ((unsigned) -1) typedef enum VerbFlags { diff --git a/src/basic/virt.c b/src/basic/virt.c index 39b4a98d89..d347732bb3 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - 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/>. -***/ #if defined(__i386__) || defined(__x86_64__) #include <cpuid.h> @@ -69,7 +51,7 @@ static int detect_vm_cpuid(void) { if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0) return VIRTUALIZATION_NONE; - hypervisor = !!(ecx & 0x80000000U); + hypervisor = ecx & 0x80000000U; if (hypervisor) { union { @@ -324,21 +306,24 @@ static int detect_vm_zvm(void) { /* Returns a short identifier for the various VM implementations */ int detect_vm(void) { static thread_local int cached_found = _VIRTUALIZATION_INVALID; - int r, dmi; bool other = false; + int r, dmi; if (cached_found >= 0) return cached_found; /* We have to use the correct order here: * - * -> First try to detect Oracle Virtualbox, even if it uses KVM. - * -> Second try to detect from cpuid, this will report KVM for - * whatever software is used even if info in dmi is overwritten. - * -> Third try to detect from dmi. */ + * → First, try to detect Oracle Virtualbox, even if it uses KVM, as well as Xen even if it cloaks as Microsoft + * Hyper-V. + * + * → Second, try to detect from CPUID, this will report KVM for whatever software is used even if info in DMI is + * overwritten. + * + * → Third, try to detect from DMI. */ dmi = detect_vm_dmi(); - if (dmi == VIRTUALIZATION_ORACLE) { + if (IN_SET(dmi, VIRTUALIZATION_ORACLE, VIRTUALIZATION_XEN)) { r = dmi; goto finish; } @@ -346,68 +331,58 @@ int detect_vm(void) { r = detect_vm_cpuid(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) { - if (r == VIRTUALIZATION_VM_OTHER) - other = true; - else - goto finish; - } + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else if (r != VIRTUALIZATION_NONE) + goto finish; - r = dmi; - if (r < 0) - return r; - if (r != VIRTUALIZATION_NONE) { - if (r == VIRTUALIZATION_VM_OTHER) - other = true; - else - goto finish; + /* Now, let's get back to DMI */ + if (dmi < 0) + return dmi; + if (dmi == VIRTUALIZATION_VM_OTHER) + other = true; + else if (dmi != VIRTUALIZATION_NONE) { + r = dmi; + goto finish; } /* x86 xen will most likely be detected by cpuid. If not (most likely * because we're not an x86 guest), then we should try the /proc/xen * directory next. If that's not found, then we check for the high-level * hypervisor sysfs file. - */ + */ r = detect_vm_xen(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) { - if (r == VIRTUALIZATION_VM_OTHER) - other = true; - else - goto finish; - } + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else if (r != VIRTUALIZATION_NONE) + goto finish; r = detect_vm_hypervisor(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) { - if (r == VIRTUALIZATION_VM_OTHER) - other = true; - else - goto finish; - } + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else if (r != VIRTUALIZATION_NONE) + goto finish; r = detect_vm_device_tree(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) { - if (r == VIRTUALIZATION_VM_OTHER) - other = true; - else - goto finish; - } + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else if (r != VIRTUALIZATION_NONE) + goto finish; r = detect_vm_uml(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) { - if (r == VIRTUALIZATION_VM_OTHER) - other = true; - else - goto finish; - } + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else if (r != VIRTUALIZATION_NONE) + goto finish; r = detect_vm_zvm(); if (r < 0) @@ -418,10 +393,12 @@ finish: * In order to detect the Dom0 as not virtualization we need to * double-check it */ if (r == VIRTUALIZATION_XEN) { - int ret = detect_vm_xen_dom0(); - if (ret < 0) - return ret; - if (ret > 0) + int dom0; + + dom0 = detect_vm_xen_dom0(); + if (dom0 < 0) + return dom0; + if (dom0 > 0) r = VIRTUALIZATION_NONE; } else if (r == VIRTUALIZATION_NONE && other) r = VIRTUALIZATION_VM_OTHER; diff --git a/src/basic/virt.h b/src/basic/virt.h index 1216bc7456..c4cf4bfeab 100644 --- a/src/basic/virt.h +++ b/src/basic/virt.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - 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 <stdbool.h> #include "macro.h" diff --git a/src/basic/web-util.c b/src/basic/web-util.c index d721b02653..82221af194 100644 --- a/src/basic/web-util.c +++ b/src/basic/web-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> diff --git a/src/basic/web-util.h b/src/basic/web-util.h index ad8c850d1d..c9e67e5c0a 100644 --- a/src/basic/web-util.h +++ b/src/basic/web-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include "macro.h" diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index a37ee4b7ef..c5c55ea846 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <errno.h> #include <fcntl.h> diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h index e25970ee6d..9fa85d7129 100644 --- a/src/basic/xattr-util.h +++ b/src/basic/xattr-util.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - 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 <stdbool.h> #include <stddef.h> #include <sys/types.h> diff --git a/src/basic/xml.c b/src/basic/xml.c index 639c3438a0..cb34d870c1 100644 --- a/src/basic/xml.c +++ b/src/basic/xml.c @@ -1,22 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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 <errno.h> #include <stddef.h> diff --git a/src/basic/xml.h b/src/basic/xml.h index d00b527232..8da2ff5f75 100644 --- a/src/basic/xml.h +++ b/src/basic/xml.h @@ -1,25 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - 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/>. -***/ - enum { XML_END, XML_TEXT, |