summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/MurmurHash2.c2
-rw-r--r--src/basic/MurmurHash2.h2
-rw-r--r--src/basic/af-list.c18
-rw-r--r--src/basic/af-list.h19
-rw-r--r--src/basic/alloc-util.c18
-rw-r--r--src/basic/alloc-util.h40
-rw-r--r--src/basic/architecture.c18
-rw-r--r--src/basic/architecture.h19
-rw-r--r--src/basic/arphrd-list.c18
-rw-r--r--src/basic/arphrd-list.h19
-rw-r--r--src/basic/async.c18
-rw-r--r--src/basic/async.h19
-rw-r--r--src/basic/audit-util.c25
-rw-r--r--src/basic/audit-util.h19
-rw-r--r--src/basic/barrier.c18
-rw-r--r--src/basic/barrier.h18
-rw-r--r--src/basic/bitmap.c18
-rw-r--r--src/basic/bitmap.h18
-rw-r--r--src/basic/blkid-util.h20
-rw-r--r--src/basic/blockdev-util.c84
-rw-r--r--src/basic/blockdev-util.h20
-rw-r--r--src/basic/bpf-program.c22
-rw-r--r--src/basic/bpf-program.h21
-rw-r--r--src/basic/btrfs-util.c29
-rw-r--r--src/basic/btrfs-util.h19
-rw-r--r--src/basic/build.h19
-rw-r--r--src/basic/bus-label.c18
-rw-r--r--src/basic/bus-label.h19
-rw-r--r--src/basic/calendarspec.c158
-rw-r--r--src/basic/calendarspec.h19
-rw-r--r--src/basic/cap-list.c21
-rw-r--r--src/basic/cap-list.h19
-rw-r--r--src/basic/capability-util.c37
-rw-r--r--src/basic/capability-util.h21
-rw-r--r--src/basic/cgroup-util.c78
-rw-r--r--src/basic/cgroup-util.h19
-rw-r--r--src/basic/chattr-util.c18
-rw-r--r--src/basic/chattr-util.h19
-rw-r--r--src/basic/clock-util.c18
-rw-r--r--src/basic/clock-util.h19
-rw-r--r--src/basic/conf-files.c216
-rw-r--r--src/basic/conf-files.h32
-rw-r--r--src/basic/copy.c339
-rw-r--r--src/basic/copy.h31
-rw-r--r--src/basic/cpu-set-util.c24
-rw-r--r--src/basic/cpu-set-util.h18
-rw-r--r--src/basic/crypt-util.c19
-rw-r--r--src/basic/crypt-util.h18
-rw-r--r--src/basic/def.h33
-rw-r--r--src/basic/device-nodes.c18
-rw-r--r--src/basic/device-nodes.h19
-rw-r--r--src/basic/dirent-util.c18
-rw-r--r--src/basic/dirent-util.h19
-rw-r--r--src/basic/env-util.c49
-rw-r--r--src/basic/env-util.h23
-rw-r--r--src/basic/errno-list.c18
-rw-r--r--src/basic/errno-list.h19
-rw-r--r--src/basic/escape.c28
-rw-r--r--src/basic/escape.h21
-rw-r--r--src/basic/ether-addr-util.c60
-rw-r--r--src/basic/ether-addr-util.h29
-rw-r--r--src/basic/exec-util.c22
-rw-r--r--src/basic/exec-util.h18
-rw-r--r--src/basic/exit-status.c98
-rw-r--r--src/basic/exit-status.h27
-rw-r--r--src/basic/extract-word.c21
-rw-r--r--src/basic/extract-word.h19
-rw-r--r--src/basic/fd-util.c317
-rw-r--r--src/basic/fd-util.h41
-rw-r--r--src/basic/fileio-label.c18
-rw-r--r--src/basic/fileio-label.h18
-rw-r--r--src/basic/fileio.c224
-rw-r--r--src/basic/fileio.h36
-rw-r--r--src/basic/format-table.c1247
-rw-r--r--src/basic/format-table.h62
-rw-r--r--src/basic/format-util.h18
-rw-r--r--src/basic/fs-util.c298
-rw-r--r--src/basic/fs-util.h42
-rw-r--r--src/basic/gcrypt-util.c20
-rw-r--r--src/basic/gcrypt-util.h20
-rwxr-xr-xsrc/basic/generate-af-list.sh2
-rw-r--r--src/basic/glob-util.c18
-rw-r--r--src/basic/glob-util.h19
-rw-r--r--src/basic/gunicode.c2
-rw-r--r--src/basic/gunicode.h2
-rw-r--r--src/basic/hash-funcs.c20
-rw-r--r--src/basic/hash-funcs.h19
-rw-r--r--src/basic/hashmap.c21
-rw-r--r--src/basic/hashmap.h19
-rw-r--r--src/basic/hexdecoct.c105
-rw-r--r--src/basic/hexdecoct.h19
-rw-r--r--src/basic/hostname-util.c18
-rw-r--r--src/basic/hostname-util.h19
-rw-r--r--src/basic/in-addr-util.c18
-rw-r--r--src/basic/in-addr-util.h19
-rw-r--r--src/basic/io-util.c18
-rw-r--r--src/basic/io-util.h28
-rw-r--r--src/basic/ioprio.h5
-rw-r--r--src/basic/journal-importer.c124
-rw-r--r--src/basic/journal-importer.h21
-rw-r--r--src/basic/khash.c21
-rw-r--r--src/basic/khash.h19
-rw-r--r--src/basic/label.c28
-rw-r--r--src/basic/label.h26
-rw-r--r--src/basic/list.h19
-rw-r--r--src/basic/locale-util.c39
-rw-r--r--src/basic/locale-util.h20
-rw-r--r--src/basic/lockfile-util.c18
-rw-r--r--src/basic/lockfile-util.h21
-rw-r--r--src/basic/log.c68
-rw-r--r--src/basic/log.h27
-rw-r--r--src/basic/login-util.c18
-rw-r--r--src/basic/login-util.h19
-rw-r--r--src/basic/macro.h56
-rw-r--r--src/basic/memfd-util.c23
-rw-r--r--src/basic/memfd-util.h19
-rw-r--r--src/basic/mempool.c30
-rw-r--r--src/basic/mempool.h22
-rw-r--r--src/basic/meson.build28
-rw-r--r--src/basic/missing.h35
-rw-r--r--src/basic/missing_syscall.h29
-rw-r--r--src/basic/mkdir-label.c25
-rw-r--r--src/basic/mkdir.c58
-rw-r--r--src/basic/mkdir.h30
-rw-r--r--src/basic/module-util.h19
-rw-r--r--src/basic/mount-util.c47
-rw-r--r--src/basic/mount-util.h19
-rw-r--r--src/basic/nss-util.h25
-rw-r--r--src/basic/ordered-set.c18
-rw-r--r--src/basic/ordered-set.h27
-rw-r--r--src/basic/os-util.c117
-rw-r--r--src/basic/os-util.h12
-rw-r--r--src/basic/pager.c206
-rw-r--r--src/basic/pager.h12
-rw-r--r--src/basic/parse-util.c150
-rw-r--r--src/basic/parse-util.h45
-rw-r--r--src/basic/path-util.c253
-rw-r--r--src/basic/path-util.h61
-rw-r--r--src/basic/prioq.c18
-rw-r--r--src/basic/prioq.h19
-rw-r--r--src/basic/proc-cmdline.c24
-rw-r--r--src/basic/proc-cmdline.h19
-rw-r--r--src/basic/process-util.c96
-rw-r--r--src/basic/process-util.h54
-rw-r--r--src/basic/random-util.c23
-rw-r--r--src/basic/random-util.h19
-rw-r--r--src/basic/ratelimit.c21
-rw-r--r--src/basic/ratelimit.h21
-rw-r--r--src/basic/raw-clone.h43
-rw-r--r--src/basic/reboot-util.h6
-rw-r--r--src/basic/refcnt.h19
-rw-r--r--src/basic/replace-var.c18
-rw-r--r--src/basic/replace-var.h19
-rw-r--r--src/basic/rlimit-util.c107
-rw-r--r--src/basic/rlimit-util.h23
-rw-r--r--src/basic/rm-rf.c40
-rw-r--r--src/basic/rm-rf.h19
-rw-r--r--src/basic/securebits-util.c21
-rw-r--r--src/basic/securebits-util.h18
-rw-r--r--src/basic/selinux-util.c99
-rw-r--r--src/basic/selinux-util.h22
-rw-r--r--src/basic/set.c62
-rw-r--r--src/basic/set.h21
-rw-r--r--src/basic/sigbus.c18
-rw-r--r--src/basic/sigbus.h19
-rw-r--r--src/basic/signal-util.c89
-rw-r--r--src/basic/signal-util.h21
-rw-r--r--src/basic/smack-util.c107
-rw-r--r--src/basic/smack-util.h32
-rw-r--r--src/basic/socket-label.c18
-rw-r--r--src/basic/socket-protocol-list.c18
-rw-r--r--src/basic/socket-protocol-list.h19
-rw-r--r--src/basic/socket-util.c30
-rw-r--r--src/basic/socket-util.h21
-rw-r--r--src/basic/special.h20
-rw-r--r--src/basic/stat-util.c47
-rw-r--r--src/basic/stat-util.h20
-rw-r--r--src/basic/stdio-util.h19
-rw-r--r--src/basic/strbuf.c83
-rw-r--r--src/basic/strbuf.h21
-rw-r--r--src/basic/string-table.c18
-rw-r--r--src/basic/string-table.h44
-rw-r--r--src/basic/string-util.c303
-rw-r--r--src/basic/string-util.h50
-rw-r--r--src/basic/strv.c58
-rw-r--r--src/basic/strv.h25
-rw-r--r--src/basic/strxcpyx.c18
-rw-r--r--src/basic/strxcpyx.h19
-rw-r--r--src/basic/syslog-util.c18
-rw-r--r--src/basic/syslog-util.h19
-rw-r--r--src/basic/terminal-util.c235
-rw-r--r--src/basic/terminal-util.h46
-rw-r--r--src/basic/time-util.c116
-rw-r--r--src/basic/time-util.h25
-rw-r--r--src/basic/umask-util.h19
-rw-r--r--src/basic/unaligned.h18
-rw-r--r--src/basic/unit-def.c19
-rw-r--r--src/basic/unit-def.h24
-rw-r--r--src/basic/unit-name.c99
-rw-r--r--src/basic/unit-name.h30
-rw-r--r--src/basic/user-util.c129
-rw-r--r--src/basic/user-util.h34
-rw-r--r--src/basic/utf8.c58
-rw-r--r--src/basic/utf8.h21
-rw-r--r--src/basic/util.c78
-rw-r--r--src/basic/util.h48
-rw-r--r--src/basic/verbs.c20
-rw-r--r--src/basic/verbs.h19
-rw-r--r--src/basic/virt.c113
-rw-r--r--src/basic/virt.h19
-rw-r--r--src/basic/web-util.c18
-rw-r--r--src/basic/web-util.h19
-rw-r--r--src/basic/xattr-util.c18
-rw-r--r--src/basic/xattr-util.h19
-rw-r--r--src/basic/xml.c18
-rw-r--r--src/basic/xml.h19
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, &ETHER_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,