diff options
Diffstat (limited to 'src')
360 files changed, 7867 insertions, 9141 deletions
diff --git a/src/activate/activate.c b/src/activate/activate.c index 23244fdc62..8ac8dd8e72 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -77,7 +77,7 @@ static int open_sockets(int *epoll_fd, bool accept) { if (r < 0) return r; - count ++; + count++; } } @@ -105,7 +105,7 @@ static int open_sockets(int *epoll_fd, bool accept) { } assert(fd == SD_LISTEN_FDS_START + count); - count ++; + count++; } if (arg_listen) @@ -176,7 +176,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd, if (!envp[n_env]) return log_oom(); - n_env ++; + n_env++; } } @@ -191,7 +191,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd, if (!envp[n_env]) return log_oom(); - n_env ++; + n_env++; } if (arg_inetd) { @@ -385,7 +385,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hl:aEd", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0) switch(c) { case 'h': help(); diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c index d36c8db3d4..b83f559e7d 100644 --- a/src/analyze/analyze-verify.c +++ b/src/analyze/analyze-verify.c @@ -290,7 +290,7 @@ int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) if (r == 0) r = k; } else - count ++; + count++; } for (i = 0; i < count; i++) { diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h index 54adad93e1..27c253a562 100644 --- a/src/analyze/analyze-verify.h +++ b/src/analyze/analyze-verify.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <stdbool.h> #include "path-lookup.h" diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index a847084781..42754a2741 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -60,7 +60,7 @@ svg(" <text class=\"%s\" x=\"%.03f\" y=\"%.03f\">", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \ svg(format, ## __VA_ARGS__); \ svg("</text>\n"); \ - } while(false) + } while (false) static enum dot { DEP_ALL, @@ -123,14 +123,6 @@ struct host_info { char *architecture; }; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; @@ -965,7 +957,7 @@ static int analyze_critical_chain(sd_bus *bus, char *names[]) { } unit_times_hashmap = h; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); puts("The time after the unit is active or started is printed after the \"@\" character.\n" "The time the unit takes to start is printed after the \"+\" character.\n"); @@ -993,7 +985,7 @@ static int analyze_blame(sd_bus *bus) { qsort(times, n, sizeof(struct unit_times), compare_unit_time); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); for (i = 0; i < (unsigned) n; i++) { char ts[FORMAT_TIMESPAN_MAX]; @@ -1206,7 +1198,7 @@ static int dump(sd_bus *bus, char **args) { return -E2BIG; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -1284,7 +1276,7 @@ static int set_log_target(sd_bus *bus, char **args) { static void help(void) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); printf("%s [OPTIONS...] {COMMAND} ...\n\n" "Profile systemd, show unit dependencies, check unit files.\n\n" diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index adc9286612..6d53dd982c 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -34,6 +34,7 @@ static const char *arg_keyname = NULL; static char *arg_message = NULL; static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; static bool arg_multiple = false; +static bool arg_no_output = false; static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE; static void help(void) { @@ -48,6 +49,7 @@ static void help(void) { " --no-tty Ask question via agent even on TTY\n" " --accept-cached Accept cached passwords\n" " --multiple List multiple passwords if available\n" + " --no-output Do not print password to standard output\n" , program_invocation_short_name); } @@ -62,6 +64,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_MULTIPLE, ARG_ID, ARG_KEYNAME, + ARG_NO_OUTPUT, }; static const struct option options[] = { @@ -74,6 +77,7 @@ static int parse_argv(int argc, char *argv[]) { { "multiple", no_argument, NULL, ARG_MULTIPLE }, { "id", required_argument, NULL, ARG_ID }, { "keyname", required_argument, NULL, ARG_KEYNAME }, + { "no-output", no_argument, NULL, ARG_NO_OUTPUT }, {} }; @@ -125,6 +129,10 @@ static int parse_argv(int argc, char *argv[]) { arg_keyname = optarg; break; + case ARG_NO_OUTPUT: + arg_no_output = true; + break; + case '?': return -EINVAL; @@ -166,7 +174,8 @@ int main(int argc, char *argv[]) { } STRV_FOREACH(p, l) { - puts(*p); + if (!arg_no_output) + puts(*p); if (!arg_multiple) break; diff --git a/src/basic/MurmurHash2.c b/src/basic/MurmurHash2.c index 2f4149dbe9..9020793930 100644 --- a/src/basic/MurmurHash2.c +++ b/src/basic/MurmurHash2.c @@ -50,7 +50,7 @@ uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ) const unsigned char * data = (const unsigned char *)key; - while(len >= 4) + while (len >= 4) { uint32_t k = *(uint32_t*)data; diff --git a/src/shared/architecture.c b/src/basic/architecture.c index a9ecfc1cd6..a9ecfc1cd6 100644 --- a/src/shared/architecture.c +++ b/src/basic/architecture.c diff --git a/src/shared/architecture.h b/src/basic/architecture.h index 26679e28c6..c22cbc8279 100644 --- a/src/shared/architecture.h +++ b/src/basic/architecture.h @@ -77,20 +77,20 @@ int uname_architecture(void); #if defined(__x86_64__) # define native_architecture() ARCHITECTURE_X86_64 # define LIB_ARCH_TUPLE "x86_64-linux-gnu" -# define PROC_CPUINFO_MODEL "model name" +# define SECONDARY_ARCHITECTURE ARCHITECTURE_X86 #elif defined(__i386__) # define native_architecture() ARCHITECTURE_X86 # define LIB_ARCH_TUPLE "i386-linux-gnu" -# define PROC_CPUINFO_MODEL "model name" #elif defined(__powerpc64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC64 # define LIB_ARCH_TUPLE "ppc64-linux-gnu" +# define SECONDARY_ARCHITECTURE ARCHITECTURE_PPC # else # define native_architecture() ARCHITECTURE_PPC64_LE # define LIB_ARCH_TUPLE "powerpc64le-linux-gnu" +# define SECONDARY_ARCHITECTURE ARCHITECTURE_PPC_LE # endif -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__powerpc__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC @@ -99,32 +99,28 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_PPC_LE # error "Missing LIB_ARCH_TUPLE for PPCLE" # endif -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__ia64__) # define native_architecture() ARCHITECTURE_IA64 # define LIB_ARCH_TUPLE "ia64-linux-gnu" #elif defined(__hppa64__) # define native_architecture() ARCHITECTURE_PARISC64 # error "Missing LIB_ARCH_TUPLE for HPPA64" -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__hppa__) # define native_architecture() ARCHITECTURE_PARISC # define LIB_ARCH_TUPLE "hppa‑linux‑gnu" -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__s390x__) # define native_architecture() ARCHITECTURE_S390X # define LIB_ARCH_TUPLE "s390x-linux-gnu" +# define SECONDARY_ARCHITECTURE ARCHITECTURE_S390 #elif defined(__s390__) # define native_architecture() ARCHITECTURE_S390 # define LIB_ARCH_TUPLE "s390-linux-gnu" #elif defined(__sparc64__) # define native_architecture() ARCHITECTURE_SPARC64 # define LIB_ARCH_TUPLE "sparc64-linux-gnu" -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__sparc__) # define native_architecture() ARCHITECTURE_SPARC # define LIB_ARCH_TUPLE "sparc-linux-gnu" -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__mips64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_MIPS64 @@ -133,7 +129,6 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_MIPS64_LE # error "Missing LIB_ARCH_TUPLE for MIPS64_LE" # endif -# define PROC_CPUINFO_MODEL "cpu model" #elif defined(__mips__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_MIPS @@ -142,7 +137,6 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_MIPS_LE # define LIB_ARCH_TUPLE "mipsel-linux-gnu" # endif -# define PROC_CPUINFO_MODEL "cpu model" #elif defined(__alpha__) # define native_architecture() ARCHITECTURE_ALPHA # define LIB_ARCH_TUPLE "alpha-linux-gnu" @@ -178,7 +172,6 @@ int uname_architecture(void); # define LIB_ARCH_TUPLE "arm-linux-gnu" # endif # endif -# define PROC_CPUINFO_MODEL "model name" #elif defined(__sh64__) # define native_architecture() ARCHITECTURE_SH64 # error "Missing LIB_ARCH_TUPLE for SH64" @@ -198,10 +191,5 @@ int uname_architecture(void); # error "Please register your architecture here!" #endif -#ifndef PROC_CPUINFO_MODEL -#warning "PROC_CPUINFO_MODEL not defined for your architecture" -#define PROC_CPUINFO_MODEL "model name" -#endif - const char *architecture_to_string(int a) _const_; int architecture_from_string(const char *s) _pure_; diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 37802c2565..1d852d502c 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <stdbool.h> #include <stdint.h> #include <sys/types.h> diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c index 914d7e5229..cf5a7242df 100644 --- a/src/basic/c-rbtree.c +++ b/src/basic/c-rbtree.c @@ -195,11 +195,6 @@ static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigne n->__parent_and_color = (CRBNode*)((unsigned long)p | c); } -/* same as c_rbnode_set_parent_and_color(), but keeps the current parent */ -static inline void c_rbnode_set_color(CRBNode *n, unsigned long c) { - c_rbnode_set_parent_and_color(n, c_rbnode_parent(n), c); -} - /* same as c_rbnode_set_parent_and_color(), but keeps the current color */ static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) { c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n)); diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 775879076d..6e0bab9b94 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -114,7 +114,7 @@ static void sort_chain(CalendarComponent **c) { static void fix_year(CalendarComponent *c) { /* Turns 12 → 2012, 89 → 1989 */ - while(c) { + while (c) { CalendarComponent *n = c->next; if (c->value >= 0 && c->value < 70) @@ -978,7 +978,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { for (;;) { /* Normalize the current date */ - mktime_or_timegm(&c, spec->utc); + (void) mktime_or_timegm(&c, spec->utc); c.tm_isdst = -1; c.tm_year += 1900; @@ -990,8 +990,10 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; } - if (r < 0 || tm_out_of_bounds(&c, spec->utc)) + if (r < 0) return r; + if (tm_out_of_bounds(&c, spec->utc)) + return -ENOENT; c.tm_mon += 1; r = find_matching_component(spec->month, &c.tm_mon); @@ -1002,7 +1004,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; } if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_year ++; + c.tm_year++; c.tm_mon = 0; c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; @@ -1013,7 +1015,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { if (r > 0) c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_mon ++; + c.tm_mon++; c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; continue; @@ -1027,18 +1029,18 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { r = find_matching_component(spec->hour, &c.tm_hour); if (r > 0) - c.tm_min = c.tm_sec = 0; + c.tm_min = c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_mday ++; + c.tm_mday++; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; continue; } r = find_matching_component(spec->minute, &c.tm_min); if (r > 0) - c.tm_sec = 0; + c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_hour ++; + c.tm_hour++; c.tm_min = c.tm_sec = tm_usec = 0; continue; } @@ -1049,7 +1051,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { c.tm_sec /= USEC_PER_SEC; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_min ++; + c.tm_min++; c.tm_sec = tm_usec = 0; continue; } diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 6ef00d51df..5043180747 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -101,6 +101,39 @@ int cg_read_pid(FILE *f, pid_t *_pid) { return 1; } +int cg_read_event(const char *controller, const char *path, const char *event, + char **val) +{ + _cleanup_free_ char *events = NULL, *content = NULL; + char *p, *line; + int r; + + r = cg_get_path(controller, path, "cgroup.events", &events); + if (r < 0) + return r; + + r = read_full_file(events, &content, NULL); + if (r < 0) + return r; + + p = content; + while ((line = strsep(&p, "\n"))) { + char *key; + + key = strsep(&line, " "); + if (!key || !line) + return -EINVAL; + + if (strcmp(key, event)) + continue; + + *val = strdup(line); + return 0; + } + + return -ENOENT; +} + int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) { _cleanup_free_ char *fs = NULL; int r; @@ -1007,18 +1040,12 @@ int cg_is_empty_recursive(const char *controller, const char *path) { return unified; if (unified > 0) { - _cleanup_free_ char *populated = NULL, *t = NULL; + _cleanup_free_ char *t = NULL; /* On the unified hierarchy we can check empty state - * via the "cgroup.populated" attribute. */ + * via the "populated" attribute of "cgroup.events". */ - r = cg_get_path(controller, path, "cgroup.populated", &populated); - if (r < 0) - return r; - - r = read_one_line_file(populated, &t); - if (r == -ENOENT) - return 1; + r = cg_read_event(controller, path, "populated", &t); if (r < 0) return r; @@ -1248,7 +1275,7 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) { return 0; } -int cg_path_decode_unit(const char *cgroup, char **unit){ +int cg_path_decode_unit(const char *cgroup, char **unit) { char *c, *s; size_t n; @@ -2129,7 +2156,7 @@ int cg_unified(void) { if (statfs("/sys/fs/cgroup/", &fs) < 0) return -errno; - if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC)) + if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) unified_cache = true; else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) unified_cache = false; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index ad1edd9cdb..4254e51e5d 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -96,6 +96,8 @@ static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) { int cg_enumerate_processes(const char *controller, const char *path, FILE **_f); int cg_read_pid(FILE *f, pid_t *_pid); +int cg_read_event(const char *controller, const char *path, const char *event, + char **val); int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d); int cg_read_subgroup(DIR *d, char **fn); diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index 507e757ff0..7fe8d35ea5 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -69,9 +69,12 @@ int clock_set_hwclock(const struct tm *tm) { return 0; } -int clock_is_localtime(void) { +int clock_is_localtime(const char* adjtime_path) { _cleanup_fclose_ FILE *f; + if (adjtime_path == NULL) + adjtime_path = "/etc/adjtime"; + /* * The third line of adjtime is "UTC" or "LOCAL" or nothing. * # /etc/adjtime @@ -79,7 +82,7 @@ int clock_is_localtime(void) { * 0 * UTC */ - f = fopen("/etc/adjtime", "re"); + f = fopen(adjtime_path, "re"); if (f) { char line[LINE_MAX]; bool b; @@ -88,7 +91,8 @@ int clock_is_localtime(void) { fgets(line, sizeof(line), f) && fgets(line, sizeof(line), f); if (!b) - return -EIO; + /* less than three lines -> default to UTC */ + return 0; truncate_nl(line); return streq(line, "LOCAL"); @@ -96,6 +100,7 @@ int clock_is_localtime(void) { } else if (errno != ENOENT) return -errno; + /* adjtime not present -> default to UTC */ return 0; } diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index f471f2abcf..8830cd2f38 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -21,7 +21,7 @@ #include <time.h> -int clock_is_localtime(void); +int clock_is_localtime(const char* adjtime_path); int clock_set_timezone(int *min); int clock_reset_timewarp(void); int clock_get_hwclock(struct tm *tm); diff --git a/src/basic/copy.c b/src/basic/copy.c index 519b412941..41dc8ca79a 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -40,17 +40,38 @@ #include "fs-util.h" #include "io-util.h" #include "macro.h" +#include "missing.h" #include "string-util.h" #include "strv.h" #include "time-util.h" #include "umask-util.h" #include "xattr-util.h" -#define COPY_BUFFER_SIZE (16*1024) +#define COPY_BUFFER_SIZE (16*1024u) + +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) + return -ENOSYS; + + r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); + if (_unlikely_(have < 0)) + have = r >= 0 || errno != ENOSYS; + if (r >= 0) + return r; + else + return -errno; +} int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { - bool try_sendfile = true, try_splice = true; + bool try_cfr = true, try_sendfile = true, try_splice = true; int r; + size_t m = SSIZE_MAX; /* that the maximum that sendfile and c_f_r accept */ assert(fdf >= 0); assert(fdt >= 0); @@ -67,11 +88,9 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { } for (;;) { - size_t m = COPY_BUFFER_SIZE; ssize_t n; if (max_bytes != (uint64_t) -1) { - if (max_bytes <= 0) return 1; /* return > 0 if we hit the max_bytes limit */ @@ -79,44 +98,59 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { m = (size_t) max_bytes; } + /* First try copy_file_range(), unless we already tried */ + if (try_cfr) { + n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u); + if (n < 0) { + if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV)) + return n; + + try_cfr = false; + /* use fallback below */ + } else if (n == 0) /* EOF */ + break; + else + /* Success! */ + goto next; + } + /* First try sendfile(), unless we already tried */ if (try_sendfile) { - n = sendfile(fdt, fdf, NULL, m); if (n < 0) { - if (errno != EINVAL && errno != ENOSYS) + if (!IN_SET(errno, EINVAL, ENOSYS)) return -errno; try_sendfile = false; /* use fallback below */ } else if (n == 0) /* EOF */ break; - else if (n > 0) + else /* Success! */ goto next; } - /* The try splice, unless we already tried */ + /* Then try splice, unless we already tried */ if (try_splice) { n = splice(fdf, NULL, fdt, NULL, m, 0); if (n < 0) { - if (errno != EINVAL && errno != ENOSYS) + if (!IN_SET(errno, EINVAL, ENOSYS)) return -errno; try_splice = false; /* use fallback below */ } else if (n == 0) /* EOF */ break; - else if (n > 0) + else /* Success! */ goto next; } /* As a fallback just copy bits by hand */ { - uint8_t buf[m]; + uint8_t buf[MIN(m, COPY_BUFFER_SIZE)]; - n = read(fdf, buf, m); + n = read(fdf, buf, sizeof buf); if (n < 0) return -errno; if (n == 0) /* EOF */ @@ -132,6 +166,11 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { assert(max_bytes >= (uint64_t) n); max_bytes -= n; } + /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, + * so reduce our maximum by the amount we already copied, + * but don't go below our copy buffer size, unless we are + * close the the limit of bytes we are allowed to copy. */ + m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); } return 0; /* return 0 if we hit EOF earlier than the size limit */ diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index ded6d31f4b..a4d8d656da 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -42,3 +42,15 @@ 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) { + 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]; +} diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 4487149efd..074363793e 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -20,10 +20,18 @@ ***/ #include <net/ethernet.h> +#include <stdbool.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); + +#define ETHER_ADDR_NULL ((const struct ether_addr){}) + +static inline bool ether_addr_is_null(const struct ether_addr *addr) { + return ether_addr_equal(addr, ÐER_ADDR_NULL); +} diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index ee35d2a0ec..d6c1228463 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -63,12 +63,12 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra if (!GREEDY_REALLOC(s, allocated, sz+1)) return -ENOMEM; - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (c == 0) goto finish_force_terminate; else if (strchr(separators, c)) { if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p) ++; + (*p)++; goto finish_force_next; } } else { @@ -81,7 +81,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra } } - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (backslash) { if (!GREEDY_REALLOC(s, allocated, sz+7)) return -ENOMEM; @@ -129,7 +129,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra backslash = false; } else if (quote) { /* inside either single or double quotes */ - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (c == 0) { if (flags & EXTRACT_RELAX) goto finish_force_terminate; @@ -149,7 +149,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra } } else { - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (c == 0) goto finish_force_terminate; else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) { @@ -160,11 +160,11 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra break; } else if (strchr(separators, c)) { if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p) ++; + (*p)++; goto finish_force_next; } /* Skip additional coalesced separators. */ - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (c == 0) goto finish_force_terminate; if (!strchr(separators, c)) diff --git a/src/basic/fileio.c b/src/basic/fileio.c index e43ca6d29e..69590941e5 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -352,7 +352,7 @@ static int parse_env_file_internal( case KEY: if (strchr(newline, c)) { state = PRE_KEY; - line ++; + line++; n_key = 0; } else if (c == '=') { state = PRE_VALUE; @@ -376,7 +376,7 @@ static int parse_env_file_internal( case PRE_VALUE: if (strchr(newline, c)) { state = PRE_KEY; - line ++; + line++; key[n_key] = 0; if (value) @@ -416,7 +416,7 @@ static int parse_env_file_internal( case VALUE: if (strchr(newline, c)) { state = PRE_KEY; - line ++; + line++; key[n_key] = 0; @@ -535,7 +535,7 @@ static int parse_env_file_internal( state = COMMENT_ESCAPE; else if (strchr(newline, c)) { state = PRE_KEY; - line ++; + line++; } break; @@ -588,7 +588,7 @@ static int parse_env_file_push( va_list aq, *ap = userdata; if (!utf8_is_valid(key)) { - _cleanup_free_ char *p; + _cleanup_free_ char *p = NULL; p = utf8_escape_invalid(key); log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p); @@ -596,7 +596,7 @@ static int parse_env_file_push( } if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *p; + _cleanup_free_ char *p = NULL; p = utf8_escape_invalid(value); log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p); @@ -908,7 +908,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin /* Back off one char if there's nothing but whitespace and zeros */ if (!*t || isspace(*t)) - t --; + t--; } len = strcspn(t, terminator); @@ -1069,7 +1069,7 @@ int fflush_and_check(FILE *f) { /* This is much like like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern, int flags) { - _cleanup_umask_ mode_t u; + _cleanup_umask_ mode_t u = 0; int fd; assert(pattern); diff --git a/src/basic/formats-util.h b/src/basic/formats-util.h index ce516b117d..9b4e8e98fa 100644 --- a/src/basic/formats-util.h +++ b/src/basic/formats-util.h @@ -49,7 +49,7 @@ #if SIZEOF_TIME_T == 8 # define PRI_TIME PRIi64 #elif SIZEOF_TIME_T == 4 -# define PRI_TIME PRIu32 +# define PRI_TIME "li" #else # error Unknown time_t size #endif diff --git a/src/basic/gunicode.h b/src/basic/gunicode.h index b03aa43160..5975bc8fc9 100644 --- a/src/basic/gunicode.h +++ b/src/basic/gunicode.h @@ -1,11 +1,11 @@ +#pragma once + /* gunicode.h - Unicode manipulation functions * * Copyright (C) 1999, 2000 Tom Tromey * Copyright 2000, 2005 Red Hat, Inc. */ -#pragma once - #include <stdbool.h> #include <stdint.h> #include <stdlib.h> diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 6f1a049d47..85b8d812b3 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -176,7 +176,7 @@ enum HashmapType { }; struct _packed_ indirect_storage { - char *storage; /* where buckets and DIBs are stored */ + void *storage; /* where buckets and DIBs are stored */ uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ unsigned n_entries; /* number of stored entries */ @@ -193,7 +193,7 @@ struct direct_storage { /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ - char storage[sizeof(struct indirect_storage)]; + uint8_t storage[sizeof(struct indirect_storage)]; }; #define DIRECT_BUCKETS(entry_t) \ @@ -302,7 +302,7 @@ static void n_entries_dec(HashmapBase *h) { h->n_direct_entries--; } -static char *storage_ptr(HashmapBase *h) { +static void *storage_ptr(HashmapBase *h) { return h->has_indirect ? h->indirect.storage : h->direct.storage; } @@ -347,7 +347,7 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) { return (struct hashmap_base_entry*) - (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); + ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); } static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) { @@ -381,7 +381,7 @@ static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_ static dib_raw_t *dib_raw_ptr(HashmapBase *h) { return (dib_raw_t*) - (storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); + ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); } static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) { @@ -1028,7 +1028,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx, */ static int resize_buckets(HashmapBase *h, unsigned entries_add) { struct swap_entries swap; - char *new_storage; + void *new_storage; dib_raw_t *old_dibs, *new_dibs; const struct hashmap_type_info *hi; unsigned idx, optimal_idx; @@ -1095,7 +1095,7 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add) { h->indirect.n_buckets = (1U << new_shift) / (hi->entry_size + sizeof(dib_raw_t)); - old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets); + old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets); new_dibs = dib_raw_ptr(h); /* diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index d7ad8d41f2..c5bda6c4d6 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -276,8 +276,8 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l if (padding) { /* strip the padding */ while (l > 0 && p[l - 1] == '=' && pad < 7) { - pad ++; - l --; + pad++; + l--; } } @@ -505,7 +505,7 @@ int unbase64char(char c) { if (c == '+') return offset; - offset ++; + offset++; if (c == '/') return offset; @@ -621,9 +621,9 @@ int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { /* strip the padding */ if (l > 0 && p[l - 1] == '=') - l --; + l--; if (l > 0 && p[l - 1] == '=') - l --; + l--; /* a group of four input bytes needs three output bytes, in case of padding we need to add two or three extra bytes */ diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 4fe6a725aa..13c3bb6446 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -17,7 +17,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <bits/local_lim.h> #include <errno.h> #include <limits.h> #include <stdio.h> @@ -49,6 +48,10 @@ bool hostname_is_set(void) { char* gethostname_malloc(void) { struct utsname u; + /* This call tries to return something useful, either the actual hostname + * or it makes something up. The only reason it might fail is OOM. + * It might even return "localhost" if that's set. */ + assert_se(uname(&u) >= 0); if (isempty(u.nodename) || streq(u.nodename, "(none)")) @@ -57,6 +60,31 @@ char* gethostname_malloc(void) { return strdup(u.nodename); } +int gethostname_strict(char **ret) { + struct utsname u; + char *k; + + /* This call will rather fail than make up a name. It will not return "localhost" either. */ + + assert_se(uname(&u) >= 0); + + if (isempty(u.nodename)) + return -ENXIO; + + if (streq(u.nodename, "(none)")) + return -ENXIO; + + if (is_localhost(u.nodename)) + return -ENXIO; + + k = strdup(u.nodename); + if (!k) + return -ENOMEM; + + *ret = k; + return 0; +} + static bool hostname_valid_char(char c) { return (c >= 'a' && c <= 'z') || @@ -96,7 +124,7 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) { return false; dot = true; - n_dots ++; + n_dots++; } else { if (!hostname_valid_char(*p)) return false; @@ -122,6 +150,8 @@ char* hostname_cleanup(char *s) { assert(s); + strshorten(s, HOST_NAME_MAX); + for (p = s, d = s, dot = true; *p; p++) { if (*p == '.') { if (dot) @@ -141,8 +171,6 @@ char* hostname_cleanup(char *s) { else *d = 0; - strshorten(s, HOST_NAME_MAX); - return s; } diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index d062eddea1..7af4e6c7ec 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -26,6 +26,7 @@ bool hostname_is_set(void); char* gethostname_malloc(void); +int gethostname_strict(char **ret); bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_; char* hostname_cleanup(char *s); diff --git a/src/basic/io-util.c b/src/basic/io-util.c index 3ec8d61236..0037a37f2a 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -249,7 +249,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { } else if (n > 0) q += n; else - q ++; + q++; } if (q > w) { diff --git a/src/basic/io-util.h b/src/basic/io-util.h index 142c940d92..4684ed3bfc 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -46,7 +46,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); char *_s = (char *)(s); \ _i->iov_base = _s; \ _i->iov_len = strlen(_s); \ - } while(false) + } while (false) static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { unsigned j; diff --git a/src/basic/list.h b/src/basic/list.h index c68185f587..5962aa4211 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -32,7 +32,7 @@ #define LIST_HEAD_INIT(head) \ do { \ (head) = NULL; } \ - while(false) + while (false) /* Initialize a list item */ #define LIST_INIT(name,item) \ @@ -40,7 +40,7 @@ typeof(*(item)) *_item = (item); \ assert(_item); \ _item->name##_prev = _item->name##_next = NULL; \ - } while(false) + } while (false) /* Prepend an item to the list */ #define LIST_PREPEND(name,head,item) \ @@ -51,7 +51,7 @@ _item->name##_next->name##_prev = _item; \ _item->name##_prev = NULL; \ *_head = _item; \ - } while(false) + } while (false) /* Append an item to the list */ #define LIST_APPEND(name,head,item) \ @@ -59,7 +59,7 @@ typeof(*(head)) *_tail; \ LIST_FIND_TAIL(name,head,_tail); \ LIST_INSERT_AFTER(name,head,_tail,item); \ - } while(false) + } while (false) /* Remove an item from the list */ #define LIST_REMOVE(name,head,item) \ @@ -75,7 +75,7 @@ *_head = _item->name##_next; \ } \ _item->name##_next = _item->name##_prev = NULL; \ - } while(false) + } while (false) /* Find the head of the list */ #define LIST_FIND_HEAD(name,item,head) \ @@ -119,7 +119,7 @@ _b->name##_prev = _a; \ _a->name##_next = _b; \ } \ - } while(false) + } while (false) /* Insert an item before another one (a = where, b = what) */ #define LIST_INSERT_BEFORE(name,head,a,b) \ @@ -145,7 +145,7 @@ _b->name##_next = _a; \ _a->name##_prev = _b; \ } \ - } while(false) + } while (false) #define LIST_JUST_US(name,item) \ (!(item)->name##_prev && !(item)->name##_next) \ diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index cda6b2895d..eaad25e65b 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -153,6 +153,8 @@ static int add_locales_from_libdir (Set *locales) { FOREACH_DIRENT(entry, dir, return -errno) { char *z; + dirent_ensure_type(dir, entry); + if (entry->d_type != DT_DIR) continue; diff --git a/src/basic/log.h b/src/basic/log.h index 60ddead74c..b6356228d9 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -193,7 +193,7 @@ void log_assert_failed_return( #ifdef LOG_TRACE # define log_trace(...) log_debug(__VA_ARGS__) #else -# define log_trace(...) do {} while(0) +# define log_trace(...) do {} while (0) #endif /* Structured logging */ @@ -246,5 +246,4 @@ int log_syntax_internal( log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \ "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ } \ - -EINVAL; \ }) diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 89a337d7c1..b01ee25c88 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <stdbool.h> #include <unistd.h> diff --git a/src/basic/macro.h b/src/basic/macro.h index 2695d0edb7..e41aa4260f 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -23,10 +23,15 @@ #include <inttypes.h> #include <stdbool.h> #include <sys/param.h> +#include <sys/sysmacros.h> #include <sys/types.h> #define _printf_(a,b) __attribute__ ((format (printf, a, b))) -#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#ifdef __clang__ +# define _alloc_(...) +#else +# define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#endif #define _sentinel_ __attribute__ ((sentinel)) #define _unused_ __attribute__ ((unused)) #define _destructor_ __attribute__ ((destructor)) @@ -224,7 +229,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { /* We override the glibc assert() here. */ #undef assert #ifdef NDEBUG -#define assert(expr) do {} while(false) +#define assert(expr) do {} while (false) #else #define assert(expr) assert_message_se(expr, #expr) #endif @@ -361,6 +366,12 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { _found; \ }) +#define SWAP_TWO(x, y) do { \ + typeof(x) _t = (x); \ + (x) = (y); \ + (y) = (_t); \ + } while (false) + /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local diff --git a/src/basic/missing.h b/src/basic/missing.h index f3d32362bd..66cd5921ad 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -31,6 +31,7 @@ #include <linux/neighbour.h> #include <linux/oom.h> #include <linux/rtnetlink.h> +#include <net/ethernet.h> #include <stdlib.h> #include <sys/resource.h> #include <sys/syscall.h> @@ -134,84 +135,6 @@ #define SOL_SCTP 132 #endif -#if !HAVE_DECL_PIVOT_ROOT -static inline int pivot_root(const char *new_root, const char *put_old) { - return syscall(SYS_pivot_root, new_root, put_old); -} -#endif - -#ifndef __NR_memfd_create -# if defined __x86_64__ -# define __NR_memfd_create 319 -# elif defined __arm__ -# define __NR_memfd_create 385 -# elif defined __aarch64__ -# define __NR_memfd_create 279 -# elif defined __s390__ -# define __NR_memfd_create 350 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_memfd_create 4354 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_memfd_create 6318 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_memfd_create 5314 -# endif -# elif defined __i386__ -# define __NR_memfd_create 356 -# else -# warning "__NR_memfd_create unknown for your architecture" -# define __NR_memfd_create 0xffffffff -# endif -#endif - -#if !HAVE_DECL_MEMFD_CREATE -static inline int memfd_create(const char *name, unsigned int flags) { - return syscall(__NR_memfd_create, name, flags); -} -#endif - -#ifndef __NR_getrandom -# if defined __x86_64__ -# define __NR_getrandom 318 -# elif defined(__i386__) -# define __NR_getrandom 355 -# elif defined(__arm__) -# define __NR_getrandom 384 -# elif defined(__aarch64__) -# define __NR_getrandom 278 -# elif defined(__ia64__) -# define __NR_getrandom 1339 -# elif defined(__m68k__) -# define __NR_getrandom 352 -# elif defined(__s390x__) -# define __NR_getrandom 349 -# elif defined(__powerpc__) -# define __NR_getrandom 359 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_getrandom 4353 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_getrandom 6317 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_getrandom 5313 -# endif -# else -# warning "__NR_getrandom unknown for your architecture" -# define __NR_getrandom 0xffffffff -# endif -#endif - -#if !HAVE_DECL_GETRANDOM -static inline int getrandom(void *buffer, size_t count, unsigned flags) { - return syscall(__NR_getrandom, buffer, count, flags); -} -#endif - #ifndef GRND_NONBLOCK #define GRND_NONBLOCK 0x0001 #endif @@ -514,6 +437,10 @@ struct btrfs_ioctl_quota_ctl_args { #define CGROUP_SUPER_MAGIC 0x27e0eb #endif +#ifndef CGROUP2_SUPER_MAGIC +#define CGROUP2_SUPER_MAGIC 0x63677270 +#endif + #ifndef TMPFS_MAGIC #define TMPFS_MAGIC 0x01021994 #endif @@ -526,12 +453,6 @@ struct btrfs_ioctl_quota_ctl_args { #define MS_PRIVATE (1 << 18) #endif -#if !HAVE_DECL_GETTID -static inline pid_t gettid(void) { - return (pid_t) syscall(SYS_gettid); -} -#endif - #ifndef SCM_SECURITY #define SCM_SECURITY 0x03 #endif @@ -560,32 +481,6 @@ static inline pid_t gettid(void) { #define MAX_HANDLE_SZ 128 #endif -#ifndef __NR_name_to_handle_at -# if defined(__x86_64__) -# define __NR_name_to_handle_at 303 -# elif defined(__i386__) -# define __NR_name_to_handle_at 341 -# elif defined(__arm__) -# define __NR_name_to_handle_at 370 -# elif defined(__powerpc__) -# define __NR_name_to_handle_at 345 -# else -# error "__NR_name_to_handle_at is not defined" -# endif -#endif - -#if !HAVE_DECL_NAME_TO_HANDLE_AT -struct file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char f_handle[0]; -}; - -static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { - return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); -} -#endif - #ifndef HAVE_SECURE_GETENV # ifdef HAVE___SECURE_GETENV # define secure_getenv __secure_getenv @@ -634,22 +529,6 @@ static inline int name_to_handle_at(int fd, const char *name, struct file_handle #endif -#ifndef __NR_setns -# if defined(__x86_64__) -# define __NR_setns 308 -# elif defined(__i386__) -# define __NR_setns 346 -# else -# error "__NR_setns is not defined" -# endif -#endif - -#if !HAVE_DECL_SETNS -static inline int setns(int fd, int nstype) { - return syscall(__NR_setns, fd, nstype); -} -#endif - #if !HAVE_DECL_LO_FLAGS_PARTSCAN #define LO_FLAGS_PARTSCAN 8 #endif @@ -883,13 +762,16 @@ static inline int setns(int fd, int nstype) { #define IFLA_BRPORT_FAST_LEAVE 7 #define IFLA_BRPORT_LEARNING 8 #define IFLA_BRPORT_UNICAST_FLOOD 9 -#define IFLA_BRPORT_PROXYARP 10 #define IFLA_BRPORT_LEARNING_SYNC 11 #define __IFLA_BRPORT_MAX 12 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) #endif +#if !HAVE_DECL_IFLA_BRPORT_PROXYARP +#define IFLA_BRPORT_PROXYARP 10 +#endif + #if !HAVE_DECL_NDA_IFINDEX #define NDA_UNSPEC 0 #define NDA_DST 1 @@ -1014,69 +896,10 @@ static inline int setns(int fd, int nstype) { #define CAP_AUDIT_READ 37 #endif -static inline int raw_clone(unsigned long flags, void *child_stack) { -#if defined(__s390__) || defined(__CRIS__) - /* On s390 and cris the order of the first and second arguments - * of the raw clone() system call is reversed. */ - return (int) syscall(__NR_clone, child_stack, flags); -#else - return (int) syscall(__NR_clone, flags, child_stack); -#endif -} - -static inline pid_t raw_getpid(void) { -#if defined(__alpha__) - return (pid_t) syscall(__NR_getxpid); -#else - return (pid_t) syscall(__NR_getpid); -#endif -} - -#if !HAVE_DECL_RENAMEAT2 - -#ifndef __NR_renameat2 -# if defined __x86_64__ -# define __NR_renameat2 316 -# elif defined __arm__ -# define __NR_renameat2 382 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_renameat2 4351 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_renameat2 6315 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_renameat2 5311 -# endif -# elif defined __i386__ -# define __NR_renameat2 353 -# else -# warning "__NR_renameat2 unknown for your architecture" -# define __NR_renameat2 0xffffffff -# endif -#endif - -static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { - return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); -} -#endif - #ifndef RENAME_NOREPLACE #define RENAME_NOREPLACE (1 << 0) #endif -#if !HAVE_DECL_KCMP -static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { -#if defined(__NR_kcmp) - return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif - #ifndef KCMP_FILE #define KCMP_FILE 0 #endif @@ -1093,35 +916,6 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns typedef int32_t key_serial_t; #endif -#if !HAVE_DECL_KEYCTL -static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) { -#if defined(__NR_keyctl) - return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); -#else - errno = ENOSYS; - return -1; -#endif -} - -static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { -#if defined (__NR_add_key) - return syscall(__NR_add_key, type, description, payload, plen, ringid); -#else - errno = ENOSYS; - return -1; -#endif -} - -static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) { -#if defined (__NR_request_key) - return syscall(__NR_request_key, type, description, callout_info, destringid); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif - #ifndef KEYCTL_READ #define KEYCTL_READ 11 #endif @@ -1168,4 +962,10 @@ static inline key_serial_t request_key(const char *type, const char *description #define char16_t uint16_t #endif +#ifndef ETHERTYPE_LLDP +#define ETHERTYPE_LLDP 0x88cc #endif + +#endif + +#include "missing_syscall.h" diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h new file mode 100644 index 0000000000..d502d3b9ca --- /dev/null +++ b/src/basic/missing_syscall.h @@ -0,0 +1,310 @@ +#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 */ + +#if !HAVE_DECL_PIVOT_ROOT +static inline int pivot_root(const char *new_root, const char *put_old) { + return syscall(SYS_pivot_root, new_root, put_old); +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_MEMFD_CREATE +# ifndef __NR_memfd_create +# if defined __x86_64__ +# define __NR_memfd_create 319 +# elif defined __arm__ +# define __NR_memfd_create 385 +# elif defined __aarch64__ +# define __NR_memfd_create 279 +# elif defined __s390__ +# define __NR_memfd_create 350 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_memfd_create 4354 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_memfd_create 6318 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_memfd_create 5314 +# endif +# elif defined __i386__ +# define __NR_memfd_create 356 +# else +# warning "__NR_memfd_create unknown for your architecture" +# endif +# endif + +static inline int memfd_create(const char *name, unsigned int flags) { +# ifdef __NR_memfd_create + return syscall(__NR_memfd_create, name, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_GETRANDOM +# ifndef __NR_getrandom +# if defined __x86_64__ +# define __NR_getrandom 318 +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__arm__) +# define __NR_getrandom 384 +# elif defined(__aarch64__) +# define __NR_getrandom 278 +# elif defined(__ia64__) +# define __NR_getrandom 1339 +# elif defined(__m68k__) +# define __NR_getrandom 352 +# elif defined(__s390x__) +# define __NR_getrandom 349 +# elif defined(__powerpc__) +# define __NR_getrandom 359 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_getrandom 4353 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_getrandom 6317 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_getrandom 5313 +# endif +# else +# warning "__NR_getrandom unknown for your architecture" +# endif +# endif + +static inline int getrandom(void *buffer, size_t count, unsigned flags) { +# ifdef __NR_getrandom + return syscall(__NR_getrandom, buffer, count, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_GETTID +static inline pid_t gettid(void) { + return (pid_t) syscall(SYS_gettid); +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_NAME_TO_HANDLE_AT +# ifndef __NR_name_to_handle_at +# if defined(__x86_64__) +# define __NR_name_to_handle_at 303 +# elif defined(__i386__) +# define __NR_name_to_handle_at 341 +# elif defined(__arm__) +# define __NR_name_to_handle_at 370 +# elif defined(__powerpc__) +# define __NR_name_to_handle_at 345 +# else +# error "__NR_name_to_handle_at is not defined" +# endif +# endif + +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[0]; +}; + +static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { +# ifdef __NR_name_to_handle_at + return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_SETNS +# ifndef __NR_setns +# if defined(__x86_64__) +# define __NR_setns 308 +# elif defined(__i386__) +# define __NR_setns 346 +# else +# error "__NR_setns is not defined" +# endif +# endif + +static inline int setns(int fd, int nstype) { +# ifdef __NR_setns + return syscall(__NR_setns, fd, nstype); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +static inline int raw_clone(unsigned long flags, void *child_stack) { +#if defined(__s390__) || defined(__CRIS__) + /* On s390 and cris the order of the first and second arguments + * of the raw clone() system call is reversed. */ + return (int) syscall(__NR_clone, child_stack, flags); +#else + return (int) syscall(__NR_clone, flags, child_stack); +#endif +} + +/* ======================================================================= */ + +static inline pid_t raw_getpid(void) { +#if defined(__alpha__) + return (pid_t) syscall(__NR_getxpid); +#else + return (pid_t) syscall(__NR_getpid); +#endif +} + +/* ======================================================================= */ + +#if !HAVE_DECL_RENAMEAT2 +# ifndef __NR_renameat2 +# if defined __x86_64__ +# define __NR_renameat2 316 +# elif defined __arm__ +# define __NR_renameat2 382 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_renameat2 4351 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_renameat2 6315 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_renameat2 5311 +# endif +# elif defined __i386__ +# define __NR_renameat2 353 +# else +# warning "__NR_renameat2 unknown for your architecture" +# endif +# endif + +static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { +# ifdef __NR_renameat2 + return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_KCMP +static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { +# ifdef __NR_kcmp + return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_KEYCTL +static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) { +# ifdef __NR_keyctl + return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); +# else + errno = ENOSYS; + return -1; +# endif +} + +static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { +# ifdef __NR_add_key + return syscall(__NR_add_key, type, description, payload, plen, ringid); +# else + errno = ENOSYS; + return -1; +# endif +} + +static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) { +# ifdef __NR_request_key + return syscall(__NR_request_key, type, description, callout_info, destringid); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_COPY_FILE_RANGE +# ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined __s390__ +# define __NR_copy_file_range 375 +# elif defined __arm__ +# define __NR_copy_file_range 391 +# elif defined __aarch64__ +# define __NR_copy_file_range 285 +# else +# warning "__NR_copy_file_range not defined for your architecture" +# endif +# endif + +static inline ssize_t copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { +# ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 33f2ee96d8..5faa2eba05 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -47,7 +47,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id if ((flags & AT_EMPTY_PATH) && isempty(filename)) xsprintf(path, "/proc/self/fdinfo/%i", fd); else { - subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); + subfd = openat(fd, filename, O_CLOEXEC|O_PATH); if (subfd < 0) return -errno; @@ -230,7 +230,7 @@ int path_is_mount_point(const char *t, int flags) { if (!parent) return -ENOMEM; - fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); + fd = openat(AT_FDCWD, parent, O_DIRECTORY|O_CLOEXEC|O_PATH); if (fd < 0) return -errno; diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index a3cb81b040..6c11b605a9 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -505,7 +505,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { s = *p; /* accept any number of digits, strtoull is limted to 19 */ - for(i=0; i < digits; i++,s++) { + for (i=0; i < digits; i++,s++) { if (*s < '0' || *s > '9') { if (i == 0) return -EINVAL; diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 189ef9ab60..ae3f6109ad 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -38,6 +38,7 @@ #endif #include "alloc-util.h" +#include "architecture.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" @@ -205,7 +206,7 @@ void rename_process(const char name[8]) { * "systemd"). If you pass a longer string it will be * truncated */ - prctl(PR_SET_NAME, name); + (void) prctl(PR_SET_NAME, name); if (program_invocation_name) strncpy(program_invocation_name, name, strlen(program_invocation_name)); @@ -674,75 +675,43 @@ bool oom_score_adjust_is_valid(int oa) { } unsigned long personality_from_string(const char *p) { + int architecture; - /* Parse a personality specifier. We introduce our own - * identifiers that indicate specific ABIs, rather than just - * hints regarding the register size, since we want to keep - * things open for multiple locally supported ABIs for the - * same register size. We try to reuse the ABI identifiers - * used by libseccomp. */ + if (!p) + return PERSONALITY_INVALID; -#if defined(__x86_64__) + /* Parse a personality specifier. We use our own identifiers that indicate specific ABIs, rather than just + * hints regarding the register size, since we want to keep things open for multiple locally supported ABIs for + * the same register size. */ - if (streq(p, "x86")) - return PER_LINUX32; + architecture = architecture_from_string(p); + if (architecture < 0) + return PERSONALITY_INVALID; - if (streq(p, "x86-64")) + if (architecture == native_architecture()) return PER_LINUX; - -#elif defined(__i386__) - - if (streq(p, "x86")) - return PER_LINUX; - -#elif defined(__s390x__) - - if (streq(p, "s390")) +#ifdef SECONDARY_ARCHITECTURE + if (architecture == SECONDARY_ARCHITECTURE) return PER_LINUX32; - - if (streq(p, "s390x")) - return PER_LINUX; - -#elif defined(__s390__) - - if (streq(p, "s390")) - return PER_LINUX; #endif return PERSONALITY_INVALID; } const char* personality_to_string(unsigned long p) { - -#if defined(__x86_64__) - - if (p == PER_LINUX32) - return "x86"; - - if (p == PER_LINUX) - return "x86-64"; - -#elif defined(__i386__) - - if (p == PER_LINUX) - return "x86"; - -#elif defined(__s390x__) + int architecture = _ARCHITECTURE_INVALID; if (p == PER_LINUX) - return "s390x"; - - if (p == PER_LINUX32) - return "s390"; - -#elif defined(__s390__) - - if (p == PER_LINUX) - return "s390"; - + architecture = native_architecture(); +#ifdef SECONDARY_ARCHITECTURE + else if (p == PER_LINUX32) + architecture = SECONDARY_ARCHITECTURE; #endif - return NULL; + if (architecture < 0) + return NULL; + + return architecture_to_string(architecture); } void valgrind_summary_hack(void) { diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 6c63b9d652..10c2f39369 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -80,31 +80,23 @@ void mac_selinux_retest(void) { #endif } -int mac_selinux_init(const char *prefix) { +int mac_selinux_init(void) { int r = 0; #ifdef HAVE_SELINUX usec_t before_timestamp, after_timestamp; struct mallinfo before_mallinfo, after_mallinfo; - if (!mac_selinux_use()) + if (label_hnd) return 0; - if (label_hnd) + if (!mac_selinux_use()) return 0; before_mallinfo = mallinfo(); before_timestamp = now(CLOCK_MONOTONIC); - if (prefix) { - struct selinux_opt options[] = { - { .type = SELABEL_OPT_SUBSET, .value = prefix }, - }; - - label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options)); - } else - label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); - + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); if (!label_hnd) { log_enforcing("Failed to initialize SELinux context: %m"); r = security_getenforce() == 1 ? -errno : 0; @@ -160,7 +152,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { return 0; if (r >= 0) { - r = lsetfilecon(path, fcon); + r = lsetfilecon_raw(path, fcon); /* If the FS doesn't support labels, then exit without warning */ if (r < 0 && errno == EOPNOTSUPP) @@ -225,7 +217,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { return -errno; sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label); if (r < 0) return -errno; #endif @@ -270,7 +262,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * if (r < 0) return -errno; - r = getpeercon(socket_fd, &peercon); + r = getpeercon_raw(socket_fd, &peercon); if (r < 0) return -errno; @@ -304,7 +296,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * return -ENOMEM; sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label); if (r < 0) return -errno; #endif @@ -358,7 +350,7 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) { log_enforcing("Failed to determine SELinux security context for %s: %m", path); } else { - if (setfscreatecon(filecon) >= 0) + if (setfscreatecon_raw(filecon) >= 0) return 0; /* Success! */ log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path); @@ -379,7 +371,7 @@ void mac_selinux_create_file_clear(void) { if (!mac_selinux_use()) return; - setfscreatecon(NULL); + setfscreatecon_raw(NULL); #endif } @@ -410,7 +402,7 @@ void mac_selinux_create_socket_clear(void) { if (!mac_selinux_use()) return; - setsockcreatecon(NULL); + setsockcreatecon_raw(NULL); #endif } @@ -469,7 +461,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { return -errno; } else { - if (setfscreatecon(fcon) < 0) { + if (setfscreatecon_raw(fcon) < 0) { log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path); if (security_getenforce() > 0) return -errno; @@ -480,7 +472,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { r = bind(fd, addr, addrlen) < 0 ? -errno : 0; if (context_changed) - setfscreatecon(NULL); + setfscreatecon_raw(NULL); return r; diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 27e8edb41b..ce6bc8e44c 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -29,7 +29,7 @@ bool mac_selinux_use(void); bool mac_selinux_have(void); void mac_selinux_retest(void); -int mac_selinux_init(const char *prefix); +int mac_selinux_init(void); void mac_selinux_finish(void); int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs); diff --git a/src/basic/set.h b/src/basic/set.h index 2bff5062da..e0d9dd001c 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -126,6 +126,9 @@ int set_put_strdupv(Set *s, char **l); #define SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) +#define SET_FOREACH_MOVE(e, d, s) \ + for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); ) + DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); diff --git a/src/basic/sigbus.h b/src/basic/sigbus.h index cce9eb201b..980243d9ce 100644 --- a/src/basic/sigbus.h +++ b/src/basic/sigbus.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - void sigbus_install(void); void sigbus_reset(void); diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index 72b10e8712..a7322ff26a 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -44,9 +44,9 @@ static inline void block_signals_reset(sigset_t *ss) { assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0); } -#define BLOCK_SIGNALS(...) \ - _cleanup_(block_signals_reset) sigset_t _saved_sigset = ({ \ - sigset_t t; \ +#define BLOCK_SIGNALS(...) \ + _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \ + sigset_t t; \ assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \ - t; \ + t; \ }) diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 35e9573aa4..6d1dc83874 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -23,7 +23,6 @@ #include <stddef.h> #include <string.h> #include <sys/socket.h> -#include <sys/stat.h> #include <sys/un.h> #include <unistd.h> @@ -35,6 +34,7 @@ #include "mkdir.h" #include "selinux-util.h" #include "socket-util.h" +#include "umask-util.h" int socket_address_listen( const SocketAddress *a, @@ -112,28 +112,24 @@ int socket_address_listen( return -errno; if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) { - mode_t old_mask; - /* Create parents */ - mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode); + (void) mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode); /* Enforce the right access mode for the socket */ - old_mask = umask(~ socket_mode); - - r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0 && errno == EADDRINUSE) { - /* Unlink and try again */ - unlink(a->sockaddr.un.sun_path); - r = bind(fd, &a->sockaddr.sa, a->size); + RUN_WITH_UMASK(~socket_mode) { + r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); + if (r == -EADDRINUSE) { + /* Unlink and try again */ + unlink(a->sockaddr.un.sun_path); + if (bind(fd, &a->sockaddr.sa, a->size) < 0) + return -errno; + } else if (r < 0) + return r; } - - umask(old_mask); - } else - r = bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0) - return -errno; + } else { + if (bind(fd, &a->sockaddr.sa, a->size) < 0) + return -errno; + } if (socket_address_can_accept(a)) if (listen(fd, backlog) < 0) diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 58512686e3..0f38f9a0f3 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -942,7 +942,7 @@ ssize_t next_datagram_size_fd(int fd) { int k; /* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will - * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD dosn't + * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD doesn't * do. This difference is actually of major importance as we need to be sure that the size returned here * actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of * the wrong size. */ diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h index 0a675571ff..bd1144b4c9 100644 --- a/src/basic/stdio-util.h +++ b/src/basic/stdio-util.h @@ -73,4 +73,4 @@ do { \ assert_not_reached("Unknown format string argument."); \ } \ } \ -} while(false) +} while (false) diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index 77220c0251..797f00cf71 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -121,7 +121,7 @@ static void bubbleinsert(struct strbuf_node *node, sizeof(struct strbuf_child_entry) * (node->children_count - left)); node->children[left] = new; - node->children_count ++; + node->children_count++; } /* add string, return the index/offset into the buffer */ @@ -156,6 +156,10 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { return off; } + /* bsearch is not allowed on a NULL sequence */ + if (node->children_count == 0) + break; + /* lookup child node */ c = s[len - 1 - depth]; search.c = c; diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 0bde55f9d5..293a15f9c0 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -477,7 +477,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne } if (k > x) /* last character was wide and went over quota */ - x ++; + x++; for (j = s + old_length; k < new_length && j > i; ) { char32_t c; diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 0b4f5ab5b9..7ca764abeb 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -139,8 +139,7 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us usec_t timespec_load(const struct timespec *ts) { assert(ts); - if (ts->tv_sec == (time_t) -1 && - ts->tv_nsec == (long) -1) + if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) return USEC_INFINITY; if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) @@ -154,13 +153,13 @@ usec_t timespec_load(const struct timespec *ts) { static nsec_t timespec_load_nsec(const struct timespec *ts) { assert(ts); - if (ts->tv_sec == (time_t) -1 && - ts->tv_nsec == (long) -1) + if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) return NSEC_INFINITY; - return - (nsec_t) ts->tv_sec * NSEC_PER_SEC + - (nsec_t) ts->tv_nsec; + if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC) + return NSEC_INFINITY; + + return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec; } struct timespec *timespec_store(struct timespec *ts, usec_t u) { @@ -577,12 +576,12 @@ int parse_timestamp(const char *t, usec_t *usec) { goto from_tm; } else if (streq(t, "yesterday")) { - tm.tm_mday --; + tm.tm_mday--; tm.tm_sec = tm.tm_min = tm.tm_hour = 0; goto from_tm; } else if (streq(t, "tomorrow")) { - tm.tm_mday ++; + tm.tm_mday++; tm.tm_sec = tm.tm_min = tm.tm_hour = 0; goto from_tm; } @@ -705,8 +704,7 @@ finish: return 0; } -int parse_time(const char *t, usec_t *usec, usec_t default_unit) { - +static char* extract_multiplier(char *p, usec_t *multiplier) { static const struct { const char *suffix; usec_t usec; @@ -740,7 +738,22 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { { "usec", 1ULL }, { "us", 1ULL }, }; + unsigned i; + + for (i = 0; i < ELEMENTSOF(table); i++) { + char *e; + + e = startswith(p, table[i].suffix); + if (e) { + *multiplier = table[i].usec; + return e; + } + } + + return p; +} +int parse_time(const char *t, usec_t *usec, usec_t default_unit) { const char *p, *s; usec_t r = 0; bool something = false; @@ -765,8 +778,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { for (;;) { long long l, z = 0; char *e; - unsigned i, n = 0; - usec_t multiplier, k; + unsigned n = 0; + usec_t multiplier = default_unit, k; p += strspn(p, WHITESPACE); @@ -779,10 +792,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { errno = 0; l = strtoll(p, &e, 10); - if (errno > 0) return -errno; - if (l < 0) return -ERANGE; @@ -806,18 +817,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { return -EINVAL; e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - multiplier = table[i].usec; - p = e + strlen(table[i].suffix); - break; - } - - if (i >= ELEMENTSOF(table)) { - multiplier = default_unit; - p = e; - } + p = extract_multiplier(e, &multiplier); something = true; diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 629db123cd..6eae2b983d 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -241,7 +241,7 @@ char *utf8_escape_non_printable(const char *str) { *(s++) = hexchar((int) *str); str += 1; - len --; + len--; } } } else { diff --git a/src/basic/utf8.h b/src/basic/utf8.h index 12c272d66e..f9b9c9468b 100644 --- a/src/basic/utf8.h +++ b/src/basic/utf8.h @@ -28,6 +28,7 @@ #include "missing.h" #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" +#define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf" bool unichar_is_valid(char32_t c); diff --git a/src/basic/util.h b/src/basic/util.h index e095254b57..286db05159 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -36,6 +36,7 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/statfs.h> +#include <sys/sysmacros.h> #include <sys/types.h> #include <time.h> #include <unistd.h> diff --git a/src/basic/virt.c b/src/basic/virt.c index 19b6318e3d..e6c5a095a0 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -98,6 +98,8 @@ static int detect_vm_cpuid(void) { : "0" (eax) ); + log_debug("Virtualization found, CPUID=%s", sig.text); + for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++) if (streq(sig.text, cpuid_vendor_table[j].cpuid)) return cpuid_vendor_table[j].id; @@ -105,6 +107,7 @@ static int detect_vm_cpuid(void) { return VIRTUALIZATION_VM_OTHER; } #endif + log_debug("No virtualization found in CPUID"); return VIRTUALIZATION_NONE; } @@ -121,19 +124,25 @@ static int detect_vm_device_tree(void) { dir = opendir("/proc/device-tree"); if (!dir) { - if (errno == ENOENT) + if (errno == ENOENT) { + log_debug_errno(errno, "/proc/device-tree: %m"); return VIRTUALIZATION_NONE; + } return -errno; } FOREACH_DIRENT(dent, dir, return -errno) - if (strstr(dent->d_name, "fw-cfg")) + if (strstr(dent->d_name, "fw-cfg")) { + log_debug("Virtualization QEMU: \"fw-cfg\" present in /proc/device-tree/%s", dent->d_name); return VIRTUALIZATION_QEMU; + } + log_debug("No virtualization found in /proc/device-tree/*"); return VIRTUALIZATION_NONE; } else if (r < 0) return r; + log_debug("Virtualization %s found in /proc/device-tree/hypervisor/compatible", hvtype); if (streq(hvtype, "linux,kvm")) return VIRTUALIZATION_KVM; else if (strstr(hvtype, "xen")) @@ -141,6 +150,7 @@ static int detect_vm_device_tree(void) { else return VIRTUALIZATION_VM_OTHER; #else + log_debug("This platform does not support /proc/device-tree"); return VIRTUALIZATION_NONE; #endif } @@ -184,30 +194,58 @@ static int detect_vm_dmi(void) { return r; } + + for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++) - if (startswith(s, dmi_vendor_table[j].vendor)) + if (startswith(s, dmi_vendor_table[j].vendor)) { + log_debug("Virtualization %s found in DMI (%s)", s, dmi_vendors[i]); return dmi_vendor_table[j].id; + } } #endif + log_debug("No virtualization found in DMI"); + return VIRTUALIZATION_NONE; } static int detect_vm_xen(void) { + /* Check for Dom0 will be executed later in detect_vm_xen_dom0 + Thats why we dont check the content of /proc/xen/capabilities here. */ + if (access("/proc/xen/capabilities", F_OK) < 0) { + log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist"); + return VIRTUALIZATION_NONE; + } + + log_debug("Virtualization XEN found (/proc/xen/capabilities exists)"); + return VIRTUALIZATION_XEN; + +} + +static bool detect_vm_xen_dom0(void) { _cleanup_free_ char *domcap = NULL; char *cap, *i; int r; r = read_one_line_file("/proc/xen/capabilities", &domcap); - if (r == -ENOENT) - return VIRTUALIZATION_NONE; + if (r == -ENOENT) { + log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist"); + return false; + } + if (r < 0) + return r; i = domcap; while ((cap = strsep(&i, ","))) if (streq(cap, "control_d")) break; + if (!cap) { + log_debug("Virtualization XEN DomU found (/proc/xen/capabilites)"); + return false; + } - return cap ? VIRTUALIZATION_NONE : VIRTUALIZATION_XEN; + log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)"); + return true; } static int detect_vm_hypervisor(void) { @@ -220,6 +258,8 @@ static int detect_vm_hypervisor(void) { if (r < 0) return r; + log_debug("Virtualization %s found in /sys/hypervisor/type", hvtype); + if (streq(hvtype, "xen")) return VIRTUALIZATION_XEN; else @@ -234,9 +274,13 @@ static int detect_vm_uml(void) { r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL); if (r < 0) return r; - if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) + + if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) { + log_debug("UML virtualization found in /proc/cpuinfo"); return VIRTUALIZATION_UML; + } + log_debug("No virtualization found in /proc/cpuinfo (%s)", cpuinfo_contents); return VIRTUALIZATION_NONE; } @@ -252,11 +296,13 @@ static int detect_vm_zvm(void) { if (r < 0) return r; + log_debug("Virtualization %s found in /proc/sysinfo", t); if (streq(t, "z/VM")) return VIRTUALIZATION_ZVM; else return VIRTUALIZATION_KVM; #else + log_debug("This platform does not support /proc/sysinfo"); return VIRTUALIZATION_NONE; #endif } @@ -324,7 +370,14 @@ int detect_vm(void) { return r; finish: + /* x86 xen Dom0 is detected as XEN in hypervisor and maybe others. + * In order to detect the Dom0 as not virtualization we need to + * double-check it */ + if (r == VIRTUALIZATION_XEN && detect_vm_xen_dom0()) + r = VIRTUALIZATION_NONE; + cached_found = r; + log_debug("Found VM virtualization %s", virtualization_to_string(r)); return r; } @@ -412,6 +465,7 @@ int detect_container(void) { r = VIRTUALIZATION_CONTAINER_OTHER; finish: + log_debug("Found container virtualization %s", virtualization_to_string(r)); cached_found = r; return r; } @@ -420,10 +474,10 @@ int detect_virtualization(void) { int r; r = detect_container(); - if (r != 0) - return r; + if (r == 0) + r = detect_vm(); - return detect_vm(); + return r; } int running_in_chroot(void) { diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index 8d7f14f382..8256899eda 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -110,7 +110,7 @@ ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ - fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); + fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); if (fd < 0) return -errno; diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c index b1cc2c0b72..c0ef7f64fe 100644 --- a/src/boot/efi/splash.c +++ b/src/boot/efi/splash.c @@ -281,9 +281,9 @@ EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_ if (EFI_ERROR(err)) goto err; - if(dib->x < GraphicsOutput->Mode->Info->HorizontalResolution) + if (dib->x < GraphicsOutput->Mode->Info->HorizontalResolution) x_pos = (GraphicsOutput->Mode->Info->HorizontalResolution - dib->x) / 2; - if(dib->y < GraphicsOutput->Mode->Info->VerticalResolution) + if (dib->y < GraphicsOutput->Mode->Info->VerticalResolution) y_pos = (GraphicsOutput->Mode->Info->VerticalResolution - dib->y) / 2; uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput, diff --git a/src/bootchart/Makefile b/src/bootchart/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/bootchart/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c deleted file mode 100644 index 77d158f5f9..0000000000 --- a/src/bootchart/bootchart.c +++ /dev/null @@ -1,531 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - 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/>. - ***/ - -/*** - - Many thanks to those who contributed ideas and code: - - Ziga Mahkovec - Original bootchart author - - Anders Norgaard - PyBootchartgui - - Michael Meeks - bootchart2 - - Scott James Remnant - Ubuntu C-based logger - - Arjan van der Ven - for the idea to merge bootgraph.pl functionality - - ***/ - -#include <errno.h> -#include <fcntl.h> -#include <getopt.h> -#include <limits.h> -#include <signal.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/resource.h> -#include <time.h> -#include <unistd.h> - -#include "sd-journal.h" - -#include "alloc-util.h" -#include "bootchart.h" -#include "conf-parser.h" -#include "def.h" -#include "fd-util.h" -#include "fileio.h" -#include "io-util.h" -#include "list.h" -#include "macro.h" -#include "parse-util.h" -#include "path-util.h" -#include "store.h" -#include "string-util.h" -#include "strxcpyx.h" -#include "svg.h" -#include "util.h" - -static int exiting = 0; - -#define DEFAULT_SAMPLES_LEN 500 -#define DEFAULT_HZ 25.0 -#define DEFAULT_SCALE_X 100.0 /* 100px = 1sec */ -#define DEFAULT_SCALE_Y 20.0 /* 16px = 1 process bar */ -#define DEFAULT_INIT ROOTLIBEXECDIR "/systemd" -#define DEFAULT_OUTPUT "/run/log" - -/* graph defaults */ -bool arg_entropy = false; -bool arg_initcall = true; -bool arg_relative = false; -bool arg_filter = true; -bool arg_show_cmdline = false; -bool arg_show_cgroup = false; -bool arg_pss = false; -bool arg_percpu = false; -int arg_samples_len = DEFAULT_SAMPLES_LEN; /* we record len+1 (1 start sample) */ -double arg_hz = DEFAULT_HZ; -double arg_scale_x = DEFAULT_SCALE_X; -double arg_scale_y = DEFAULT_SCALE_Y; - -char arg_init_path[PATH_MAX] = DEFAULT_INIT; -char arg_output_path[PATH_MAX] = DEFAULT_OUTPUT; - -static void signal_handler(int sig) { - exiting = 1; -} - -#define BOOTCHART_MAX (16*1024*1024) - -static void parse_conf(void) { - char *init = NULL, *output = NULL; - const ConfigTableItem items[] = { - { "Bootchart", "Samples", config_parse_int, 0, &arg_samples_len }, - { "Bootchart", "Frequency", config_parse_double, 0, &arg_hz }, - { "Bootchart", "Relative", config_parse_bool, 0, &arg_relative }, - { "Bootchart", "Filter", config_parse_bool, 0, &arg_filter }, - { "Bootchart", "Output", config_parse_path, 0, &output }, - { "Bootchart", "Init", config_parse_path, 0, &init }, - { "Bootchart", "PlotMemoryUsage", config_parse_bool, 0, &arg_pss }, - { "Bootchart", "PlotEntropyGraph", config_parse_bool, 0, &arg_entropy }, - { "Bootchart", "ScaleX", config_parse_double, 0, &arg_scale_x }, - { "Bootchart", "ScaleY", config_parse_double, 0, &arg_scale_y }, - { "Bootchart", "ControlGroup", config_parse_bool, 0, &arg_show_cgroup }, - { "Bootchart", "PerCPU", config_parse_bool, 0, &arg_percpu }, - { NULL, NULL, NULL, 0, NULL } - }; - - config_parse_many(PKGSYSCONFDIR "/bootchart.conf", - CONF_PATHS_NULSTR("systemd/bootchart.conf.d"), - NULL, config_item_table_lookup, items, true, NULL); - - if (init != NULL) - strscpy(arg_init_path, sizeof(arg_init_path), init); - if (output != NULL) - strscpy(arg_output_path, sizeof(arg_output_path), output); -} - -static void help(void) { - printf("Usage: %s [OPTIONS]\n\n" - "Options:\n" - " -r --rel Record time relative to recording\n" - " -f --freq=FREQ Sample frequency [%g]\n" - " -n --samples=N Stop sampling at [%d] samples\n" - " -x --scale-x=N Scale the graph horizontally [%g] \n" - " -y --scale-y=N Scale the graph vertically [%g] \n" - " -p --pss Enable PSS graph (CPU intensive)\n" - " -e --entropy Enable the entropy_avail graph\n" - " -o --output=PATH Path to output files [%s]\n" - " -i --init=PATH Path to init executable [%s]\n" - " -F --no-filter Disable filtering of unimportant or ephemeral processes\n" - " -C --cmdline Display full command lines with arguments\n" - " -c --control-group Display process control group\n" - " --per-cpu Draw each CPU utilization and wait bar also\n" - " -h --help Display this message\n\n" - "See bootchart.conf for more information.\n", - program_invocation_short_name, - DEFAULT_HZ, - DEFAULT_SAMPLES_LEN, - DEFAULT_SCALE_X, - DEFAULT_SCALE_Y, - DEFAULT_OUTPUT, - DEFAULT_INIT); -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_PERCPU = 0x100, - }; - - static const struct option options[] = { - {"rel", no_argument, NULL, 'r' }, - {"freq", required_argument, NULL, 'f' }, - {"samples", required_argument, NULL, 'n' }, - {"pss", no_argument, NULL, 'p' }, - {"output", required_argument, NULL, 'o' }, - {"init", required_argument, NULL, 'i' }, - {"no-filter", no_argument, NULL, 'F' }, - {"cmdline", no_argument, NULL, 'C' }, - {"control-group", no_argument, NULL, 'c' }, - {"help", no_argument, NULL, 'h' }, - {"scale-x", required_argument, NULL, 'x' }, - {"scale-y", required_argument, NULL, 'y' }, - {"entropy", no_argument, NULL, 'e' }, - {"per-cpu", no_argument, NULL, ARG_PERCPU}, - {} - }; - int c, r; - - if (getpid() == 1) - opterr = 0; - - while ((c = getopt_long(argc, argv, "erpf:n:o:i:FCchx:y:", options, NULL)) >= 0) - switch (c) { - - case 'r': - arg_relative = true; - break; - case 'f': - r = safe_atod(optarg, &arg_hz); - if (r < 0) - log_warning_errno(r, "failed to parse --freq/-f argument '%s': %m", - optarg); - break; - case 'F': - arg_filter = false; - break; - case 'C': - arg_show_cmdline = true; - break; - case 'c': - arg_show_cgroup = true; - break; - case 'n': - r = safe_atoi(optarg, &arg_samples_len); - if (r < 0) - log_warning_errno(r, "failed to parse --samples/-n argument '%s': %m", - optarg); - break; - case 'o': - path_kill_slashes(optarg); - strscpy(arg_output_path, sizeof(arg_output_path), optarg); - break; - case 'i': - path_kill_slashes(optarg); - strscpy(arg_init_path, sizeof(arg_init_path), optarg); - break; - case 'p': - arg_pss = true; - break; - case 'x': - r = safe_atod(optarg, &arg_scale_x); - if (r < 0) - log_warning_errno(r, "failed to parse --scale-x/-x argument '%s': %m", - optarg); - break; - case 'y': - r = safe_atod(optarg, &arg_scale_y); - if (r < 0) - log_warning_errno(r, "failed to parse --scale-y/-y argument '%s': %m", - optarg); - break; - case 'e': - arg_entropy = true; - break; - case ARG_PERCPU: - arg_percpu = true; - break; - case 'h': - help(); - return 0; - case '?': - if (getpid() != 1) - return -EINVAL; - else - return 0; - default: - assert_not_reached("Unhandled option code."); - } - - if (arg_hz <= 0) { - log_error("Frequency needs to be > 0"); - return -EINVAL; - } - - return 1; -} - -static int do_journal_append(char *file) { - _cleanup_free_ char *bootchart_message = NULL; - _cleanup_free_ char *bootchart_file = NULL; - _cleanup_free_ char *p = NULL; - _cleanup_close_ int fd = -1; - struct iovec iovec[5]; - int r, j = 0; - ssize_t n; - - bootchart_file = strappend("BOOTCHART_FILE=", file); - if (!bootchart_file) - return log_oom(); - - IOVEC_SET_STRING(iovec[j++], bootchart_file); - IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518"); - IOVEC_SET_STRING(iovec[j++], "PRIORITY=7"); - bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL); - if (!bootchart_message) - return log_oom(); - - IOVEC_SET_STRING(iovec[j++], bootchart_message); - - p = malloc(10 + BOOTCHART_MAX); - if (!p) - return log_oom(); - - memcpy(p, "BOOTCHART=", 10); - - fd = open(file, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return log_error_errno(errno, "Failed to open bootchart data \"%s\": %m", file); - - n = loop_read(fd, p + 10, BOOTCHART_MAX, false); - if (n < 0) - return log_error_errno(n, "Failed to read bootchart data: %m"); - - iovec[j].iov_base = p; - iovec[j].iov_len = 10 + n; - j++; - - r = sd_journal_sendv(iovec, j); - if (r < 0) - log_error_errno(r, "Failed to send bootchart: %m"); - - return 0; -} - -int main(int argc, char *argv[]) { - static struct list_sample_data *sampledata; - _cleanup_closedir_ DIR *proc = NULL; - _cleanup_free_ char *build = NULL; - _cleanup_fclose_ FILE *of = NULL; - _cleanup_close_ int sysfd = -1; - struct ps_struct *ps_first; - double graph_start; - double log_start; - double interval; - char output_file[PATH_MAX]; - char datestr[200]; - int pscount = 0; - int n_cpus = 0; - int overrun = 0; - time_t t = 0; - int r, samples; - struct ps_struct *ps; - struct rlimit rlim; - struct list_sample_data *head; - struct sigaction sig = { - .sa_handler = signal_handler, - }; - - parse_conf(); - - r = parse_argv(argc, argv); - if (r < 0) - return EXIT_FAILURE; - - if (r == 0) - return EXIT_SUCCESS; - - /* - * If the kernel executed us through init=/usr/lib/systemd/systemd-bootchart, then - * fork: - * - parent execs executable specified via init_path[] (/usr/lib/systemd/systemd by default) as pid=1 - * - child logs data - */ - if (getpid() == 1) { - if (fork()) - /* parent */ - execl(arg_init_path, arg_init_path, NULL); - } - argv[0][0] = '@'; - - rlim.rlim_cur = 4096; - rlim.rlim_max = 4096; - (void) setrlimit(RLIMIT_NOFILE, &rlim); - - /* start with empty ps LL */ - ps_first = new0(struct ps_struct, 1); - if (!ps_first) { - log_oom(); - return EXIT_FAILURE; - } - - /* handle TERM/INT nicely */ - sigaction(SIGHUP, &sig, NULL); - - interval = (1.0 / arg_hz) * 1000000000.0; - - if (arg_relative) - graph_start = log_start = gettime_ns(); - else { - struct timespec n; - double uptime; - - clock_gettime(clock_boottime_or_monotonic(), &n); - uptime = (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC)); - - log_start = gettime_ns(); - graph_start = log_start - uptime; - } - - if (graph_start < 0.0) { - log_error("Failed to setup graph start time.\n\n" - "The system uptime probably includes time that the system was suspended. " - "Use --rel to bypass this issue."); - return EXIT_FAILURE; - } - - LIST_HEAD_INIT(head); - - /* main program loop */ - for (samples = 0; !exiting && samples < arg_samples_len; samples++) { - int res; - double sample_stop; - double elapsed; - double timeleft; - - sampledata = new0(struct list_sample_data, 1); - if (sampledata == NULL) { - log_oom(); - return EXIT_FAILURE; - } - - sampledata->sampletime = gettime_ns(); - sampledata->counter = samples; - - if (sysfd < 0) - sysfd = open("/sys", O_RDONLY|O_CLOEXEC); - - if (!build) { - if (parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &build, NULL) == -ENOENT) - parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &build, NULL); - } - - if (proc) - rewinddir(proc); - else - proc = opendir("/proc"); - - /* wait for /proc to become available, discarding samples */ - if (proc) { - r = log_sample(proc, samples, ps_first, &sampledata, &pscount, &n_cpus); - if (r < 0) - return EXIT_FAILURE; - } - - sample_stop = gettime_ns(); - - elapsed = (sample_stop - sampledata->sampletime) * 1000000000.0; - timeleft = interval - elapsed; - - /* - * check if we have not consumed our entire timeslice. If we - * do, don't sleep and take a new sample right away. - * we'll lose all the missed samples and overrun our total - * time - */ - if (timeleft > 0) { - struct timespec req; - - req.tv_sec = (time_t)(timeleft / 1000000000.0); - req.tv_nsec = (long)(timeleft - (req.tv_sec * 1000000000.0)); - - res = nanosleep(&req, NULL); - if (res) { - if (errno == EINTR) - /* caught signal, probably HUP! */ - break; - log_error_errno(errno, "nanosleep() failed: %m"); - return EXIT_FAILURE; - } - } else { - overrun++; - /* calculate how many samples we lost and scrap them */ - arg_samples_len -= (int)(-timeleft / interval); - } - LIST_PREPEND(link, head, sampledata); - } - - /* do some cleanup, close fd's */ - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - ps->schedstat = safe_close(ps->schedstat); - ps->sched = safe_close(ps->sched); - ps->smaps = safe_fclose(ps->smaps); - } - - if (!of) { - t = time(NULL); - r = strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); - assert_se(r > 0); - - snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr); - of = fopen(output_file, "we"); - } - - if (!of) { - log_error("Error opening output file '%s': %m\n", output_file); - return EXIT_FAILURE; - } - - r = svg_do(of, strna(build), head, ps_first, - samples, pscount, n_cpus, graph_start, - log_start, interval, overrun); - - if (r < 0) { - log_error_errno(r, "Error generating svg file: %m"); - return EXIT_FAILURE; - } - - log_info("systemd-bootchart wrote %s\n", output_file); - - r = do_journal_append(output_file); - if (r < 0) - return EXIT_FAILURE; - - /* nitpic cleanups */ - ps = ps_first->next_ps; - while (ps->next_ps) { - struct ps_struct *old; - - old = ps; - old->sample = ps->first; - ps = ps->next_ps; - while (old->sample->next) { - struct ps_sched_struct *oldsample = old->sample; - - old->sample = old->sample->next; - free(oldsample); - } - free(old->cgroup); - free(old->sample); - free(old); - } - - free(ps->cgroup); - free(ps->sample); - free(ps); - - sampledata = head; - while (sampledata->link_prev) { - struct list_sample_data *old_sampledata = sampledata; - sampledata = sampledata->link_prev; - free(old_sampledata); - } - free(sampledata); - - /* don't complain when overrun once, happens most commonly on 1st sample */ - if (overrun > 1) - log_warning("systemd-bootchart: sample time overrun %i times\n", overrun); - - return 0; -} diff --git a/src/bootchart/bootchart.conf b/src/bootchart/bootchart.conf deleted file mode 100644 index 4f5e50936e..0000000000 --- a/src/bootchart/bootchart.conf +++ /dev/null @@ -1,26 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. -# -# See bootchart.conf(5) for details. - -[Bootchart] -#Samples=500 -#Frequency=25 -#Relative=no -#Filter=yes -#Output=<folder name, defaults to /run/log> -#Init=/path/to/init-binary -#PlotMemoryUsage=no -#PlotEntropyGraph=no -#ScaleX=100 -#ScaleY=20 -#ControlGroup=no -#PerCPU=no diff --git a/src/bootchart/bootchart.h b/src/bootchart/bootchart.h deleted file mode 100644 index 1b445b954b..0000000000 --- a/src/bootchart/bootchart.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - 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 "list.h" - -#define MAXCPUS 16 -#define MAXPIDS 65535 - -struct block_stat_struct { - /* /proc/vmstat pgpgin & pgpgout */ - int bi; - int bo; -}; - -struct cpu_stat_sample_struct { - /* /proc/schedstat fields 10 & 11 (after name) */ - double runtime; - double waittime; -}; - -/* per process, per sample data we will log */ -struct ps_sched_struct { - /* /proc/<n>/schedstat fields 1 & 2 */ - double runtime; - double waittime; - int pss; - struct list_sample_data *sampledata; - struct ps_sched_struct *next; - struct ps_sched_struct *prev; - struct ps_sched_struct *cross; /* cross pointer */ - struct ps_struct *ps_new; -}; - -struct list_sample_data { - double runtime[MAXCPUS]; - double waittime[MAXCPUS]; - double sampletime; - int entropy_avail; - struct block_stat_struct blockstat; - LIST_FIELDS(struct list_sample_data, link); /* DLL */ - int counter; -}; - -/* process info */ -struct ps_struct { - struct ps_struct *next_ps; /* SLL pointer */ - struct ps_struct *parent; /* ppid ref */ - struct ps_struct *children; /* children */ - struct ps_struct *next; /* siblings */ - - /* must match - otherwise it's a new process with same PID */ - char name[256]; - int pid; - int ppid; - char *cgroup; - - /* cache fd's */ - int sched; - int schedstat; - FILE *smaps; - - /* pointers to first/last seen timestamps */ - struct ps_sched_struct *first; - struct ps_sched_struct *last; - - /* records actual start time, may be way before bootchart runs */ - double starttime; - - /* record human readable total cpu time */ - double total; - - /* largest PSS size found */ - int pss_max; - - /* for drawing connection lines later */ - double pos_x; - double pos_y; - - struct ps_sched_struct *sample; -}; - -extern bool arg_relative; -extern bool arg_filter; -extern bool arg_show_cmdline; -extern bool arg_show_cgroup; -extern bool arg_pss; -extern bool arg_entropy; -extern bool arg_percpu; -extern bool arg_initcall; -extern int arg_samples_len; -extern double arg_hz; -extern double arg_scale_x; -extern double arg_scale_y; - -extern char arg_output_path[PATH_MAX]; -extern char arg_init_path[PATH_MAX]; diff --git a/src/bootchart/store.c b/src/bootchart/store.c deleted file mode 100644 index 42cb8043ce..0000000000 --- a/src/bootchart/store.c +++ /dev/null @@ -1,555 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - 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 <dirent.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - -#include "alloc-util.h" -#include "bootchart.h" -#include "cgroup-util.h" -#include "dirent-util.h" -#include "fd-util.h" -#include "fileio.h" -#include "parse-util.h" -#include "store.h" -#include "string-util.h" -#include "strxcpyx.h" -#include "time-util.h" -#include "util.h" - -/* - * Alloc a static 4k buffer for stdio - primarily used to increase - * PSS buffering from the default 1k stdin buffer to reduce - * read() overhead. - */ -static char smaps_buf[4096]; -static int skip = 0; - -double gettime_ns(void) { - struct timespec n; - - clock_gettime(CLOCK_MONOTONIC, &n); - - return (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC)); -} - -static char *bufgetline(char *buf) { - char *c; - - if (!buf) - return NULL; - - c = strchr(buf, '\n'); - if (c) - c++; - - return c; -} - -static int pid_cmdline_strscpy(int procfd, char *buffer, size_t buf_len, int pid) { - char filename[PATH_MAX]; - _cleanup_close_ int fd = -1; - ssize_t n; - - sprintf(filename, "%d/cmdline", pid); - fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return -errno; - - n = read(fd, buffer, buf_len-1); - if (n > 0) { - int i; - for (i = 0; i < n; i++) - if (buffer[i] == '\0') - buffer[i] = ' '; - buffer[n] = '\0'; - } - - return 0; -} - -int log_sample(DIR *proc, - int sample, - struct ps_struct *ps_first, - struct list_sample_data **ptr, - int *pscount, - int *cpus) { - - static int vmstat = -1; - _cleanup_free_ char *buf_schedstat = NULL; - char buf[4096]; - char key[256]; - char val[256]; - char rt[256]; - char wt[256]; - char *m; - int r; - int c; - int p; - int mod; - static int e_fd = -1; - ssize_t s; - ssize_t n; - struct dirent *ent; - int fd; - struct list_sample_data *sampledata; - struct ps_sched_struct *ps_prev = NULL; - int procfd; - int taskfd = -1; - - sampledata = *ptr; - - procfd = dirfd(proc); - if (procfd < 0) - return -errno; - - if (vmstat < 0) { - /* block stuff */ - vmstat = openat(procfd, "vmstat", O_RDONLY|O_CLOEXEC); - if (vmstat < 0) - return log_error_errno(errno, "Failed to open /proc/vmstat: %m"); - } - - n = pread(vmstat, buf, sizeof(buf) - 1, 0); - if (n <= 0) { - vmstat = safe_close(vmstat); - if (n < 0) - return -errno; - return -ENODATA; - } - - buf[n] = '\0'; - - m = buf; - while (m) { - if (sscanf(m, "%s %s", key, val) < 2) - goto vmstat_next; - if (streq(key, "pgpgin")) - sampledata->blockstat.bi = atoi(val); - if (streq(key, "pgpgout")) { - sampledata->blockstat.bo = atoi(val); - break; - } -vmstat_next: - m = bufgetline(m); - if (!m) - break; - } - - /* Parse "/proc/schedstat" for overall CPU utilization */ - r = read_full_file("/proc/schedstat", &buf_schedstat, NULL); - if (r < 0) - return log_error_errno(r, "Unable to read schedstat: %m"); - - m = buf_schedstat; - while (m) { - if (sscanf(m, "%s %*s %*s %*s %*s %*s %*s %s %s", key, rt, wt) < 3) - goto schedstat_next; - - if (strstr(key, "cpu")) { - r = safe_atoi((const char*)(key+3), &c); - if (r < 0 || c > MAXCPUS -1) - /* Oops, we only have room for MAXCPUS data */ - break; - sampledata->runtime[c] = atoll(rt); - sampledata->waittime[c] = atoll(wt); - - if (c == *cpus) - *cpus = c + 1; - } -schedstat_next: - m = bufgetline(m); - if (!m) - break; - } - - if (arg_entropy) { - if (e_fd < 0) { - e_fd = openat(procfd, "sys/kernel/random/entropy_avail", O_RDONLY|O_CLOEXEC); - if (e_fd < 0) - return log_error_errno(errno, "Failed to open /proc/sys/kernel/random/entropy_avail: %m"); - } - - n = pread(e_fd, buf, sizeof(buf) - 1, 0); - if (n <= 0) { - e_fd = safe_close(e_fd); - } else { - buf[n] = '\0'; - sampledata->entropy_avail = atoi(buf); - } - } - - while ((ent = readdir(proc)) != NULL) { - char filename[PATH_MAX]; - int pid; - struct ps_struct *ps; - - if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) - continue; - - pid = atoi(ent->d_name); - - if (pid >= MAXPIDS) - continue; - - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - if (ps->pid == pid) - break; - } - - /* end of our LL? then append a new record */ - if (ps->pid != pid) { - _cleanup_fclose_ FILE *st = NULL; - char t[32]; - struct ps_struct *parent; - - ps->next_ps = new0(struct ps_struct, 1); - if (!ps->next_ps) - return log_oom(); - - ps = ps->next_ps; - ps->pid = pid; - ps->sched = -1; - ps->schedstat = -1; - - ps->sample = new0(struct ps_sched_struct, 1); - if (!ps->sample) - return log_oom(); - - ps->sample->sampledata = sampledata; - - (*pscount)++; - - /* mark our first sample */ - ps->first = ps->last = ps->sample; - ps->sample->runtime = atoll(rt); - ps->sample->waittime = atoll(wt); - - /* get name, start time */ - if (ps->sched < 0) { - sprintf(filename, "%d/sched", pid); - ps->sched = openat(procfd, filename, O_RDONLY|O_CLOEXEC); - if (ps->sched < 0) - continue; - } - - s = pread(ps->sched, buf, sizeof(buf) - 1, 0); - if (s <= 0) { - ps->sched = safe_close(ps->sched); - continue; - } - buf[s] = '\0'; - - if (!sscanf(buf, "%s %*s %*s", key)) - continue; - - strscpy(ps->name, sizeof(ps->name), key); - - /* cmdline */ - if (arg_show_cmdline) - pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid); - - /* discard line 2 */ - m = bufgetline(buf); - if (!m) - continue; - - m = bufgetline(m); - if (!m) - continue; - - if (!sscanf(m, "%*s %*s %s", t)) - continue; - - r = safe_atod(t, &ps->starttime); - if (r < 0) - continue; - - ps->starttime /= 1000.0; - - if (arg_show_cgroup) - /* if this fails, that's OK */ - cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, - ps->pid, &ps->cgroup); - - /* ppid */ - sprintf(filename, "%d/stat", pid); - fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC); - if (fd < 0) - continue; - - st = fdopen(fd, "re"); - if (!st) { - close(fd); - continue; - } - - if (!fscanf(st, "%*s %*s %*s %i", &p)) - continue; - - ps->ppid = p; - - /* - * setup child pointers - * - * these are used to paint the tree coherently later - * each parent has a LL of children, and a LL of siblings - */ - if (pid == 1) - continue; /* nothing to do for init atm */ - - /* kthreadd has ppid=0, which breaks our tree ordering */ - if (ps->ppid == 0) - ps->ppid = 1; - - parent = ps_first; - while ((parent->next_ps && parent->pid != ps->ppid)) - parent = parent->next_ps; - - if (parent->pid != ps->ppid) { - /* orphan */ - ps->ppid = 1; - parent = ps_first->next_ps; - } - - ps->parent = parent; - - if (!parent->children) { - /* it's the first child */ - parent->children = ps; - } else { - /* walk all children and append */ - struct ps_struct *children; - children = parent->children; - while (children->next) - children = children->next; - - children->next = ps; - } - } - - /* else -> found pid, append data in ps */ - - /* below here is all continuous logging parts - we get here on every - * iteration */ - - /* rt, wt */ - if (ps->schedstat < 0) { - sprintf(filename, "%d/schedstat", pid); - ps->schedstat = openat(procfd, filename, O_RDONLY|O_CLOEXEC); - if (ps->schedstat < 0) - continue; - } - - s = pread(ps->schedstat, buf, sizeof(buf) - 1, 0); - if (s <= 0) { - /* clean up our file descriptors - assume that the process exited */ - close(ps->schedstat); - ps->schedstat = -1; - ps->sched = safe_close(ps->sched); - continue; - } - - buf[s] = '\0'; - - if (!sscanf(buf, "%s %s %*s", rt, wt)) - continue; - - ps->sample->next = new0(struct ps_sched_struct, 1); - if (!ps->sample->next) - return log_oom(); - - ps->sample->next->prev = ps->sample; - ps->sample = ps->sample->next; - ps->last = ps->sample; - ps->sample->runtime = atoll(rt); - ps->sample->waittime = atoll(wt); - ps->sample->sampledata = sampledata; - ps->sample->ps_new = ps; - if (ps_prev) - ps_prev->cross = ps->sample; - - ps_prev = ps->sample; - ps->total = (ps->last->runtime - ps->first->runtime) - / 1000000000.0; - - /* Take into account CPU runtime/waittime spent in non-main threads of the process - * by parsing "/proc/[pid]/task/[tid]/schedstat" for all [tid] != [pid] - * See https://github.com/systemd/systemd/issues/139 - */ - - /* Browse directory "/proc/[pid]/task" to know the thread ids of process [pid] */ - snprintf(filename, sizeof(filename), PID_FMT "/task", pid); - taskfd = openat(procfd, filename, O_RDONLY|O_DIRECTORY|O_CLOEXEC); - if (taskfd >= 0) { - _cleanup_closedir_ DIR *taskdir = NULL; - - taskdir = fdopendir(taskfd); - if (!taskdir) { - safe_close(taskfd); - return -errno; - } - FOREACH_DIRENT(ent, taskdir, break) { - int tid = -1; - _cleanup_close_ int tid_schedstat = -1; - long long delta_rt; - long long delta_wt; - - if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) - continue; - - /* Skip main thread as it was already accounted */ - r = safe_atoi(ent->d_name, &tid); - if (r < 0 || tid == pid) - continue; - - /* Parse "/proc/[pid]/task/[tid]/schedstat" */ - snprintf(filename, sizeof(filename), PID_FMT "/schedstat", tid); - tid_schedstat = openat(taskfd, filename, O_RDONLY|O_CLOEXEC); - - if (tid_schedstat == -1) - continue; - - s = pread(tid_schedstat, buf, sizeof(buf) - 1, 0); - if (s <= 0) - continue; - buf[s] = '\0'; - - if (!sscanf(buf, "%s %s %*s", rt, wt)) - continue; - - r = safe_atolli(rt, &delta_rt); - if (r < 0) - continue; - r = safe_atolli(rt, &delta_wt); - if (r < 0) - continue; - ps->sample->runtime += delta_rt; - ps->sample->waittime += delta_wt; - } - } - - if (!arg_pss) - goto catch_rename; - - /* Pss */ - if (!ps->smaps) { - sprintf(filename, "%d/smaps", pid); - fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC); - if (fd < 0) - continue; - ps->smaps = fdopen(fd, "re"); - if (!ps->smaps) { - close(fd); - continue; - } - setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf)); - } else { - rewind(ps->smaps); - } - - /* test to see if we need to skip another field */ - if (skip == 0) { - if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { - continue; - } - if (fread(buf, 1, 28 * 15, ps->smaps) != (28 * 15)) { - continue; - } - if (buf[392] == 'V') { - skip = 2; - } - else { - skip = 1; - } - rewind(ps->smaps); - } - - while (1) { - int pss_kb; - - /* skip one line, this contains the object mapped. */ - if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { - break; - } - /* then there's a 28 char 14 line block */ - if (fread(buf, 1, 28 * 14, ps->smaps) != 28 * 14) { - break; - } - pss_kb = atoi(&buf[61]); - ps->sample->pss += pss_kb; - - /* skip one more line if this is a newer kernel */ - if (skip == 2) { - if (fgets(buf, sizeof(buf), ps->smaps) == NULL) - break; - } - } - - if (ps->sample->pss > ps->pss_max) - ps->pss_max = ps->sample->pss; - -catch_rename: - /* catch process rename, try to randomize time */ - mod = (arg_hz < 4.0) ? 4.0 : (arg_hz / 4.0); - if (((sample - ps->pid) + pid) % (int)(mod) == 0) { - - /* re-fetch name */ - /* get name, start time */ - if (ps->sched < 0) { - sprintf(filename, "%d/sched", pid); - ps->sched = openat(procfd, filename, O_RDONLY|O_CLOEXEC); - if (ps->sched < 0) - continue; - } - - s = pread(ps->sched, buf, sizeof(buf) - 1, 0); - if (s <= 0) { - /* clean up file descriptors */ - ps->sched = safe_close(ps->sched); - ps->schedstat = safe_close(ps->schedstat); - continue; - } - - buf[s] = '\0'; - - if (!sscanf(buf, "%s %*s %*s", key)) - continue; - - strscpy(ps->name, sizeof(ps->name), key); - - /* cmdline */ - if (arg_show_cmdline) - pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid); - } - } - - return 0; -} diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c deleted file mode 100644 index f2af535061..0000000000 --- a/src/bootchart/svg.c +++ /dev/null @@ -1,1375 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - 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 <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <sys/utsname.h> -#include <time.h> -#include <unistd.h> - -#include "alloc-util.h" -#include "architecture.h" -#include "bootchart.h" -#include "fd-util.h" -#include "fileio.h" -#include "list.h" -#include "macro.h" -#include "stdio-util.h" -#include "store.h" -#include "svg.h" -#include "utf8.h" -#include "util.h" - -#define time_to_graph(t) ((t) * arg_scale_x) -#define ps_to_graph(n) ((n) * arg_scale_y) -#define kb_to_graph(m) ((m) * arg_scale_y * 0.0001) -#define to_color(n) (192.0 - ((n) * 192.0)) - -static const char * const colorwheel[12] = { - "rgb(255,32,32)", // red - "rgb(32,192,192)", // cyan - "rgb(255,128,32)", // orange - "rgb(128,32,192)", // blue-violet - "rgb(255,255,32)", // yellow - "rgb(192,32,128)", // red-violet - "rgb(32,255,32)", // green - "rgb(255,64,32)", // red-orange - "rgb(32,32,255)", // blue - "rgb(255,192,32)", // yellow-orange - "rgb(192,32,192)", // violet - "rgb(32,192,32)" // yellow-green -}; - -static double idletime = -1.0; -static int pfiltered = 0; -static int pcount = 0; -static int kcount = 0; -static double psize = 0; -static double ksize = 0; -static double esize = 0; -static struct list_sample_data *sampledata; -static struct list_sample_data *prev_sampledata; - -static void svg_header(FILE *of, struct list_sample_data *head, double graph_start, int n_cpus) { - double w; - double h; - struct list_sample_data *sampledata_last; - - assert(head); - - sampledata_last = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - sampledata_last = sampledata; - } - - /* min width is about 1600px due to the label */ - w = 150.0 + 10.0 + time_to_graph(sampledata_last->sampletime - graph_start); - w = ((w < 1600.0) ? 1600.0 : w); - - /* height is variable based on pss, psize, ksize */ - h = 400.0 + (arg_scale_y * 30.0) /* base graphs and title */ - + (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */ - + psize + ksize + esize + (n_cpus * 15 * arg_scale_y); - - fprintf(of, "<?xml version=\"1.0\" standalone=\"no\"?>\n"); - fprintf(of, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "); - fprintf(of, "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"); - - //fprintf(of, "<g transform=\"translate(10,%d)\">\n", 1000 + 150 + (pcount * 20)); - fprintf(of, "<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" ", w, h); - fprintf(of, "xmlns=\"http://www.w3.org/2000/svg\">\n\n"); - - /* write some basic info as a comment, including some help */ - fprintf(of, "<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n"); - fprintf(of, "<!-- such as Chrome, Chromium, or Firefox. Other applications that -->\n"); - fprintf(of, "<!-- render these files properly but more slowly are ImageMagick, gimp, -->\n"); - fprintf(of, "<!-- inkscape, etc. To display the files on your system, just point -->\n"); - fprintf(of, "<!-- your browser to file:///run/log/ and click. This bootchart was -->\n\n"); - - fprintf(of, "<!-- generated by bootchart version %s, running with options: -->\n", VERSION); - fprintf(of, "<!-- hz=\"%f\" n=\"%d\" -->\n", arg_hz, arg_samples_len); - fprintf(of, "<!-- x=\"%f\" y=\"%f\" -->\n", arg_scale_x, arg_scale_y); - fprintf(of, "<!-- rel=\"%d\" f=\"%d\" -->\n", arg_relative, arg_filter); - fprintf(of, "<!-- p=\"%d\" e=\"%d\" -->\n", arg_pss, arg_entropy); - fprintf(of, "<!-- o=\"%s\" i=\"%s\" -->\n\n", arg_output_path, arg_init_path); - - /* style sheet */ - fprintf(of, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); - - fprintf(of, " rect { stroke-width: 1; }\n"); - fprintf(of, " rect.bg { fill: rgb(255,255,255); }\n"); - fprintf(of, " rect.cpu { fill: rgb(64,64,240); stroke-width: 0; fill-opacity: 0.7; }\n"); - fprintf(of, " rect.wait { fill: rgb(240,240,0); stroke-width: 0; fill-opacity: 0.7; }\n"); - fprintf(of, " rect.bi { fill: rgb(240,128,128); stroke-width: 0; fill-opacity: 0.7; }\n"); - fprintf(of, " rect.bo { fill: rgb(192,64,64); stroke-width: 0; fill-opacity: 0.7; }\n"); - fprintf(of, " rect.ps { fill: rgb(192,192,192); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n"); - fprintf(of, " rect.krnl { fill: rgb(240,240,0); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n"); - fprintf(of, " rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n"); - fprintf(of, " rect.clrw { stroke-width: 0; fill-opacity: 0.7;}\n"); - fprintf(of, " line { stroke: rgb(64,64,64); stroke-width: 1; }\n"); - fprintf(of, "// line.sec1 { }\n"); - fprintf(of, " line.sec5 { stroke-width: 2; }\n"); - fprintf(of, " line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n"); - fprintf(of, " line.dot { stroke-dasharray: 2 4; }\n"); - fprintf(of, " line.idle { stroke: rgb(64,64,64); stroke-dasharray: 10 6; stroke-opacity: 0.7; }\n"); - - fprintf(of, " .run { font-size: 8; font-style: italic; }\n"); - fprintf(of, " text { font-family: Verdana, Helvetica; font-size: 10; }\n"); - fprintf(of, " text.sec { font-size: 8; }\n"); - fprintf(of, " text.t1 { font-size: 24; }\n"); - fprintf(of, " text.t2 { font-size: 12; }\n"); - fprintf(of, " text.idle { font-size: 18; }\n"); - - fprintf(of, " ]]>\n </style>\n</defs>\n\n"); -} - -static int svg_title(FILE *of, const char *build, int pscount, double log_start, int overrun) { - _cleanup_free_ char *cmdline = NULL; - _cleanup_free_ char *model = NULL; - _cleanup_free_ char *buf = NULL; - char date[256] = "Unknown"; - const char *cpu; - char *c; - time_t t; - int r; - struct utsname uts; - - r = read_one_line_file("/proc/cmdline", &cmdline); - if (r < 0) { - log_error_errno(r, "Unable to read cmdline: %m"); - return r; - } - - /* extract root fs so we can find disk model name in sysfs */ - /* FIXME: this works only in the simple case */ - c = strstr(cmdline, "root=/dev/"); - if (c) { - char rootbdev[4]; - char filename[32]; - - strncpy(rootbdev, &c[10], sizeof(rootbdev) - 1); - rootbdev[3] = '\0'; - xsprintf(filename, "/sys/block/%s/device/model", rootbdev); - - r = read_one_line_file(filename, &model); - if (r < 0) - log_info("Error reading disk model for %s: %m\n", rootbdev); - } - - /* various utsname parameters */ - r = uname(&uts); - if (r < 0) { - log_error("Error getting uname info\n"); - return -errno; - } - - /* date */ - t = time(NULL); - r = strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); - assert_se(r > 0); - - /* CPU type */ - r = get_proc_field("/proc/cpuinfo", PROC_CPUINFO_MODEL, "\n", &buf); - if (r < 0) - cpu = "Unknown"; - else - cpu = buf; - - fprintf(of, "<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n", - uts.nodename, date); - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n", - uts.sysname, uts.release, uts.version, uts.machine); - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n", cpu); - if (model) - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n", model); - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n", cmdline); - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n", build); - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start); - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"140\">Idle time: "); - - if (idletime >= 0.0) - fprintf(of, "%.03fs", idletime); - else - fprintf(of, "Not detected"); - - fprintf(of, "</text>\n"); - fprintf(of, "<text class=\"sec\" x=\"20\" y=\"155\">Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered</text>\n", - arg_hz, arg_samples_len, overrun, pscount, pfiltered); - - return 0; -} - -static void svg_graph_box(FILE *of, struct list_sample_data *head, int height, double graph_start) { - double d = 0.0; - int i = 0; - double finalsample = 0.0; - struct list_sample_data *sampledata_last; - - sampledata_last = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - sampledata_last = sampledata; - } - - finalsample = sampledata_last->sampletime; - - /* outside box, fill */ - fprintf(of, "<rect class=\"box\" x=\"%.03f\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(0.0), - time_to_graph(finalsample - graph_start), - ps_to_graph(height)); - - for (d = graph_start; d <= finalsample; - d += (arg_scale_x < 2.0 ? 60.0 : arg_scale_x < 10.0 ? 1.0 : 0.1)) { - /* lines for each second */ - if (i % 50 == 0) - fprintf(of, " <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n", - time_to_graph(d - graph_start), - time_to_graph(d - graph_start), - ps_to_graph(height)); - else if (i % 10 == 0) - fprintf(of, " <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n", - time_to_graph(d - graph_start), - time_to_graph(d - graph_start), - ps_to_graph(height)); - else - fprintf(of, " <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n", - time_to_graph(d - graph_start), - time_to_graph(d - graph_start), - ps_to_graph(height)); - - /* time label */ - if (i % 10 == 0) - fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n", - time_to_graph(d - graph_start), - -5.0, d - graph_start); - - i++; - } -} - -/* xml comments must not contain "--" */ -static char* xml_comment_encode(const char* name) { - char *enc_name, *p; - - enc_name = strdup(name); - if (!enc_name) - return NULL; - - for (p = enc_name; *p; p++) - if (p[0] == '-' && p[1] == '-') - p[1] = '_'; - - return enc_name; -} - -static void svg_pss_graph(FILE *of, - struct list_sample_data *head, - struct ps_struct *ps_first, - double graph_start) { - struct ps_struct *ps; - int i; - struct list_sample_data *sampledata_last; - - sampledata_last = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - sampledata_last = sampledata; - } - - - fprintf(of, "\n\n<!-- Pss memory size graph -->\n"); - - fprintf(of, "\n <text class=\"t2\" x=\"5\" y=\"-15\">Memory allocation - Pss</text>\n"); - - /* vsize 1000 == 1000mb */ - svg_graph_box(of, head, 100, graph_start); - /* draw some hlines for usable memory sizes */ - for (i = 100000; i < 1000000; i += 100000) { - fprintf(of, " <line class=\"sec01\" x1=\"%.03f\" y1=\"%.0f\" x2=\"%.03f\" y2=\"%.0f\"/>\n", - time_to_graph(.0), - kb_to_graph(i), - time_to_graph(sampledata_last->sampletime - graph_start), - kb_to_graph(i)); - fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.0f\">%dM</text>\n", - time_to_graph(sampledata_last->sampletime - graph_start) + 5, - kb_to_graph(i), (1000000 - i) / 1000); - } - fprintf(of, "\n"); - - /* now plot the graph itself */ - i = 1; - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int bottom; - int top; - struct ps_sched_struct *cross_place; - - bottom = 0; - top = 0; - - /* put all the small pss blocks into the bottom */ - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - if (!ps) - continue; - ps->sample = ps->first; - while (ps->sample->next) { - ps->sample = ps->sample->next; - if (ps->sample->sampledata == sampledata) - break; - } - if (ps->sample->sampledata == sampledata) { - if (ps->sample->pss <= (100 * arg_scale_y)) - top += ps->sample->pss; - break; - } - } - while (ps->sample->cross) { - cross_place = ps->sample->cross; - ps = ps->sample->cross->ps_new; - ps->sample = cross_place; - if (ps->sample->pss <= (100 * arg_scale_y)) - top += ps->sample->pss; - } - - fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - "rgb(64,64,64)", - time_to_graph(prev_sampledata->sampletime - graph_start), - kb_to_graph(1000000.0 - top), - time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), - kb_to_graph(top - bottom)); - bottom = top; - - /* now plot the ones that are of significant size */ - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - if (!ps) - continue; - ps->sample = ps->first; - while (ps->sample->next) { - ps->sample = ps->sample->next; - if (ps->sample->sampledata == sampledata) - break; - } - /* don't draw anything smaller than 2mb */ - if (ps->sample->sampledata != sampledata) - continue; - if (ps->sample->pss > (100 * arg_scale_y)) { - top = bottom + ps->sample->pss; - fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - colorwheel[ps->pid % 12], - time_to_graph(prev_sampledata->sampletime - graph_start), - kb_to_graph(1000000.0 - top), - time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), - kb_to_graph(top - bottom)); - bottom = top; - } - break; - } - - while ((cross_place = ps->sample->cross)) { - ps = ps->sample->cross->ps_new; - ps->sample = cross_place; - if (ps->sample->pss > (100 * arg_scale_y)) { - top = bottom + ps->sample->pss; - fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - colorwheel[ps->pid % 12], - time_to_graph(prev_sampledata->sampletime - graph_start), - kb_to_graph(1000000.0 - top), - time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), - kb_to_graph(top - bottom)); - bottom = top; - } - } - - prev_sampledata = sampledata; - i++; - } - - /* overlay all the text labels */ - i = 1; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int bottom; - int top = 0; - struct ps_sched_struct *prev_sample; - struct ps_sched_struct *cross_place; - - /* put all the small pss blocks into the bottom */ - ps = ps_first->next_ps; - while (ps->next_ps) { - ps = ps->next_ps; - if (!ps) - continue; - - ps->sample = ps->first; - while (ps->sample->next) { - ps->sample = ps->sample->next; - if (ps->sample->sampledata == sampledata) - break; - } - - if (ps->sample->sampledata == sampledata) { - if (ps->sample->pss <= (100 * arg_scale_y)) - top += ps->sample->pss; - - break; - } - } - - while ((cross_place = ps->sample->cross)) { - ps = ps->sample->cross->ps_new; - ps->sample = cross_place; - if (ps->sample->pss <= (100 * arg_scale_y)) - top += ps->sample->pss; - } - bottom = top; - - /* now plot the ones that are of significant size */ - ps = ps_first; - while (ps->next_ps) { - prev_sample = ps->sample; - ps = ps->next_ps; - if (!ps) - continue; - ps->sample = ps->first; - while (ps->sample->next) { - prev_sample = ps->sample; - ps->sample = ps->sample->next; - if (ps->sample->sampledata == sampledata) - break; - } - /* don't draw anything smaller than 2mb */ - if (ps->sample->sampledata == sampledata) { - if (ps->sample->pss > (100 * arg_scale_y)) { - top = bottom + ps->sample->pss; - /* draw a label with the process / PID */ - if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y))) - fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n", - time_to_graph(sampledata->sampletime - graph_start), - kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)), - ps->name, ps->pid); - bottom = top; - } - break; - } - } - while ((cross_place = ps->sample->cross)) { - ps = ps->sample->cross->ps_new; - ps->sample = cross_place; - prev_sample = ps->sample->prev; - if (ps->sample->pss > (100 * arg_scale_y)) { - top = bottom + ps->sample->pss; - /* draw a label with the process / PID */ - if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y))) - fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n", - time_to_graph(sampledata->sampletime - graph_start), - kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)), - ps->name, ps->pid); - bottom = top; - } - } - - i++; - } - - /* debug output - full data dump */ - fprintf(of, "\n\n<!-- PSS map - csv format -->\n"); - ps = ps_first; - while (ps->next_ps) { - _cleanup_free_ char *enc_name = NULL; - ps = ps->next_ps; - if (!ps) - continue; - - enc_name = xml_comment_encode(ps->name); - if (!enc_name) - continue; - - fprintf(of, "<!-- %s [%d] pss=", enc_name, ps->pid); - - ps->sample = ps->first; - while (ps->sample->next) { - ps->sample = ps->sample->next; - fprintf(of, "%d," , ps->sample->pss); - } - - fprintf(of, " -->\n"); - } - -} - -static void svg_io_bi_bar(FILE *of, - struct list_sample_data *head, - int n_samples, - double graph_start, - double interval) { - - double max = 0.0; - double range; - int max_here = 0; - int i; - int k; - struct list_sample_data *start_sampledata; - struct list_sample_data *stop_sampledata; - - fprintf(of, "<!-- IO utilization graph - In -->\n"); - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - read</text>\n"); - - /* - * calculate rounding range - * - * We need to round IO data since IO block data is not updated on - * each poll. Applying a smoothing function loses some burst data, - * so keep the smoothing range short. - */ - range = 0.25 / (1.0 / arg_hz); - if (range < 2.0) - range = 2.0; /* no smoothing */ - - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* find the max IO first */ - i = 1; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int start; - int stop; - int diff; - double tot; - - start = MAX(i - ((range / 2) - 1), 0); - stop = MIN(i + (range / 2), n_samples - 1); - diff = (stop - start); - - start_sampledata = sampledata; - stop_sampledata = sampledata; - - for (k = 0; k < ((range/2) - 1) && start_sampledata->link_next; k++) - start_sampledata = start_sampledata->link_next; - - for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++) - stop_sampledata = stop_sampledata->link_prev; - - tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff; - - if (tot > max) { - max = tot; - max_here = i; - } - - tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff; - - if (tot > max) - max = tot; - - i++; - } - - /* plot bi */ - i = 1; - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int start; - int stop; - int diff; - double tot; - double pbi = 0; - - start = MAX(i - ((range / 2) - 1), 0); - stop = MIN(i + (range / 2), n_samples); - diff = (stop - start); - - start_sampledata = sampledata; - stop_sampledata = sampledata; - - for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++) - start_sampledata = start_sampledata->link_next; - - for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++) - stop_sampledata = stop_sampledata->link_prev; - - tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff; - - if (max > 0) - pbi = tot / max; - - if (pbi > 0.001) - fprintf(of, "<rect class=\"bi\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(prev_sampledata->sampletime - graph_start), - (arg_scale_y * 5) - (pbi * (arg_scale_y * 5)), - time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), - pbi * (arg_scale_y * 5)); - - /* labels around highest value */ - if (i == max_here) - fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n", - time_to_graph(sampledata->sampletime - graph_start) + 5, - ((arg_scale_y * 5) - (pbi * (arg_scale_y * 5))) + 15, - max / 1024.0 / (interval / 1000000000.0)); - - i++; - prev_sampledata = sampledata; - } -} - -static void svg_io_bo_bar(FILE *of, - struct list_sample_data *head, - int n_samples, - double graph_start, - double interval) { - double max = 0.0; - double range; - int max_here = 0; - int i; - int k; - struct list_sample_data *start_sampledata; - struct list_sample_data *stop_sampledata; - - fprintf(of, "<!-- IO utilization graph - out -->\n"); - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - write</text>\n"); - - /* - * calculate rounding range - * - * We need to round IO data since IO block data is not updated on - * each poll. Applying a smoothing function loses some burst data, - * so keep the smoothing range short. - */ - range = 0.25 / (1.0 / arg_hz); - if (range < 2.0) - range = 2.0; /* no smoothing */ - - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* find the max IO first */ - i = 0; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int start; - int stop; - int diff; - double tot; - - start = MAX(i - ((range / 2) - 1), 0); - stop = MIN(i + (range / 2), n_samples - 1); - diff = (stop - start); - - start_sampledata = sampledata; - stop_sampledata = sampledata; - - for (k = 0; k < (range/2) - 1 && start_sampledata->link_next; k++) - start_sampledata = start_sampledata->link_next; - - for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++) - stop_sampledata = stop_sampledata->link_prev; - - tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff; - if (tot > max) - max = tot; - - tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff; - if (tot > max) { - max = tot; - max_here = i; - } - - i++; - } - - /* plot bo */ - prev_sampledata = head; - i = 1; - - LIST_FOREACH_BEFORE(link, sampledata, head) { - int start, stop, diff; - double tot, pbo; - - pbo = 0; - - start = MAX(i - ((range / 2) - 1), 0); - stop = MIN(i + (range / 2), n_samples); - diff = (stop - start); - - start_sampledata = sampledata; - stop_sampledata = sampledata; - - for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++) - start_sampledata = start_sampledata->link_next; - - for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++) - stop_sampledata = stop_sampledata->link_prev; - - tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) - / diff; - - if (max > 0) - pbo = tot / max; - - if (pbo > 0.001) - fprintf(of, "<rect class=\"bo\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(prev_sampledata->sampletime - graph_start), - (arg_scale_y * 5) - (pbo * (arg_scale_y * 5)), - time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), - pbo * (arg_scale_y * 5)); - - /* labels around highest bo value */ - if (i == max_here) - fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n", - time_to_graph(sampledata->sampletime - graph_start) + 5, - ((arg_scale_y * 5) - (pbo * (arg_scale_y * 5))), - max / 1024.0 / (interval / 1000000000.0)); - - i++; - prev_sampledata = sampledata; - } -} - -static void svg_cpu_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) { - - fprintf(of, "<!-- CPU utilization graph -->\n"); - - if (cpu_num < 0) - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] utilization</text>\n"); - else - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] utilization</text>\n", cpu_num); - - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* bars for each sample, proportional to the CPU util. */ - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int c; - double trt; - double ptrt; - - ptrt = trt = 0.0; - - if (cpu_num < 0) - for (c = 0; c < n_cpus; c++) - trt += sampledata->runtime[c] - prev_sampledata->runtime[c]; - else - trt = sampledata->runtime[cpu_num] - prev_sampledata->runtime[cpu_num]; - - trt = trt / 1000000000.0; - - if (cpu_num < 0) - trt = trt / (double)n_cpus; - - if (trt > 0.0) - ptrt = trt / (sampledata->sampletime - prev_sampledata->sampletime); - - if (ptrt > 1.0) - ptrt = 1.0; - - if (ptrt > 0.001) - fprintf(of, "<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(prev_sampledata->sampletime - graph_start), - (arg_scale_y * 5) - (ptrt * (arg_scale_y * 5)), - time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), - ptrt * (arg_scale_y * 5)); - - prev_sampledata = sampledata; - } -} - -static void svg_wait_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) { - - fprintf(of, "<!-- Wait time aggregation box -->\n"); - - if (cpu_num < 0) - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] wait</text>\n"); - else - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] wait</text>\n", cpu_num); - - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* bars for each sample, proportional to the CPU util. */ - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int c; - double twt; - double ptwt; - - ptwt = twt = 0.0; - - if (cpu_num < 0) - for (c = 0; c < n_cpus; c++) - twt += sampledata->waittime[c] - prev_sampledata->waittime[c]; - else - twt = sampledata->waittime[cpu_num] - prev_sampledata->waittime[cpu_num]; - - twt = twt / 1000000000.0; - - if (cpu_num < 0) - twt = twt / (double)n_cpus; - - if (twt > 0.0) - ptwt = twt / (sampledata->sampletime - prev_sampledata->sampletime); - - if (ptwt > 1.0) - ptwt = 1.0; - - if (ptwt > 0.001) - fprintf(of, "<rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(prev_sampledata->sampletime - graph_start), - ((arg_scale_y * 5) - (ptwt * (arg_scale_y * 5))), - time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), - ptwt * (arg_scale_y * 5)); - - prev_sampledata = sampledata; - } -} - -static void svg_entropy_bar(FILE *of, struct list_sample_data *head, double graph_start) { - - fprintf(of, "<!-- entropy pool graph -->\n"); - - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Entropy pool size</text>\n"); - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* bars for each sample, scale 0-4096 */ - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - fprintf(of, "<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(prev_sampledata->sampletime - graph_start), - ((arg_scale_y * 5) - ((sampledata->entropy_avail / 4096.) * (arg_scale_y * 5))), - time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), - (sampledata->entropy_avail / 4096.) * (arg_scale_y * 5)); - prev_sampledata = sampledata; - } -} - -static struct ps_struct *get_next_ps(struct ps_struct *ps, struct ps_struct *ps_first) { - /* - * walk the list of processes and return the next one to be - * painted - */ - if (ps == ps_first) - return ps->next_ps; - - /* go deep */ - if (ps->children) - return ps->children; - - /* find siblings */ - if (ps->next) - return ps->next; - - /* go back for parent siblings */ - for (;;) { - if (ps->parent && ps->parent->next) - return ps->parent->next; - - ps = ps->parent; - if (!ps) - return ps; - } - - return NULL; -} - -static bool ps_filter(struct ps_struct *ps) { - if (!arg_filter) - return false; - - /* can't draw data when there is only 1 sample (need start + stop) */ - if (ps->first == ps->last) - return true; - - /* don't filter kthreadd */ - if (ps->pid == 2) - return false; - - /* drop stuff that doesn't use any real CPU time */ - if (ps->total <= 0.001) - return true; - - return 0; -} - -static void svg_do_initcall(FILE *of, struct list_sample_data *head, int count_only, double graph_start) { - _cleanup_pclose_ FILE *f = NULL; - double t; - char func[256]; - int ret; - int usecs; - - /* can't plot initcall when disabled or in relative mode */ - if (!arg_initcall || arg_relative) { - kcount = 0; - return; - } - - if (!count_only) { - fprintf(of, "<!-- initcall -->\n"); - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Kernel init threads</text>\n"); - /* surrounding box */ - svg_graph_box(of, head, kcount, graph_start); - } - - kcount = 0; - - /* - * Initcall graphing - parses dmesg buffer and displays kernel threads - * This somewhat uses the same methods and scaling to show processes - * but looks a lot simpler. It's overlaid entirely onto the PS graph - * when appropriate. - */ - - f = popen("dmesg", "r"); - if (!f) - return; - - while (!feof(f)) { - int c; - int z = 0; - char l[256]; - - if (fgets(l, sizeof(l) - 1, f) == NULL) - continue; - - c = sscanf(l, "[%lf] initcall %s %*s %d %*s %d %*s", - &t, func, &ret, &usecs); - if (c != 4) { - /* also parse initcalls done by module loading */ - c = sscanf(l, "[%lf] initcall %s %*s %*s %d %*s %d %*s", - &t, func, &ret, &usecs); - if (c != 4) - continue; - } - - /* chop the +0xXX/0xXX stuff */ - while(func[z] != '+') - z++; - func[z] = 0; - - if (count_only) { - /* filter out irrelevant stuff */ - if (usecs >= 1000) - kcount++; - continue; - } - - fprintf(of, "<!-- thread=\"%s\" time=\"%.3f\" elapsed=\"%d\" result=\"%d\" -->\n", - func, t, usecs, ret); - - if (usecs < 1000) - continue; - - /* rect */ - fprintf(of, " <rect class=\"krnl\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(t - (usecs / 1000000.0)), - ps_to_graph(kcount), - time_to_graph(usecs / 1000000.0), - ps_to_graph(1)); - - /* label */ - fprintf(of, " <text x=\"%.03f\" y=\"%.03f\">%s <tspan class=\"run\">%.03fs</tspan></text>\n", - time_to_graph(t - (usecs / 1000000.0)) + 5, - ps_to_graph(kcount) + 15, - func, usecs / 1000000.0); - - kcount++; - } -} - -static void svg_ps_bars(FILE *of, - struct list_sample_data *head, - int n_samples, - int n_cpus, - struct ps_struct *ps_first, - double graph_start, - double interval) { - - struct ps_struct *ps; - int i = 0; - int j = 0; - int pid; - double w = 0.0; - - fprintf(of, "<!-- Process graph -->\n"); - fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Processes</text>\n"); - - /* surrounding box */ - svg_graph_box(of, head, pcount, graph_start); - - /* pass 2 - ps boxes */ - ps = ps_first; - while ((ps = get_next_ps(ps, ps_first))) { - _cleanup_free_ char *enc_name = NULL, *escaped = NULL; - double endtime; - double starttime; - int t; - - if (!utf8_is_printable(ps->name, strlen(ps->name))) - escaped = utf8_escape_non_printable(ps->name); - - enc_name = xml_comment_encode(escaped ? escaped : ps->name); - if (!enc_name) - continue; - - /* leave some trace of what we actually filtered etc. */ - fprintf(of, "<!-- %s [%i] ppid=%i runtime=%.03fs -->\n", enc_name, ps->pid, - ps->ppid, ps->total); - - starttime = ps->first->sampledata->sampletime; - - if (!ps_filter(ps)) { - /* remember where _to_ our children need to draw a line */ - ps->pos_x = time_to_graph(starttime - graph_start); - ps->pos_y = ps_to_graph(j+1); /* bottom left corner */ - } else if (ps->parent){ - /* hook children to our parent coords instead */ - ps->pos_x = ps->parent->pos_x; - ps->pos_y = ps->parent->pos_y; - - /* if this is the last child, we might still need to draw a connecting line */ - if ((!ps->next) && (ps->parent)) - fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n", - ps->parent->pos_x, - ps_to_graph(j-1) + 10.0, /* whee, use the last value here */ - ps->parent->pos_x, - ps->parent->pos_y); - continue; - } - - endtime = ps->last->sampledata->sampletime; - fprintf(of, " <rect class=\"ps\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(starttime - graph_start), - ps_to_graph(j), - time_to_graph(ps->last->sampledata->sampletime - starttime), - ps_to_graph(1)); - - /* paint cpu load over these */ - ps->sample = ps->first; - t = 1; - while (ps->sample->next) { - double rt, prt; - double wt, wrt; - struct ps_sched_struct *prev; - - prev = ps->sample; - ps->sample = ps->sample->next; - - /* calculate over interval */ - rt = ps->sample->runtime - prev->runtime; - wt = ps->sample->waittime - prev->waittime; - - prt = (rt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime); - wrt = (wt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime); - - /* this can happen if timekeeping isn't accurate enough */ - if (prt > 1.0) - prt = 1.0; - if (wrt > 1.0) - wrt = 1.0; - - if ((prt < 0.1) && (wrt < 0.1)) /* =~ 26 (color threshold) */ - continue; - - fprintf(of, " <rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(prev->sampledata->sampletime - graph_start), - ps_to_graph(j), - time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime), - ps_to_graph(wrt)); - - /* draw cpu over wait - TODO figure out how/why run + wait > interval */ - fprintf(of, " <rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", - time_to_graph(prev->sampledata->sampletime - graph_start), - ps_to_graph(j + (1.0 - prt)), - time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime), - ps_to_graph(prt)); - t++; - } - - /* determine where to display the process name */ - if ((endtime - starttime) < 1.5) - /* too small to fit label inside the box */ - w = endtime; - else - w = starttime; - - /* text label of process name */ - fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan> %s</text>\n", - time_to_graph(w - graph_start) + 5.0, - ps_to_graph(j) + 14.0, - escaped ? escaped : ps->name, - ps->pid, - (ps->last->runtime - ps->first->runtime) / 1000000000.0, - arg_show_cgroup ? ps->cgroup : ""); - /* paint lines to the parent process */ - if (ps->parent) { - /* horizontal part */ - fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n", - time_to_graph(starttime - graph_start), - ps_to_graph(j) + 10.0, - ps->parent->pos_x, - ps_to_graph(j) + 10.0); - - /* one vertical line connecting all the horizontal ones up */ - if (!ps->next) - fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n", - ps->parent->pos_x, - ps_to_graph(j) + 10.0, - ps->parent->pos_x, - ps->parent->pos_y); - } - - j++; /* count boxes */ - - fprintf(of, "\n"); - } - - /* last pass - determine when idle */ - pid = getpid(); - /* make sure we start counting from the point where we actually have - * data: assume that bootchart's first sample is when data started - */ - - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - if (ps->pid == pid) - break; - } - - /* need to know last node first */ - ps->sample = ps->first; - i = ps->sample->next->sampledata->counter; - - while (ps->sample->next && i<(n_samples-(arg_hz/2))) { - double crt; - double brt; - int c; - int ii; - struct ps_sched_struct *sample_hz; - - ps->sample = ps->sample->next; - sample_hz = ps->sample; - for (ii = 0; (ii < (int)arg_hz/2) && sample_hz->next; ii++) - sample_hz = sample_hz->next; - - /* subtract bootchart cpu utilization from total */ - crt = 0.0; - for (c = 0; c < n_cpus; c++) - crt += sample_hz->sampledata->runtime[c] - ps->sample->sampledata->runtime[c]; - - brt = sample_hz->runtime - ps->sample->runtime; - /* - * our definition of "idle": - * - * if for (hz / 2) we've used less CPU than (interval / 2) ... - * defaults to 4.0%, which experimentally, is where atom idles - */ - if ((crt - brt) < (interval / 2.0)) { - idletime = ps->sample->sampledata->sampletime - graph_start; - fprintf(of, "\n<!-- idle detected at %.03f seconds -->\n", idletime); - fprintf(of, "<line class=\"idle\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n", - time_to_graph(idletime), - -arg_scale_y, - time_to_graph(idletime), - ps_to_graph(pcount) + arg_scale_y); - fprintf(of, "<text class=\"idle\" x=\"%.03f\" y=\"%.03f\">%.01fs</text>\n", - time_to_graph(idletime) + 5.0, - ps_to_graph(pcount) + arg_scale_y, - idletime); - break; - } - - i++; - } -} - -static void svg_top_ten_cpu(FILE *of, struct ps_struct *ps_first) { - struct ps_struct *top[10]; - struct ps_struct emptyps = {}; - struct ps_struct *ps; - int n, m; - - for (n = 0; n < (int) ELEMENTSOF(top); n++) - top[n] = &emptyps; - - /* walk all ps's and setup ptrs */ - ps = ps_first; - while ((ps = get_next_ps(ps, ps_first))) { - for (n = 0; n < 10; n++) { - if (ps->total <= top[n]->total) - continue; - /* cascade insert */ - for (m = 9; m > n; m--) - top[m] = top[m-1]; - top[n] = ps; - break; - } - } - - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"0\">Top CPU consumers:</text>\n"); - for (n = 0; n < 10; n++) - fprintf(of, "<text class=\"t3\" x=\"20\" y=\"%d\">%3.03fs - <![CDATA[%s]]> [%d]</text>\n", - 20 + (n * 13), - top[n]->total, - top[n]->name, - top[n]->pid); -} - -static void svg_top_ten_pss(FILE *of, struct ps_struct *ps_first) { - struct ps_struct *top[10]; - struct ps_struct emptyps = {}; - struct ps_struct *ps; - int n, m; - - for (n = 0; n < (int) ELEMENTSOF(top); n++) - top[n] = &emptyps; - - /* walk all ps's and setup ptrs */ - ps = ps_first; - while ((ps = get_next_ps(ps, ps_first))) { - for (n = 0; n < 10; n++) { - if (ps->pss_max <= top[n]->pss_max) - continue; - - /* cascade insert */ - for (m = 9; m > n; m--) - top[m] = top[m-1]; - top[n] = ps; - break; - } - } - - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"0\">Top PSS consumers:</text>\n"); - for (n = 0; n < 10; n++) - fprintf(of, "<text class=\"t3\" x=\"20\" y=\"%d\">%dK - <![CDATA[%s]]> [%d]</text>\n", - 20 + (n * 13), - top[n]->pss_max, - top[n]->name, - top[n]->pid); -} - -int svg_do(FILE *of, - const char *build, - struct list_sample_data *head, - struct ps_struct *ps_first, - int n_samples, - int pscount, - int n_cpus, - double graph_start, - double log_start, - double interval, - int overrun) { - - struct ps_struct *ps; - double offset = 7; - int r, c; - - sampledata = head; - LIST_FIND_TAIL(link, sampledata, head); - ps = ps_first; - - /* count initcall thread count first */ - svg_do_initcall(of, head, 1, graph_start); - ksize = kcount ? ps_to_graph(kcount) + (arg_scale_y * 2) : 0; - - /* then count processes */ - while ((ps = get_next_ps(ps, ps_first))) { - if (!ps_filter(ps)) - pcount++; - else - pfiltered++; - } - psize = ps_to_graph(pcount) + (arg_scale_y * 2); - - esize = (arg_entropy ? arg_scale_y * 7 : 0); - - /* after this, we can draw the header with proper sizing */ - svg_header(of, head, graph_start, arg_percpu ? n_cpus : 0); - fprintf(of, "<rect class=\"bg\" width=\"100%%\" height=\"100%%\" />\n\n"); - - fprintf(of, "<g transform=\"translate(10,400)\">\n"); - svg_io_bi_bar(of, head, n_samples, graph_start, interval); - fprintf(of, "</g>\n\n"); - - fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset)); - svg_io_bo_bar(of, head, n_samples, graph_start, interval); - fprintf(of, "</g>\n\n"); - - for (c = -1; c < (arg_percpu ? n_cpus : 0); c++) { - offset += 7; - fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset)); - svg_cpu_bar(of, head, n_cpus, c, graph_start); - fprintf(of, "</g>\n\n"); - - offset += 7; - fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset)); - svg_wait_bar(of, head, n_cpus, c, graph_start); - fprintf(of, "</g>\n\n"); - } - - if (kcount) { - offset += 7; - fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset)); - svg_do_initcall(of, head, 0, graph_start); - fprintf(of, "</g>\n\n"); - } - - offset += 7; - fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize); - svg_ps_bars(of, head, n_samples, n_cpus, ps_first, graph_start, interval); - fprintf(of, "</g>\n\n"); - - fprintf(of, "<g transform=\"translate(10, 0)\">\n"); - r = svg_title(of, build, pscount, log_start, overrun); - fprintf(of, "</g>\n\n"); - - if (r < 0) - return r; - - fprintf(of, "<g transform=\"translate(10,200)\">\n"); - svg_top_ten_cpu(of, ps_first); - fprintf(of, "</g>\n\n"); - - if (arg_entropy) { - fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize); - svg_entropy_bar(of, head, graph_start); - fprintf(of, "</g>\n\n"); - } - - if (arg_pss) { - fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize + esize); - svg_pss_graph(of, head, ps_first, graph_start); - fprintf(of, "</g>\n\n"); - - fprintf(of, "<g transform=\"translate(410,200)\">\n"); - svg_top_ten_pss(of, ps_first); - fprintf(of, "</g>\n\n"); - } - - /* fprintf footer */ - fprintf(of, "\n</svg>\n"); - - return 0; -} diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index b839fadd04..d6fb10cac5 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -184,7 +184,7 @@ int main(int argc, char *argv[]) { goto finish; if (!arg_no_pager) { - r = pager_open(false); + r = pager_open(arg_no_pager, false); if (r > 0 && arg_full < 0) arg_full = true; } diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 39235a95f6..9c34928052 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -765,7 +765,7 @@ int unit_set_cgroup_path(Unit *u, const char *path) { } int unit_watch_cgroup(Unit *u) { - _cleanup_free_ char *populated = NULL; + _cleanup_free_ char *events = NULL; int r; assert(u); @@ -791,11 +791,11 @@ int unit_watch_cgroup(Unit *u) { if (r < 0) return log_oom(); - r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.populated", &populated); + r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events", &events); if (r < 0) return log_oom(); - u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, populated, IN_MODIFY); + u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, events, IN_MODIFY); if (u->cgroup_inotify_wd < 0) { if (errno == ENOENT) /* If the directory is already diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index f939196397..00372b92b4 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -139,7 +139,7 @@ static int property_get_tainted( if (access("/proc/cgroups", F_OK) < 0) e = stpcpy(e, "cgroups-missing:"); - if (clock_is_localtime() > 0) + if (clock_is_localtime(NULL) > 0) e = stpcpy(e, "local-hwclock:"); /* remove the last ':' */ diff --git a/src/core/device.c b/src/core/device.c index d201dc5e4b..28e4039da2 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -318,7 +318,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa * the GC to have garbaged it. That's desired since the device * unit may have a dependency on the mount unit which was * added during the loading of the later. */ - if (u && DEVICE(u)->state == DEVICE_PLUGGED) { + if (dev && u && DEVICE(u)->state == DEVICE_PLUGGED) { /* This unit is in plugged state: we're sure it's * attached to a device. */ if (!path_equal(DEVICE(u)->sysfs, sysfs)) { diff --git a/src/core/execute.c b/src/core/execute.c index 184c72dbe7..ac2ac39892 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -24,6 +24,7 @@ #include <poll.h> #include <signal.h> #include <string.h> +#include <sys/capability.h> #include <sys/personality.h> #include <sys/prctl.h> #include <sys/socket.h> @@ -1824,6 +1825,11 @@ static int exec_child( if (params->apply_permissions) { + bool use_address_families = context->address_families_whitelist || + !set_isempty(context->address_families); + bool use_syscall_filter = context->syscall_whitelist || + !set_isempty(context->syscall_filter) || + !set_isempty(context->syscall_archs); int secure_bits = context->secure_bits; for (i = 0; i < _RLIMIT_MAX; i++) { @@ -1876,7 +1882,7 @@ static int exec_child( * also to the context secure_bits so that we don't try to * drop the bit away next. */ - secure_bits |= 1<<SECURE_KEEP_CAPS; + secure_bits |= 1<<SECURE_KEEP_CAPS; } } @@ -1890,15 +1896,15 @@ static int exec_child( return -errno; } - if (context->no_new_privileges) + if (context->no_new_privileges || + (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || use_syscall_filter))) if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { *exit_status = EXIT_NO_NEW_PRIVILEGES; return -errno; } #ifdef HAVE_SECCOMP - if (context->address_families_whitelist || - !set_isempty(context->address_families)) { + if (use_address_families) { r = apply_address_families(context); if (r < 0) { *exit_status = EXIT_ADDRESS_FAMILIES; @@ -1906,9 +1912,7 @@ static int exec_child( } } - if (context->syscall_whitelist || - !set_isempty(context->syscall_filter) || - !set_isempty(context->syscall_archs)) { + if (use_syscall_filter) { r = apply_seccomp(context); if (r < 0) { *exit_status = EXIT_SECCOMP; @@ -2237,7 +2241,7 @@ int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) { if (fn[0] == '-') { ignore = true; - fn ++; + fn++; } if (!path_is_absolute(fn)) { diff --git a/src/core/failure-action.c b/src/core/failure-action.c index 39f5519ca1..bb2bc3f399 100644 --- a/src/core/failure-action.c +++ b/src/core/failure-action.c @@ -62,7 +62,8 @@ int failure_action( log_and_status(m, "Rebooting as result of failure."); update_reboot_param_file(reboot_arg); - (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, NULL); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, + JOB_REPLACE_IRREVERSIBLY, NULL); break; @@ -89,7 +90,8 @@ int failure_action( case FAILURE_ACTION_POWEROFF: log_and_status(m, "Powering off as result of failure."); - (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, NULL); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, + JOB_REPLACE_IRREVERSIBLY, NULL); break; case FAILURE_ACTION_POWEROFF_FORCE: diff --git a/src/core/job.c b/src/core/job.c index 97304c4d05..5557a6a942 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -222,7 +222,7 @@ Job* job_install(Job *j) { *pj = j; j->installed = true; - j->manager->n_installed_jobs ++; + j->manager->n_installed_jobs++; log_unit_debug(j->unit, "Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); @@ -645,7 +645,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = { [JOB_DONE] = "Stopped %s.", [JOB_FAILED] = "Stopped (with error) %s.", - [JOB_TIMEOUT] = "Timed out stoppping %s.", + [JOB_TIMEOUT] = "Timed out stopping %s.", }; static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = { [JOB_DONE] = "Reloaded %s.", @@ -690,17 +690,20 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR } static void job_print_status_message(Unit *u, JobType t, JobResult result) { - static const char* const job_result_status_table[_JOB_RESULT_MAX] = { - [JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL, - [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL, - [JOB_FAILED] = ANSI_HIGHLIGHT_RED "FAILED" ANSI_NORMAL, - [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW "DEPEND" ANSI_NORMAL, - [JOB_SKIPPED] = ANSI_HIGHLIGHT " INFO " ANSI_NORMAL, - [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW "ASSERT" ANSI_NORMAL, - [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL, + static struct { + const char *color, *word; + } const statuses[_JOB_RESULT_MAX] = { + [JOB_DONE] = {ANSI_GREEN, " OK "}, + [JOB_TIMEOUT] = {ANSI_HIGHLIGHT_RED, " TIME "}, + [JOB_FAILED] = {ANSI_HIGHLIGHT_RED, "FAILED"}, + [JOB_DEPENDENCY] = {ANSI_HIGHLIGHT_YELLOW, "DEPEND"}, + [JOB_SKIPPED] = {ANSI_HIGHLIGHT, " INFO "}, + [JOB_ASSERT] = {ANSI_HIGHLIGHT_YELLOW, "ASSERT"}, + [JOB_UNSUPPORTED] = {ANSI_HIGHLIGHT_YELLOW, "UNSUPP"}, }; const char *format; + const char *status; assert(u); assert(t >= 0); @@ -714,11 +717,16 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { if (!format) return; + if (log_get_show_color()) + status = strjoina(statuses[result].color, statuses[result].word, ANSI_NORMAL); + else + status = statuses[result].word; + if (result != JOB_DONE) manager_flip_auto_status(u->manager, true); DISABLE_WARNING_FORMAT_NONLITERAL; - unit_status_printf(u, job_result_status_table[result], format); + unit_status_printf(u, status, format); REENABLE_WARNING; if (t == JOB_START && result == JOB_FAILED) { @@ -856,7 +864,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { } if (result == JOB_FAILED || result == JOB_INVALID) - j->manager->n_failed_jobs ++; + j->manager->n_failed_jobs++; job_uninstall(j); job_free(j); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 4a65d174b8..d078924c5b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -119,7 +119,7 @@ int config_parse_unit_deps( assert(rvalue); p = rvalue; - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL, *k = NULL; int r; @@ -620,7 +620,7 @@ int config_parse_exec( separate_argv0 = true; else break; - f ++; + f++; } if (isempty(f)) { @@ -668,7 +668,7 @@ int config_parse_exec( /* Check explicitly for an unquoted semicolon as * command separator token. */ if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) { - p ++; + p++; p += strspn(p, WHITESPACE); semicolon = true; break; @@ -1599,7 +1599,7 @@ int config_parse_service_sockets( assert(data); p = rvalue; - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL, *k = NULL; r = extract_first_word(&p, &word, NULL, 0); @@ -3361,7 +3361,7 @@ int config_parse_protect_home( ProtectHome h; h = protect_home_from_string(rvalue); - if (h < 0){ + if (h < 0) { log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue); return 0; } @@ -3404,7 +3404,7 @@ int config_parse_protect_system( ProtectSystem s; s = protect_system_from_string(rvalue); - if (s < 0){ + if (s < 0) { log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue); return 0; } @@ -3507,7 +3507,19 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { * ours? Then let's try it the other way * round */ - other = manager_get_unit((*u)->manager, k); + /* If the symlink name we are looking at is unit template, then + we must search for instance of this template */ + if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE)) { + _cleanup_free_ char *instance = NULL; + + r = unit_name_replace_instance(k, (*u)->instance, &instance); + if (r < 0) + return r; + + other = manager_get_unit((*u)->manager, instance); + } else + other = manager_get_unit((*u)->manager, k); + free(k); if (other) { diff --git a/src/core/main.c b/src/core/main.c index c725a686f1..56df32426a 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -102,7 +102,7 @@ static bool arg_crash_reboot = false; static bool arg_confirm_spawn = false; static ShowStatus arg_show_status = _SHOW_STATUS_UNSET; static bool arg_switched_root = false; -static int arg_no_pager = -1; +static bool arg_no_pager = false; static char ***arg_join_controllers = NULL; static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL; static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT; @@ -127,14 +127,6 @@ static bool arg_default_tasks_accounting = true; static uint64_t arg_default_tasks_max = UINT64_C(512); static sd_id128_t arg_machine_id = {}; -static void pager_open_if_enabled(void) { - - if (arg_no_pager <= 0) - return; - - pager_open(false); -} - noreturn static void freeze_or_reboot(void) { if (arg_crash_reboot) { @@ -883,8 +875,6 @@ static int parse_argv(int argc, char *argv[]) { case ARG_TEST: arg_action = ACTION_TEST; - if (arg_no_pager < 0) - arg_no_pager = true; break; case ARG_NO_PAGER: @@ -994,8 +984,6 @@ static int parse_argv(int argc, char *argv[]) { case 'h': arg_action = ACTION_HELP; - if (arg_no_pager < 0) - arg_no_pager = true; break; case 'D': @@ -1073,7 +1061,7 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching return log_error_errno(r, "Failed to create serialization file: %m"); /* Make sure nothing is really destructed when we shut down */ - m->n_reloading ++; + m->n_reloading++; bus_manager_send_reloading(m, true); fds = fdset_new(); @@ -1230,10 +1218,15 @@ static int status_welcome(void) { if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read os-release file: %m"); - return status_printf(NULL, false, false, - "\nWelcome to \x1B[%sm%s\x1B[0m!\n", - isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); + if (log_get_show_color()) + return status_printf(NULL, false, false, + "\nWelcome to \x1B[%sm%s\x1B[0m!\n", + isempty(ansi_color) ? "1" : ansi_color, + isempty(pretty_name) ? "Linux" : pretty_name); + else + return status_printf(NULL, false, false, + "\nWelcome to %s!\n", + isempty(pretty_name) ? "Linux" : pretty_name); } static int write_container_id(void) { @@ -1381,13 +1374,13 @@ int main(int argc, char *argv[]) { dual_timestamp_get(&security_finish_timestamp); } - if (mac_selinux_init(NULL) < 0) { + if (mac_selinux_init() < 0) { error_message = "Failed to initialize SELinux policy"; goto finish; } if (!skip_setup) { - if (clock_is_localtime() > 0) { + if (clock_is_localtime(NULL) > 0) { int min; /* @@ -1447,9 +1440,7 @@ int main(int argc, char *argv[]) { /* clear the kernel timestamp, * because we are in a container */ - kernel_timestamp.monotonic = 0ULL; - kernel_timestamp.realtime = 0ULL; - + kernel_timestamp = DUAL_TIMESTAMP_NULL; } else { /* Running as user instance */ arg_running_as = MANAGER_USER; @@ -1548,7 +1539,8 @@ int main(int argc, char *argv[]) { if (arg_action == ACTION_TEST) skip_setup = true; - pager_open_if_enabled(); + if (arg_action == ACTION_TEST || arg_action == ACTION_HELP) + pager_open(arg_no_pager, false); if (arg_action == ACTION_HELP) { retval = help(); @@ -1672,7 +1664,7 @@ int main(int argc, char *argv[]) { test_usr(); } - if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0) + if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY) watchdog_set_timeout(&arg_runtime_watchdog); if (arg_timer_slack_nsec != NSEC_INFINITY) @@ -2103,7 +2095,7 @@ finish: assert(pos < ELEMENTSOF(command_line)); - if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) { + if (arm_reboot_watchdog && arg_shutdown_watchdog > 0 && arg_shutdown_watchdog != USEC_INFINITY) { char *e; /* If we reboot let's set the shutdown diff --git a/src/core/manager.c b/src/core/manager.c index f36cf5e320..e739795e70 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1137,7 +1137,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { * this is already known, so we increase the counter here * already */ if (serialization) - m->n_reloading ++; + m->n_reloading++; /* First, enumerate what we can from all config files */ dual_timestamp_get(&m->units_load_start_timestamp); @@ -1171,7 +1171,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { if (serialization) { assert(m->n_reloading > 0); - m->n_reloading --; + m->n_reloading--; /* Let's wait for the UnitNew/JobNew messages being * sent, before we notify that the reload is @@ -1333,8 +1333,12 @@ int manager_load_unit_prepare( t = unit_name_to_type(name); - if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { + if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is missing the instance name.", name); + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); + } ret = manager_get_unit(m, name); if (ret) { @@ -1631,7 +1635,9 @@ static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) { log_unit_debug(u, "Child "PID_FMT" belongs to %s", si->si_pid, u->id); unit_unwatch_pid(u, si->si_pid); - UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); + + if (UNIT_VTABLE(u)->sigchld_event) + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); } static int manager_dispatch_sigchld(Manager *m) { @@ -2016,7 +2022,7 @@ int manager_loop(Manager *m) { while (m->exit_code == MANAGER_OK) { usec_t wait_usec; - if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM) + if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM) watchdog_ping(); if (!ratelimit_test(&rl)) { @@ -2041,7 +2047,7 @@ int manager_loop(Manager *m) { continue; /* Sleep for half the watchdog time */ - if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM) { + if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM) { wait_usec = m->runtime_watchdog / 2; if (wait_usec <= 0) wait_usec = 1; @@ -2231,7 +2237,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { assert(f); assert(fds); - m->n_reloading ++; + m->n_reloading++; fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id); fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr)); @@ -2301,13 +2307,13 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { r = unit_serialize(u, f, fds, !switching_root); if (r < 0) { - m->n_reloading --; + m->n_reloading--; return r; } } assert(m->n_reloading > 0); - m->n_reloading --; + m->n_reloading--; if (ferror(f)) return -EIO; @@ -2327,7 +2333,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { log_debug("Deserializing state..."); - m->n_reloading ++; + m->n_reloading++; for (;;) { char line[LINE_MAX], *l; @@ -2495,7 +2501,7 @@ finish: r = -EIO; assert(m->n_reloading > 0); - m->n_reloading --; + m->n_reloading--; return r; } @@ -2511,23 +2517,23 @@ int manager_reload(Manager *m) { if (r < 0) return r; - m->n_reloading ++; + m->n_reloading++; bus_manager_send_reloading(m, true); fds = fdset_new(); if (!fds) { - m->n_reloading --; + m->n_reloading--; return -ENOMEM; } r = manager_serialize(m, f, fds, false); if (r < 0) { - m->n_reloading --; + m->n_reloading--; return r; } if (fseeko(f, 0, SEEK_SET) < 0) { - m->n_reloading --; + m->n_reloading--; return -errno; } diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index de1a361cc4..32fe51c67e 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -94,7 +94,7 @@ static const MountPoint mount_table[] = { #endif { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, NULL, MNT_FATAL|MNT_IN_CONTAINER }, - { "cgroup", "/sys/fs/cgroup", "cgroup", "__DEVEL__sane_behavior", MS_NOSUID|MS_NOEXEC|MS_NODEV, + { "cgroup", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, cg_is_unified_wanted, MNT_FATAL|MNT_IN_CONTAINER }, { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER }, diff --git a/src/core/mount.c b/src/core/mount.c index 93d2bd595c..0fd880df5d 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -104,6 +104,14 @@ static bool mount_is_auto(const MountParameters *p) { return !fstab_test_option(p->options, "noauto\0"); } +static bool mount_is_automount(const MountParameters *p) { + assert(p); + + return fstab_test_option(p->options, + "comment=systemd.automount\0" + "x-systemd.automount\0"); +} + static bool needs_quota(const MountParameters *p) { assert(p); @@ -328,7 +336,8 @@ static int mount_add_device_links(Mount *m) { if (path_equal(m->where, "/")) return 0; - if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM) + if (mount_is_auto(p) && !mount_is_automount(p) && + UNIT(m)->manager->running_as == MANAGER_SYSTEM) device_wants_mount = true; r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES); @@ -369,7 +378,8 @@ static bool should_umount(Mount *m) { MountParameters *p; if (path_equal(m->where, "/") || - path_equal(m->where, "/usr")) + path_equal(m->where, "/usr") || + path_startswith(m->where, "/run/initramfs")) return false; p = get_mount_parameters(m); @@ -393,13 +403,15 @@ static int mount_add_default_dependencies(Mount *m) { if (UNIT(m)->manager->running_as != MANAGER_SYSTEM) return 0; - /* We do not add any default dependencies to / and /usr, since - * they are guaranteed to stay mounted the whole time, since - * our system is on it. Also, don't bother with anything - * mounted below virtual file systems, it's also going to be - * virtual, and hence not worth the effort. */ + /* We do not add any default dependencies to /, /usr or + * /run/initramfs/, since they are guaranteed to stay + * mounted the whole time, since our system is on it. + * Also, don't bother with anything mounted below virtual + * file systems, it's also going to be virtual, and hence + * not worth the effort. */ if (path_equal(m->where, "/") || path_equal(m->where, "/usr") || + path_startswith(m->where, "/run/initramfs") || path_startswith(m->where, "/proc") || path_startswith(m->where, "/sys") || path_startswith(m->where, "/dev")) diff --git a/src/core/scope.c b/src/core/scope.c index c5d0ecef04..361695c3f9 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -50,8 +50,7 @@ static void scope_init(Unit *u) { assert(u->load_state == UNIT_STUB); s->timeout_stop_usec = u->manager->default_timeout_stop_usec; - - UNIT(s)->ignore_on_isolate = true; + u->ignore_on_isolate = true; } static void scope_done(Unit *u) { diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index 9a115a4387..4072df58e6 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -88,7 +88,7 @@ int mac_selinux_setup(bool *loaded_policy) { log_open(); log_error("Failed to compute init label, ignoring."); } else { - r = setcon(label); + r = setcon_raw(label); log_open(); if (r < 0) diff --git a/src/core/service.c b/src/core/service.c index 1f6d821db3..5d58b0b752 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -942,7 +942,7 @@ static void service_set_state(Service *s, ServiceState state) { if (ec && exec_context_may_touch_console(ec)) { Manager *m = UNIT(s)->manager; - m->n_on_console --; + m->n_on_console--; if (m->n_on_console == 0) /* unset no_console_output flag, since the console is free */ m->no_console_output = false; diff --git a/src/core/slice.c b/src/core/slice.c index d65364c6f4..667f61bde5 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -34,6 +34,13 @@ static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = { [SLICE_ACTIVE] = UNIT_ACTIVE }; +static void slice_init(Unit *u) { + assert(u); + assert(u->load_state == UNIT_STUB); + + u->ignore_on_isolate = true; +} + static void slice_set_state(Slice *t, SliceState state) { SliceState old_state; assert(t); @@ -305,6 +312,7 @@ const UnitVTable slice_vtable = { .no_instances = true, .can_transient = true, + .init = slice_init, .load = slice_load, .coldplug = slice_coldplug, diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index 0c26e85460..5a6d11cfa1 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -261,7 +261,7 @@ static int write_netlabel_rules(const char* srcdir) { } } - return r; + return r; } #endif diff --git a/src/core/socket.c b/src/core/socket.c index a1cb54d77a..dd515a17a5 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1341,8 +1341,12 @@ static int socket_open_fds(Socket *s) { break; case SOCKET_USB_FUNCTION: + { + _cleanup_free_ char *ep = NULL; - p->fd = usbffs_address_create(p->path); + ep = path_make_absolute("ep0", p->path); + + p->fd = usbffs_address_create(ep); if (p->fd < 0) { r = p->fd; goto rollback; @@ -1357,7 +1361,7 @@ static int socket_open_fds(Socket *s) { goto rollback; break; - + } default: assert_not_reached("Unknown port type"); } @@ -1979,7 +1983,7 @@ static void socket_enter_running(Socket *s, int cfd) { service = SERVICE(UNIT_DEREF(s->service)); unit_ref_unset(&s->service); - s->n_accepted ++; + s->n_accepted++; UNIT(service)->no_gc = false; @@ -1990,7 +1994,7 @@ static void socket_enter_running(Socket *s, int cfd) { goto fail; cfd = -1; - s->n_connections ++; + s->n_connections++; r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL); if (r < 0) diff --git a/src/core/transaction.c b/src/core/transaction.c index b28fc76785..c894001cf9 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -391,6 +391,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi if (delete) { + const char *status; /* logging for j not k here here to provide consistent narrative */ log_unit_warning(j->unit, "Breaking ordering cycle by deleting job %s/%s", @@ -399,7 +400,13 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi "Job %s/%s deleted to break ordering cycle starting with %s/%s", delete->unit->id, job_type_to_string(delete->type), j->unit->id, job_type_to_string(j->type)); - unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL, + + if (log_get_show_color()) + status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL; + else + status = " SKIP "; + + unit_status_printf(delete->unit, status, "Ordering cycle found, skipping %s"); transaction_delete_unit(tr, delete->unit); return -EAGAIN; diff --git a/src/core/umount.c b/src/core/umount.c index a458768e7d..c21a2be54e 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -412,6 +412,7 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e #ifndef HAVE_SPLIT_USR || path_equal(m->path, "/usr") #endif + || path_startswith(m->path, "/run/initramfs") ) continue; @@ -472,7 +473,7 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) { major(root_st.st_dev) != 0 && lstat(m->path, &loopback_st) >= 0 && root_st.st_dev == loopback_st.st_rdev) { - n_failed ++; + n_failed++; continue; } @@ -507,7 +508,7 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) { if (k >= 0 && major(root_st.st_dev) != 0 && root_st.st_dev == m->devnum) { - n_failed ++; + n_failed++; continue; } diff --git a/src/core/unit.c b/src/core/unit.c index 3c4f85e744..af38beb0c3 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -364,7 +364,7 @@ void unit_add_to_gc_queue(Unit *u) { LIST_PREPEND(gc_queue, u->manager->gc_queue, u); u->in_gc_queue = true; - u->manager->n_in_gc_queue ++; + u->manager->n_in_gc_queue++; } void unit_add_to_dbus_queue(Unit *u) { @@ -1864,13 +1864,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su ec = unit_get_exec_context(u); if (ec && exec_context_may_touch_console(ec)) { if (UNIT_IS_INACTIVE_OR_FAILED(ns)) { - m->n_on_console --; + m->n_on_console--; if (m->n_on_console == 0) /* unset no_console_output flag, since the console is free */ m->no_console_output = false; } else - m->n_on_console ++; + m->n_on_console++; } } diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 0034a1a0ac..dac800ebef 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -54,7 +54,7 @@ static enum { } arg_action = ACTION_LIST; static const char* arg_field = NULL; static const char *arg_directory = NULL; -static int arg_no_pager = false; +static bool arg_no_pager = false; static int arg_no_legend = false; static int arg_one = false; static FILE* arg_output = NULL; @@ -852,9 +852,7 @@ int main(int argc, char *argv[]) { case ACTION_LIST: case ACTION_INFO: - if (!arg_no_pager) - pager_open(false); - + pager_open(arg_no_pager, false); r = dump_list(j); break; diff --git a/src/coredump/stacktrace.c b/src/coredump/stacktrace.c index 68806992fc..cc4dad9465 100644 --- a/src/coredump/stacktrace.c +++ b/src/coredump/stacktrace.c @@ -91,7 +91,7 @@ static int frame_callback(Dwfl_Frame *frame, void *userdata) { } fprintf(c->f, "#%-2u 0x%016" PRIx64 " %s (%s)\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname)); - c->n_frame ++; + c->n_frame++; return DWARF_CB_OK; } @@ -117,7 +117,7 @@ static int thread_callback(Dwfl_Thread *thread, void *userdata) { if (dwfl_thread_getframes(thread, frame_callback, c) < 0) return DWARF_CB_ABORT; - c->n_thread ++; + c->n_thread++; return DWARF_CB_OK; } diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 2ef966257a..9927621ea0 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -719,8 +719,12 @@ int main(int argc, char *argv[]) { int k; k = crypt_init_by_name(&cd, argv[2]); - if (k) { - log_error_errno(k, "crypt_init() failed: %m"); + if (k == -ENODEV) { + log_info("Volume %s already inactive.", argv[2]); + r = EXIT_SUCCESS; + goto finish; + } else if (k) { + log_error_errno(k, "crypt_init_by_name() failed: %m"); goto finish; } diff --git a/src/delta/delta.c b/src/delta/delta.c index a54fc89de6..b4f0ecff2d 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -85,14 +85,6 @@ static enum { (SHOW_MASKED | SHOW_EQUIVALENT | SHOW_REDIRECTED | SHOW_OVERRIDDEN | SHOW_EXTENDED) } arg_flags = 0; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static int equivalent(const char *a, const char *b) { _cleanup_free_ char *x = NULL, *y = NULL; @@ -431,7 +423,7 @@ finish: hashmap_free_free(top); hashmap_free_free(bottom); - HASHMAP_FOREACH_KEY(h, key, drops, i){ + HASHMAP_FOREACH_KEY(h, key, drops, i) { hashmap_free_free(hashmap_remove(drops, key)); hashmap_remove(drops, key); free(key); @@ -610,7 +602,7 @@ int main(int argc, char *argv[]) { else if (arg_diff) arg_flags |= SHOW_OVERRIDDEN; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (optind < argc) { int i; diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 7790ab865d..435e3805c4 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -245,7 +245,7 @@ static int process_locale(void) { int r; etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf"); - if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_localeconf, F_OK) >= 0) return 0; if (arg_copy_locale && arg_root) { @@ -319,7 +319,7 @@ static int process_timezone(void) { int r; etc_localtime = prefix_roota(arg_root, "/etc/localtime"); - if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_localtime, F_OK) >= 0) return 0; if (arg_copy_timezone && arg_root) { @@ -399,7 +399,7 @@ static int process_hostname(void) { int r; etc_hostname = prefix_roota(arg_root, "/etc/hostname"); - if (faccessat(AT_FDCWD, etc_hostname, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_hostname, F_OK) >= 0) return 0; r = prompt_hostname(); @@ -424,7 +424,7 @@ static int process_machine_id(void) { int r; etc_machine_id = prefix_roota(arg_root, "/etc/machine-id"); - if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_machine_id, F_OK) >= 0) return 0; if (sd_id128_equal(arg_machine_id, SD_ID128_NULL)) @@ -450,7 +450,7 @@ static int prompt_root_password(void) { return 0; etc_shadow = prefix_roota(arg_root, "/etc/shadow"); - if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_shadow, F_OK) >= 0) return 0; print_welcome(); @@ -533,7 +533,7 @@ static int process_root_password(void) { int r; etc_shadow = prefix_roota(arg_root, "/etc/shadow"); - if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_shadow, F_OK) >= 0) return 0; mkdir_parents(etc_shadow, 0755); diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 97a48764ae..6f576b5ecf 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -336,8 +336,8 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to write unit file %s: %m", unit); - if (!noauto) { - lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL); + if (!noauto && !automount) { + lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", name, NULL); if (!lnk) return log_oom(); diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index c37e32e96b..d11756e615 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -706,7 +706,7 @@ int main(int argc, char *argv[]) { log_open(); umask(0022); - mac_selinux_init("/etc"); + mac_selinux_init(); if (argc != 1) { log_error("This program takes no arguments."); diff --git a/src/import/import-common.c b/src/import/import-common.c index 18a30be36d..287a3382a1 100644 --- a/src/import/import-common.c +++ b/src/import/import-common.c @@ -136,7 +136,7 @@ int import_fork_tar_x(const char *path, pid_t *ret) { if (r < 0) log_error_errno(r, "Failed to drop capabilities, ignoring: %m"); - execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL); + execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL); log_error_errno(errno, "Failed to execute tar: %m"); _exit(EXIT_FAILURE); } @@ -210,7 +210,7 @@ int import_fork_tar_c(const char *path, pid_t *ret) { if (r < 0) log_error_errno(r, "Failed to drop capabilities, ignoring: %m"); - execlp("tar", "tar", "-C", path, "-c", ".", NULL); + execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL); log_error_errno(errno, "Failed to execute tar: %m"); _exit(EXIT_FAILURE); } diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 8a16602c3e..8993402821 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -355,10 +355,12 @@ static int raw_pull_make_local_copy(RawPull *i) { r = copy_file_atomic(i->settings_path, local_settings, 0644, i->force_local, 0); if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); - else if (r < 0 && r != -ENOENT) + else if (r == -ENOENT) + log_debug_errno(r, "Skipping creation of settings file, since none was found."); + else if (r < 0) log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings); else - log_info("Created new settings file '%s.nspawn'", i->local); + log_info("Created new settings file %s.", local_settings); } return 0; diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index afb13366f0..8c61c46f73 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -251,10 +251,12 @@ static int tar_pull_make_local_copy(TarPull *i) { r = copy_file_atomic(i->settings_path, local_settings, 0664, i->force_local, 0); if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); - else if (r < 0 && r != -ENOENT) + else if (r == -ENOENT) + log_debug_errno(r, "Skipping creation of settings file, since none was found."); + else if (r < 0) log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings); else - log_info("Created new settings file '%s.nspawn'", i->local); + log_info("Created new settings file %s.", local_settings); } return 0; diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index 3e57afb997..41b2237d16 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -314,7 +314,7 @@ static int server_init(Server *s, unsigned n_sockets) { f->fd = fd; LIST_PREPEND(fifo, s->fifos, f); f->server = s; - s->n_fifos ++; + s->n_fifos++; } r = bus_connect_system_systemd(&s->bus); diff --git a/src/journal-remote/browse.html b/src/journal-remote/browse.html index 3594f70c87..32848c7673 100644 --- a/src/journal-remote/browse.html +++ b/src/journal-remote/browse.html @@ -391,7 +391,7 @@ entry = document.getElementById("tableentry"); var buf = ""; - for (var key in d){ + for (var key in d) { var data = d[key]; if (data == null) diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h index 0b8b6af736..1740a21f92 100644 --- a/src/journal-remote/journal-remote-parse.h +++ b/src/journal-remote/journal-remote-parse.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "sd-event.h" #include "journal-remote-write.h" diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c index 5fab74e5cc..7bba52566e 100644 --- a/src/journal-remote/journal-remote-write.c +++ b/src/journal-remote/journal-remote-write.c @@ -54,7 +54,7 @@ void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) { **********************************************************************/ static int do_rotate(JournalFile **f, bool compress, bool seal) { - int r = journal_file_rotate(f, compress, seal); + int r = journal_file_rotate(f, compress, seal, NULL); if (r < 0) { if (*f) log_error_errno(r, "Failed to rotate %s: %m", (*f)->path); diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h index 6b645a353c..53ba45fc04 100644 --- a/src/journal-remote/journal-remote-write.h +++ b/src/journal-remote/journal-remote-write.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - - #include "journal-file.h" typedef struct RemoteServer RemoteServer; diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index 3ce6fe27b3..35a1e55f9e 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -203,7 +203,7 @@ static int open_output(Writer *w, const char* host) { O_RDWR|O_CREAT, 0640, arg_compress, arg_seal, &w->metrics, - w->mmap, + w->mmap, NULL, NULL, &w->journal); if (r < 0) log_error_errno(r, "Failed to open output journal %s: %m", @@ -434,7 +434,7 @@ static int add_raw_socket(RemoteServer *s, int fd) { return r; fd_ = -1; - s->active ++; + s->active++; return 0; } @@ -742,7 +742,7 @@ static int setup_microhttpd_server(RemoteServer *s, goto error; } - s->active ++; + s->active++; return 0; error: diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h index 6466a1c101..30ad7df996 100644 --- a/src/journal-remote/journal-remote.h +++ b/src/journal-remote/journal-remote.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - - #include "sd-event.h" #include "hashmap.h" diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index fc8f63c9e3..e61b6bc68f 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -52,7 +52,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { /* not enough space */ return pos; - u->entry_state ++; + u->entry_state++; if (pos + r == size) { /* exactly one character short, but we don't need it */ @@ -76,7 +76,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { /* not enough space */ return pos; - u->entry_state ++; + u->entry_state++; if (r + pos == size) { /* exactly one character short, but we don't need it */ @@ -101,7 +101,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { /* not enough space */ return pos; - u->entry_state ++; + u->entry_state++; if (r + pos == size) { /* exactly one character short, but we don't need it */ @@ -126,7 +126,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { /* not enough space */ return pos; - u->entry_state ++; + u->entry_state++; if (r + pos == size) { /* exactly one character short, but we don't need it */ @@ -156,7 +156,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { continue; } - u->entry_state ++; + u->entry_state++; } /* fall through */ case ENTRY_TEXT_FIELD: @@ -206,7 +206,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { pos += len + 1; u->field_pos = len + 1; - u->entry_state ++; + u->entry_state++; } /* fall through */ case ENTRY_BINARY_FIELD_SIZE: { @@ -220,7 +220,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { memcpy(buf + pos, &le64, 8); pos += 8; - u->entry_state ++; + u->entry_state++; continue; } @@ -230,8 +230,8 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { return pos; buf[pos++] = '\n'; - u->entry_state ++; - u->entries_sent ++; + u->entry_state++; + u->entries_sent++; return pos; diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 440563e7d3..6e1c3bb9ef 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -75,7 +75,7 @@ static void close_fd_input(Uploader *u); curl_easy_strerror(code)); \ cmd; \ } \ - } while(0) + } while (0) static size_t output_callback(char *buf, size_t size, diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h index 70c4d29c0f..ea160f212b 100644 --- a/src/journal-remote/microhttpd-util.h +++ b/src/journal-remote/microhttpd-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <microhttpd.h> #include <stdarg.h> diff --git a/src/journal/catalog.c b/src/journal/catalog.c index 164a3a15f2..886f6efd8b 100644 --- a/src/journal/catalog.c +++ b/src/journal/catalog.c @@ -164,14 +164,14 @@ static int finish_item( Hashmap *h, sd_id128_t id, const char *language, - char *payload) { + char *payload, size_t payload_size) { _cleanup_free_ CatalogItem *i = NULL; - _cleanup_free_ char *combined = NULL, *prev = NULL; - int r; + _cleanup_free_ char *prev = NULL, *combined = NULL; assert(h); assert(payload); + assert(payload_size > 0); i = new0(CatalogItem, 1); if (!i) @@ -184,23 +184,25 @@ static int finish_item( } prev = hashmap_get(h, i); - - /* Already have such an item, combine them */ if (prev) { + /* Already have such an item, combine them */ combined = combine_entries(payload, prev); if (!combined) return log_oom(); - r = hashmap_update(h, i, combined); - if (r < 0) - return r; - combined = NULL; - /* A new item */ + if (hashmap_update(h, i, combined) < 0) + return log_oom(); + combined = NULL; } else { - r = hashmap_put(h, i, payload); - if (r < 0) - return r; + /* A new item */ + combined = memdup(payload, payload_size + 1); + if (!combined) + return log_oom(); + + if (hashmap_put(h, i, combined) < 0) + return log_oom(); i = NULL; + combined = NULL; } return 0; @@ -215,7 +217,7 @@ int catalog_file_lang(const char* filename, char **lang) { beg = end - 1; while (beg > filename && *beg != '.' && *beg != '/' && end - beg < 32) - beg --; + beg--; if (*beg != '.' || end <= beg + 1) return 0; @@ -262,6 +264,7 @@ static int catalog_entry_lang(const char* filename, int line, int catalog_import_file(Hashmap *h, const char *path) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *payload = NULL; + size_t payload_size = 0, payload_allocated = 0; unsigned n = 0; sd_id128_t id; _cleanup_free_ char *deflang = NULL, *lang = NULL; @@ -283,8 +286,7 @@ int catalog_import_file(Hashmap *h, const char *path) { for (;;) { char line[LINE_MAX]; - size_t a, b, c; - char *t; + size_t line_len; if (!fgets(line, sizeof(line), f)) { if (feof(f)) @@ -323,17 +325,23 @@ int catalog_import_file(Hashmap *h, const char *path) { if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) { if (got_id) { - r = finish_item(h, id, lang ?: deflang, payload); + if (payload_size == 0) { + log_error("[%s:%u] No payload text.", path, n); + return -EINVAL; + } + + r = finish_item(h, id, lang ?: deflang, payload, payload_size); if (r < 0) return r; - payload = NULL; lang = mfree(lang); + payload_size = 0; } if (with_language) { - t = strstrip(line + 2 + 1 + 32 + 1); + char *t; + t = strstrip(line + 2 + 1 + 32 + 1); r = catalog_entry_lang(path, n, t, deflang, &lang); if (r < 0) return r; @@ -343,9 +351,6 @@ int catalog_import_file(Hashmap *h, const char *path) { empty_line = false; id = jd; - if (payload) - payload[0] = '\0'; - continue; } } @@ -356,34 +361,30 @@ int catalog_import_file(Hashmap *h, const char *path) { return -EINVAL; } - a = payload ? strlen(payload) : 0; - b = strlen(line); - - c = a + (empty_line ? 1 : 0) + b + 1 + 1; - t = realloc(payload, c); - if (!t) + line_len = strlen(line); + if (!GREEDY_REALLOC(payload, payload_allocated, + payload_size + (empty_line ? 1 : 0) + line_len + 1 + 1)) return log_oom(); - if (empty_line) { - t[a] = '\n'; - memcpy(t + a + 1, line, b); - t[a+b+1] = '\n'; - t[a+b+2] = 0; - } else { - memcpy(t + a, line, b); - t[a+b] = '\n'; - t[a+b+1] = 0; - } + if (empty_line) + payload[payload_size++] = '\n'; + memcpy(payload + payload_size, line, line_len); + payload_size += line_len; + payload[payload_size++] = '\n'; + payload[payload_size] = '\0'; - payload = t; empty_line = false; } if (got_id) { - r = finish_item(h, id, lang ?: deflang, payload); + if (payload_size == 0) { + log_error("[%s:%u] No payload text.", path, n); + return -EINVAL; + } + + r = finish_item(h, id, lang ?: deflang, payload, payload_size); if (r < 0) return r; - payload = NULL; } return 0; diff --git a/src/journal/compress.c b/src/journal/compress.c index 1933b87b00..c43849c46a 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -17,6 +17,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> @@ -498,7 +499,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { total_out += n; if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { - log_debug("Compressed stream longer than %zd bytes", max_bytes); + log_debug("Compressed stream longer than %"PRIu64" bytes", max_bytes); return -EFBIG; } @@ -649,7 +650,7 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) { total_out += produced; if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { - log_debug("Decompressed stream longer than %zd bytes", max_bytes); + log_debug("Decompressed stream longer than %"PRIu64" bytes", max_bytes); r = -EFBIG; goto cleanup; } diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 994d1ec5d8..bed825cdc3 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -20,6 +20,7 @@ #include <errno.h> #include <fcntl.h> #include <linux/fs.h> +#include <pthread.h> #include <stddef.h> #include <sys/mman.h> #include <sys/statvfs.h> @@ -38,6 +39,7 @@ #include "parse-util.h" #include "random-util.h" #include "sd-event.h" +#include "set.h" #include "string-util.h" #include "xattr-util.h" @@ -86,33 +88,127 @@ /* The mmap context to use for the header we pick as one above the last defined typed */ #define CONTEXT_HEADER _OBJECT_TYPE_MAX -static int journal_file_set_online(JournalFile *f) { +/* This may be called from a separate thread to prevent blocking the caller for the duration of fsync(). + * As a result we use atomic operations on f->offline_state for inter-thread communications with + * journal_file_set_offline() and journal_file_set_online(). */ +static void journal_file_set_offline_internal(JournalFile *f) { assert(f); + assert(f->fd >= 0); + assert(f->header); - if (!f->writable) - return -EPERM; + for (;;) { + switch (f->offline_state) { + case OFFLINE_CANCEL: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_CANCEL, OFFLINE_DONE)) + continue; + return; - if (!(f->fd >= 0 && f->header)) - return -EINVAL; + case OFFLINE_AGAIN_FROM_SYNCING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_SYNCING, OFFLINE_SYNCING)) + continue; + break; + + case OFFLINE_AGAIN_FROM_OFFLINING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_OFFLINING, OFFLINE_SYNCING)) + continue; + break; + + case OFFLINE_SYNCING: + (void) fsync(f->fd); + + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_OFFLINING)) + continue; + + f->header->state = STATE_OFFLINE; + (void) fsync(f->fd); + break; + + case OFFLINE_OFFLINING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_OFFLINING, OFFLINE_DONE)) + continue; + /* fall through */ + + case OFFLINE_DONE: + return; + + case OFFLINE_JOINED: + log_debug("OFFLINE_JOINED unexpected offline state for journal_file_set_offline_internal()"); + return; + } + } +} + +static void * journal_file_set_offline_thread(void *arg) { + JournalFile *f = arg; + + journal_file_set_offline_internal(f); + + return NULL; +} + +static int journal_file_set_offline_thread_join(JournalFile *f) { + int r; + + assert(f); + + if (f->offline_state == OFFLINE_JOINED) + return 0; + + r = pthread_join(f->offline_thread, NULL); + if (r) + return -r; + + f->offline_state = OFFLINE_JOINED; if (mmap_cache_got_sigbus(f->mmap, f->fd)) return -EIO; - switch (f->header->state) { - case STATE_ONLINE: - return 0; + return 0; +} - case STATE_OFFLINE: - f->header->state = STATE_ONLINE; - fsync(f->fd); - return 0; +/* Trigger a restart if the offline thread is mid-flight in a restartable state. */ +static bool journal_file_set_offline_try_restart(JournalFile *f) { + for (;;) { + switch (f->offline_state) { + case OFFLINE_AGAIN_FROM_SYNCING: + case OFFLINE_AGAIN_FROM_OFFLINING: + return true; + + case OFFLINE_CANCEL: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_CANCEL, OFFLINE_AGAIN_FROM_SYNCING)) + continue; + return true; + + case OFFLINE_SYNCING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_AGAIN_FROM_SYNCING)) + continue; + return true; + + case OFFLINE_OFFLINING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_OFFLINING, OFFLINE_AGAIN_FROM_OFFLINING)) + continue; + return true; default: - return -EINVAL; + return false; + } } } -int journal_file_set_offline(JournalFile *f) { +/* Sets a journal offline. + * + * If wait is false then an offline is dispatched in a separate thread for a + * subsequent journal_file_set_offline() or journal_file_set_online() of the + * same journal to synchronize with. + * + * If wait is true, then either an existing offline thread will be restarted + * and joined, or if none exists the offline is simply performed in this + * context without involving another thread. + */ +int journal_file_set_offline(JournalFile *f, bool wait) { + bool restarted; + int r; + assert(f); if (!f->writable) @@ -124,19 +220,109 @@ int journal_file_set_offline(JournalFile *f) { if (f->header->state != STATE_ONLINE) return 0; - fsync(f->fd); + /* Restart an in-flight offline thread and wait if needed, or join a lingering done one. */ + restarted = journal_file_set_offline_try_restart(f); + if ((restarted && wait) || !restarted) { + r = journal_file_set_offline_thread_join(f); + if (r < 0) + return r; + } - if (mmap_cache_got_sigbus(f->mmap, f->fd)) - return -EIO; + if (restarted) + return 0; + + /* Initiate a new offline. */ + f->offline_state = OFFLINE_SYNCING; + + if (wait) /* Without using a thread if waiting. */ + journal_file_set_offline_internal(f); + else { + r = pthread_create(&f->offline_thread, NULL, journal_file_set_offline_thread, f); + if (r > 0) { + f->offline_state = OFFLINE_JOINED; + return -r; + } + } + + return 0; +} + +static int journal_file_set_online(JournalFile *f) { + bool joined = false; - f->header->state = STATE_OFFLINE; + assert(f); + + if (!f->writable) + return -EPERM; + + if (!(f->fd >= 0 && f->header)) + return -EINVAL; + + while (!joined) { + switch (f->offline_state) { + case OFFLINE_JOINED: + /* No offline thread, no need to wait. */ + joined = true; + break; + + case OFFLINE_SYNCING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_CANCEL)) + continue; + /* Canceled syncing prior to offlining, no need to wait. */ + break; + + case OFFLINE_AGAIN_FROM_SYNCING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_SYNCING, OFFLINE_CANCEL)) + continue; + /* Canceled restart from syncing, no need to wait. */ + break; + + case OFFLINE_AGAIN_FROM_OFFLINING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_OFFLINING, OFFLINE_CANCEL)) + continue; + /* Canceled restart from offlining, must wait for offlining to complete however. */ + + /* fall through to wait */ + default: { + int r; + + r = journal_file_set_offline_thread_join(f); + if (r < 0) + return r; + + joined = true; + break; + } + } + } if (mmap_cache_got_sigbus(f->mmap, f->fd)) return -EIO; - fsync(f->fd); + switch (f->header->state) { + case STATE_ONLINE: + return 0; - return 0; + case STATE_OFFLINE: + f->header->state = STATE_ONLINE; + (void) fsync(f->fd); + return 0; + + default: + return -EINVAL; + } +} + +bool journal_file_is_offlining(JournalFile *f) { + assert(f); + + __sync_synchronize(); + + if (f->offline_state == OFFLINE_DONE || + f->offline_state == OFFLINE_JOINED) + return false; + + return true; } JournalFile* journal_file_close(JournalFile *f) { @@ -159,7 +345,7 @@ JournalFile* journal_file_close(JournalFile *f) { sd_event_source_unref(f->post_change_timer); } - journal_file_set_offline(f); + journal_file_set_offline(f, true); if (f->mmap && f->fd >= 0) mmap_cache_close_fd(f->mmap, f->fd); @@ -203,6 +389,15 @@ JournalFile* journal_file_close(JournalFile *f) { return NULL; } +void journal_file_close_set(Set *s) { + JournalFile *f; + + assert(s); + + while ((f = set_steal_first(s))) + (void) journal_file_close(f); +} + static int journal_file_init_header(JournalFile *f, JournalFile *template) { Header h = {}; ssize_t k; @@ -263,7 +458,7 @@ static int journal_file_refresh_header(JournalFile *f) { r = journal_file_set_online(f); /* Sync the online state to disk */ - fsync(f->fd); + (void) fsync(f->fd); return r; } @@ -1977,7 +2172,7 @@ static int generic_array_bisect_plus_one( goto found; if (r > 0 && idx) - (*idx) ++; + (*idx)++; return r; @@ -2710,6 +2905,7 @@ int journal_file_open( bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, + Set *deferred_closes, JournalFile *template, JournalFile **ret) { @@ -2829,6 +3025,9 @@ int journal_file_open( f->header = h; if (!newly_created) { + if (deferred_closes) + journal_file_close_set(deferred_closes); + r = journal_file_verify_header(f); if (r < 0) goto fail; @@ -2898,12 +3097,12 @@ fail: if (f->fd >= 0 && mmap_cache_got_sigbus(f->mmap, f->fd)) r = -EIO; - journal_file_close(f); + (void) journal_file_close(f); return r; } -int journal_file_rotate(JournalFile **f, bool compress, bool seal) { +int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred_closes) { _cleanup_free_ char *p = NULL; size_t l; JournalFile *old_file, *new_file = NULL; @@ -2943,8 +3142,13 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) { * we archive them */ old_file->defrag_on_close = true; - r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file); - journal_file_close(old_file); + r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, deferred_closes, old_file, &new_file); + + if (deferred_closes && + set_put(deferred_closes, old_file) >= 0) + (void) journal_file_set_offline(old_file, false); + else + (void) journal_file_close(old_file); *f = new_file; return r; @@ -2958,6 +3162,7 @@ int journal_file_open_reliably( bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, + Set *deferred_closes, JournalFile *template, JournalFile **ret) { @@ -2965,7 +3170,7 @@ int journal_file_open_reliably( size_t l; _cleanup_free_ char *p = NULL; - r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret); + r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret); if (!IN_SET(r, -EBADMSG, /* corrupted */ -ENODATA, /* truncated */ @@ -3006,7 +3211,7 @@ int journal_file_open_reliably( log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname); - return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret); + return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret); } int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) { diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 07b9561b8a..9ad6013359 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -63,6 +63,16 @@ typedef enum LocationType { LOCATION_SEEK } LocationType; +typedef enum OfflineState { + OFFLINE_JOINED, + OFFLINE_SYNCING, + OFFLINE_OFFLINING, + OFFLINE_CANCEL, + OFFLINE_AGAIN_FROM_SYNCING, + OFFLINE_AGAIN_FROM_OFFLINING, + OFFLINE_DONE +} OfflineState; + typedef struct JournalFile { int fd; @@ -105,6 +115,9 @@ typedef struct JournalFile { OrderedHashmap *chain_cache; + pthread_t offline_thread; + volatile OfflineState offline_state; + #if defined(HAVE_XZ) || defined(HAVE_LZ4) void *compress_buffer; size_t compress_buffer_size; @@ -136,11 +149,14 @@ int journal_file_open( bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, + Set *deferred_closes, JournalFile *template, JournalFile **ret); -int journal_file_set_offline(JournalFile *f); +int journal_file_set_offline(JournalFile *f, bool wait); +bool journal_file_is_offlining(JournalFile *f); JournalFile* journal_file_close(JournalFile *j); +void journal_file_close_set(Set *s); int journal_file_open_reliably( const char *fname, @@ -150,6 +166,7 @@ int journal_file_open_reliably( bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, + Set *deferred_closes, JournalFile *template, JournalFile **ret); @@ -223,7 +240,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 void journal_file_dump(JournalFile *f); void journal_file_print_header(JournalFile *f); -int journal_file_rotate(JournalFile **f, bool compress, bool seal); +int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred_closes); void journal_file_post_change(JournalFile *f); int journal_file_enable_post_change_timer(JournalFile *f, sd_event *e, usec_t t); diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index c7d670f4ff..a79846146a 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -50,7 +50,7 @@ *_f = alloca(_fl + 10); \ memcpy(*_f, "CODE_FUNC=", 10); \ memcpy(*_f + 10, _func, _fl); \ - } while(false) + } while (false) /* We open a single fd, and we'll share it with the current process, * all its threads, and all its subprocesses. This means we need to diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c index 05e97620ae..f09dc66e03 100644 --- a/src/journal/journal-vacuum.c +++ b/src/journal/journal-vacuum.c @@ -239,13 +239,13 @@ int journal_directory_vacuum( /* Vacuum corrupted files */ if (q < 1 + 16 + 1 + 16 + 8 + 1) { - n_active_files ++; + n_active_files++; continue; } if (de->d_name[q-1-8-16-1] != '-' || de->d_name[q-1-8-16-1-16-1] != '@') { - n_active_files ++; + n_active_files++; continue; } @@ -256,7 +256,7 @@ int journal_directory_vacuum( } if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { - n_active_files ++; + n_active_files++; continue; } @@ -302,7 +302,7 @@ int journal_directory_vacuum( list[n_list].realtime = realtime; list[n_list].seqnum_id = seqnum_id; list[n_list].have_seqnum = have_seqnum; - n_list ++; + n_list++; p = NULL; sum += size; diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index b968e89bb8..a1241c9bcf 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -97,20 +97,20 @@ static void flush_progress(void) { fflush(stdout); } -#define debug(_offset, _fmt, ...) do{ \ +#define debug(_offset, _fmt, ...) do { \ flush_progress(); \ log_debug(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \ - } while(0) + } while (0) -#define warning(_offset, _fmt, ...) do{ \ +#define warning(_offset, _fmt, ...) do { \ flush_progress(); \ log_warning(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \ - } while(0) + } while (0) -#define error(_offset, _fmt, ...) do{ \ +#define error(_offset, _fmt, ...) do { \ flush_progress(); \ log_error(OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \ - } while(0) + } while (0) static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) { uint64_t i; @@ -894,7 +894,7 @@ int journal_file_verify( goto fail; } - n_objects ++; + n_objects++; r = journal_file_object_verify(f, p, o); if (r < 0) { @@ -991,7 +991,7 @@ int journal_file_verify( entry_realtime = le64toh(o->entry.realtime); entry_realtime_set = true; - n_entries ++; + n_entries++; break; case OBJECT_DATA_HASH_TABLE: @@ -1131,11 +1131,11 @@ int journal_file_verify( last_epoch = le64toh(o->tag.epoch); - n_tags ++; + n_tags++; break; default: - n_weird ++; + n_weird++; } if (p == le64toh(f->header->tail_object_offset)) { diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 273242bea6..fd2cb99410 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -225,14 +225,6 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) { return 0; } -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(arg_pager_end); -} - static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) { if (arg_utc) @@ -278,7 +270,7 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset static void help(void) { - pager_open_if_enabled(); + pager_open(arg_no_pager, arg_pager_end); printf("%s [OPTIONS...] [MATCHES...]\n\n" "Query the journal.\n\n" @@ -1183,7 +1175,7 @@ static int list_boots(sd_journal *j) { if (count == 0) return count; - pager_open_if_enabled(); + pager_open(arg_no_pager, arg_pager_end); /* numbers are one less, but we need an extra char for the sign */ w = DECIMAL_STR_WIDTH(count - 1) + 1; @@ -1363,7 +1355,7 @@ static int add_units(sd_journal *j) { r = sd_journal_add_disjunction(j); if (r < 0) return r; - count ++; + count++; } } @@ -1383,7 +1375,7 @@ static int add_units(sd_journal *j) { r = sd_journal_add_disjunction(j); if (r < 0) return r; - count ++; + count++; } } @@ -1408,7 +1400,7 @@ static int add_units(sd_journal *j) { r = sd_journal_add_disjunction(j); if (r < 0) return r; - count ++; + count++; } } @@ -1428,7 +1420,7 @@ static int add_units(sd_journal *j) { r = sd_journal_add_disjunction(j); if (r < 0) return r; - count ++; + count++; } } @@ -2061,7 +2053,7 @@ int main(int argc, char *argv[]) { } else { bool oneline = arg_action == ACTION_LIST_CATALOG; - pager_open_if_enabled(); + pager_open(arg_no_pager, arg_pager_end); if (optind < argc) r = catalog_list_items(stdout, database, oneline, argv + optind); @@ -2181,7 +2173,7 @@ int main(int argc, char *argv[]) { SD_JOURNAL_FOREACH_FIELD(j, field) { printf("%s\n", field); - n_shown ++; + n_shown++; } r = 0; @@ -2273,7 +2265,7 @@ int main(int argc, char *argv[]) { else printf("%.*s\n", (int) size, (const char*) data); - n_shown ++; + n_shown++; } r = 0; @@ -2368,7 +2360,7 @@ int main(int argc, char *argv[]) { } if (!arg_follow) - pager_open_if_enabled(); + pager_open(arg_no_pager, arg_pager_end); if (!arg_quiet) { usec_t start, end; diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index b2eb8a33ef..a433c91c54 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -63,7 +63,7 @@ static int map_simple_field(const char *field, const char **p, struct iovec **io (*iov)[*n_iov].iov_base = c; (*iov)[*n_iov].iov_len = l; - (*n_iov) ++; + (*n_iov)++; *p = e; c = NULL; @@ -142,7 +142,7 @@ static int map_string_field_internal(const char *field, const char **p, struct i (*iov)[*n_iov].iov_base = c; (*iov)[*n_iov].iov_len = l; - (*n_iov) ++; + (*n_iov)++; *p = e; c = NULL; @@ -200,7 +200,7 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec ** } strcpy(t, "="); - e ++; + e++; r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov); if (r < 0) diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index eb1ac90e98..f64abdd431 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -201,7 +201,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) { if (*k != ' ') break; - k ++, l --; + k++, l--; e = memchr(k, '\n', l); if (!e) diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c index 6f6a90fe4e..fce799a6ce 100644 --- a/src/journal/journald-rate-limit.c +++ b/src/journal/journald-rate-limit.c @@ -104,7 +104,7 @@ static void journal_rate_limit_group_free(JournalRateLimitGroup *g) { LIST_REMOVE(lru, g->parent->lru, g); LIST_REMOVE(bucket, g->parent->buckets[g->hash % BUCKETS_MAX], g); - g->parent->n_groups --; + g->parent->n_groups--; } free(g->id); @@ -168,7 +168,7 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, LIST_PREPEND(lru, r->lru, g); if (!g->lru_next) r->lru_tail = g; - r->n_groups ++; + r->n_groups++; g->parent = r; return g; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index ee2db8d29f..2939322925 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -251,15 +251,15 @@ static int open_journal( assert(ret); if (reliably) - r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, NULL, &f); + r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f); else - r = journal_file_open(fname, flags, 0640, s->compress, seal, metrics, s->mmap, NULL, &f); + r = journal_file_open(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f); if (r < 0) return r; r = journal_file_enable_post_change_timer(f, s->event, POST_CHANGE_TIMER_INTERVAL_USEC); if (r < 0) { - journal_file_close(f); + (void) journal_file_close(f); return r; } @@ -302,7 +302,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { /* Too many open? Then let's close one */ f = ordered_hashmap_steal_first(s->user_journals); assert(f); - journal_file_close(f); + (void) journal_file_close(f); } r = open_journal(s, true, p, O_RDWR|O_CREAT, s->seal, &s->system_metrics, &f); @@ -313,7 +313,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f); if (r < 0) { - journal_file_close(f); + (void) journal_file_close(f); return s->system_journal; } @@ -333,7 +333,7 @@ static int do_rotate( if (!*f) return -EINVAL; - r = journal_file_rotate(f, s->compress, seal); + r = journal_file_rotate(f, s->compress, seal, s->deferred_closes); if (r < 0) if (*f) log_error_errno(r, "Failed to rotate %s: %m", (*f)->path); @@ -364,6 +364,13 @@ void server_rotate(Server *s) { /* Old file has been closed and deallocated */ ordered_hashmap_remove(s->user_journals, k); } + + /* Perform any deferred closes which aren't still offlining. */ + SET_FOREACH(f, s->deferred_closes, i) + if (!journal_file_is_offlining(f)) { + (void) set_remove(s->deferred_closes, f); + (void) journal_file_close(f); + } } void server_sync(Server *s) { @@ -372,13 +379,13 @@ void server_sync(Server *s) { int r; if (s->system_journal) { - r = journal_file_set_offline(s->system_journal); + r = journal_file_set_offline(s->system_journal, false); if (r < 0) log_warning_errno(r, "Failed to sync system journal, ignoring: %m"); } ORDERED_HASHMAP_FOREACH(f, s->user_journals, i) { - r = journal_file_set_offline(f); + r = journal_file_set_offline(f, false); if (r < 0) log_warning_errno(r, "Failed to sync user journal, ignoring: %m"); } @@ -1400,7 +1407,7 @@ static int server_parse_proc_cmdline(Server *s) { } p = line; - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL; r = extract_first_word(&p, &word, NULL, 0); @@ -1765,6 +1772,10 @@ int server_init(Server *s) { if (!s->mmap) return log_oom(); + s->deferred_closes = set_new(NULL); + if (!s->deferred_closes) + return log_oom(); + r = sd_event_default(&s->event); if (r < 0) return log_error_errno(r, "Failed to create event loop: %m"); @@ -1918,17 +1929,22 @@ void server_done(Server *s) { JournalFile *f; assert(s); + if (s->deferred_closes) { + journal_file_close_set(s->deferred_closes); + set_free(s->deferred_closes); + } + while (s->stdout_streams) stdout_stream_free(s->stdout_streams); if (s->system_journal) - journal_file_close(s->system_journal); + (void) journal_file_close(s->system_journal); if (s->runtime_journal) - journal_file_close(s->runtime_journal); + (void) journal_file_close(s->runtime_journal); while ((f = ordered_hashmap_steal_first(s->user_journals))) - journal_file_close(f); + (void) journal_file_close(f); ordered_hashmap_free(s->user_journals); diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index b9551dda1b..e025a4cf90 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -130,6 +130,8 @@ struct Server { MMapCache *mmap; + Set *deferred_closes; + struct udev *udev; uint64_t *kernel_seqnum; diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 6e8b405b53..59352bcb3f 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -96,7 +96,7 @@ void stdout_stream_free(StdoutStream *s) { if (s->server) { assert(s->server->n_stdout_streams > 0); - s->server->n_stdout_streams --; + s->server->n_stdout_streams--; LIST_REMOVE(stdout_stream, s->server->stdout_streams, s); if (s->in_notify_queue) @@ -511,7 +511,7 @@ static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { stream->server = s; LIST_PREPEND(stdout_stream, s->stdout_streams, stream); - s->n_stdout_streams ++; + s->n_stdout_streams++; if (ret) *ret = stream; diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index 9c0ce8ccbf..6bcd9b6ac8 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -107,7 +107,7 @@ MMapCache* mmap_cache_ref(MMapCache *m) { assert(m); assert(m->n_ref > 0); - m->n_ref ++; + m->n_ref++; return m; } @@ -361,7 +361,7 @@ MMapCache* mmap_cache_unref(MMapCache *m) { assert(m->n_ref > 0); - m->n_ref --; + m->n_ref--; if (m->n_ref == 0) mmap_cache_free(m); @@ -598,14 +598,14 @@ int mmap_cache_get( /* Check whether the current context is the right one already */ r = try_context(m, fd, prot, context, keep_always, offset, size, ret); if (r != 0) { - m->n_hit ++; + m->n_hit++; return r; } /* Search for a matching mmap */ r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret); if (r != 0) { - m->n_hit ++; + m->n_hit++; return r; } diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 5a2a28a8d4..3c21d4129e 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -19,6 +19,7 @@ #include <errno.h> #include <fcntl.h> +#include <inttypes.h> #include <linux/magic.h> #include <poll.h> #include <stddef.h> @@ -1063,7 +1064,7 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { if (r < 0) return r; - for(;;) { + for (;;) { _cleanup_free_ char *item = NULL; unsigned long long ll; sd_id128_t id; @@ -1248,7 +1249,7 @@ static int add_any_file(sd_journal *j, const char *path) { goto fail; } - r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f); + r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f); if (r < 0) { log_debug_errno(r, "Failed to open journal file %s: %m", path); goto fail; @@ -1258,7 +1259,7 @@ static int add_any_file(sd_journal *j, const char *path) { r = ordered_hashmap_put(j->files, f->path, f); if (r < 0) { - journal_file_close(f); + (void) journal_file_close(f); goto fail; } @@ -1266,7 +1267,7 @@ static int add_any_file(sd_journal *j, const char *path) { check_network(j, f->fd); - j->current_invalidate_counter ++; + j->current_invalidate_counter++; return 0; @@ -1343,9 +1344,9 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { j->fields_file_lost = true; } - journal_file_close(f); + (void) journal_file_close(f); - j->current_invalidate_counter ++; + j->current_invalidate_counter++; } static int dirname_is_machine_id(const char *fn) { @@ -1410,7 +1411,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) } path = NULL; /* avoid freeing in cleanup */ - j->current_invalidate_counter ++; + j->current_invalidate_counter++; log_debug("Directory %s added.", m->path); @@ -1495,7 +1496,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { goto fail; } - j->current_invalidate_counter ++; + j->current_invalidate_counter++; log_debug("Root directory %s added.", m->path); @@ -1784,7 +1785,7 @@ _public_ void sd_journal_close(sd_journal *j) { sd_journal_flush_matches(j); while ((f = ordered_hashmap_steal_first(j->files))) - journal_file_close(f); + (void) journal_file_close(f); ordered_hashmap_free(j->files); @@ -1957,7 +1958,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** &f->compress_buffer, &f->compress_buffer_size, field, field_length, '='); if (r < 0) - log_debug_errno(r, "Cannot decompress %s object of length %zu at offset "OFSfmt": %m", + log_debug_errno(r, "Cannot decompress %s object of length %"PRIu64" at offset "OFSfmt": %m", object_compressed_to_string(compression), l, p); else if (r > 0) { @@ -2078,7 +2079,7 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t if (r < 0) return r; - j->current_field ++; + j->current_field++; return 1; } diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c index da6fcbca4d..898c876450 100644 --- a/src/journal/test-catalog.c +++ b/src/journal/test-catalog.c @@ -103,6 +103,8 @@ static void test_catalog_import_one(void) { assert_se(hashmap_size(h) == 1); HASHMAP_FOREACH(payload, h, j) { + printf("expect: %s\n", expect); + printf("actual: %s\n", payload); assert_se(streq(expect, payload)); } } diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c index 5b2d130cd6..0ef6d36a50 100644 --- a/src/journal/test-compress-benchmark.c +++ b/src/journal/test-compress-benchmark.c @@ -105,6 +105,8 @@ static void test_compress_decompress(const char* label, const char* type, int r; size = permute(i); + if (size == 0) + continue; log_debug("%s %zu %zu", type, i, size); diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c index e5e9d9dcb3..354c2c3c00 100644 --- a/src/journal/test-journal-enum.c +++ b/src/journal/test-journal-enum.c @@ -44,7 +44,7 @@ int main(int argc, char *argv[]) { printf("%.*s\n", (int) l, (char*) d); - n ++; + n++; if (n >= 10) break; } diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c index 7bd9c40366..93dc0e0d81 100644 --- a/src/journal/test-journal-flush.c +++ b/src/journal/test-journal-flush.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { assert_se(mkdtemp(dn)); fn = strappend(dn, "/test.journal"); - r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, &new_journal); + r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, NULL, &new_journal); assert_se(r >= 0); r = sd_journal_open(&j, 0); @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) { sd_journal_close(j); - journal_file_close(new_journal); + (void) journal_file_close(new_journal); unlink(fn); assert_se(rmdir(dn) == 0); diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index 7f94990888..f887f43f0d 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -52,12 +52,12 @@ noreturn static void log_assert_errno(const char *text, int eno, const char *fil static JournalFile *test_open(const char *name) { JournalFile *f; - assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f)); + assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, NULL, &f)); return f; } static void test_close(JournalFile *f) { - journal_file_close (f); + (void) journal_file_close (f); } static void append_number(JournalFile *f, int n, uint64_t *seqnum) { @@ -217,7 +217,7 @@ static void test_sequence_numbers(void) { assert_se(chdir(t) >= 0); assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644, - true, false, NULL, NULL, NULL, &one) == 0); + true, false, NULL, NULL, NULL, NULL, &one) == 0); append_number(one, 1, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); @@ -234,7 +234,7 @@ static void test_sequence_numbers(void) { memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t)); assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644, - true, false, NULL, NULL, one, &two) == 0); + true, false, NULL, NULL, NULL, one, &two) == 0); assert_se(two->header->state == STATE_ONLINE); assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id)); @@ -265,7 +265,7 @@ static void test_sequence_numbers(void) { seqnum = 0; assert_se(journal_file_open("two.journal", O_RDWR, 0, - true, false, NULL, NULL, NULL, &two) == 0); + true, false, NULL, NULL, NULL, NULL, &two) == 0); assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id)); diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index 4e6f8c0f7b..839ea5a9a5 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -92,9 +92,9 @@ int main(int argc, char *argv[]) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &one) == 0); - assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &two) == 0); - assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &three) == 0); + assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &one) == 0); + assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &two) == 0); + assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &three) == 0); for (i = 0; i < N_ENTRIES; i++) { char *p, *q; @@ -133,9 +133,9 @@ int main(int argc, char *argv[]) { free(q); } - journal_file_close(one); - journal_file_close(two); - journal_file_close(three); + (void) journal_file_close(one); + (void) journal_file_close(two); + (void) journal_file_close(three); assert_se(sd_journal_open_directory(&j, t, 0) >= 0); diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index a26c624f41..6b4643cd25 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -55,12 +55,12 @@ static int raw_verify(const char *fn, const char *verification_key) { JournalFile *f; int r; - r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f); + r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f); if (r < 0) return r; r = journal_file_verify(f, verification_key, NULL, NULL, NULL, false); - journal_file_close(f); + (void) journal_file_close(f); return r; } @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) { log_info("Generating..."); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); for (n = 0; n < N_ENTRIES; n++) { struct iovec iovec; @@ -107,11 +107,11 @@ int main(int argc, char *argv[]) { free(test); } - journal_file_close(f); + (void) journal_file_close(f); log_info("Verifying..."); - assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); /* journal_file_print_header(f); */ journal_file_dump(f); @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) { format_timestamp(b, sizeof(b), to), format_timespan(c, sizeof(c), total > to ? total - to : 0, 0)); - journal_file_close(f); + (void) journal_file_close(f); if (verification_key) { log_info("Toggling bits..."); diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 0334b1cd1a..ea685af782 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -42,7 +42,7 @@ static void test_non_empty(void) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f) == 0); dual_timestamp_get(&ts); @@ -104,10 +104,10 @@ static void test_non_empty(void) { assert_se(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0); - journal_file_rotate(&f, true, true); - journal_file_rotate(&f, true, true); + journal_file_rotate(&f, true, true, NULL); + journal_file_rotate(&f, true, true, NULL); - journal_file_close(f); + (void) journal_file_close(f); log_info("Done..."); @@ -131,13 +131,13 @@ static void test_empty(void) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, &f1) == 0); + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, NULL, &f1) == 0); - assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f2) == 0); + assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &f2) == 0); - assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, &f3) == 0); + assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, NULL, &f3) == 0); - assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f4) == 0); + assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f4) == 0); journal_file_print_header(f1); puts(""); @@ -158,10 +158,10 @@ static void test_empty(void) { assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } - journal_file_close(f1); - journal_file_close(f2); - journal_file_close(f3); - journal_file_close(f4); + (void) journal_file_close(f1); + (void) journal_file_close(f2); + (void) journal_file_close(f3); + (void) journal_file_close(f4); } int main(int argc, char *argv[]) { diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 1d9ec7be82..4f7d4d8bf2 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { if (r < 0) return r; - unaligned_write_be16(&duid->type, DHCP6_DUID_EN); + unaligned_write_be16(&duid->type, DUID_TYPE_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); *len = sizeof(duid->type) + sizeof(duid->en); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 93f06f5938..e6486b78f8 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -25,13 +25,23 @@ #include "sparse-endian.h" #include "unaligned.h" +typedef enum DUIDType { + DUID_TYPE_RAW = 0, + DUID_TYPE_LLT = 1, + DUID_TYPE_EN = 2, + DUID_TYPE_LL = 3, + DUID_TYPE_UUID = 4, + _DUID_TYPE_MAX, + _DUID_TYPE_INVALID = -1, +} DUIDType; + /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 struct duid { - uint16_t type; + be16_t type; union { struct { /* DHCP6_DUID_LLT */ @@ -61,3 +71,34 @@ struct duid { int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); + +static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { + struct duid d; + + assert(duid_len > 0); + + switch (duid_type) { + case DUID_TYPE_LLT: + if (duid_len <= sizeof(d.llt)) + return -EINVAL; + break; + case DUID_TYPE_EN: + if (duid_len != sizeof(d.en)) + return -EINVAL; + break; + case DUID_TYPE_LL: + if (duid_len <= sizeof(d.ll)) + return -EINVAL; + break; + case DUID_TYPE_UUID: + if (duid_len != sizeof(d.uuid)) + return -EINVAL; + break; + default: + if (duid_len > sizeof(d.raw)) + return -EINVAL; + /* accept unknown type in order to be forward compatible */ + break; + } + return 0; +} diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index a3b842cda3..4662b0d847 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -42,10 +42,10 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload, uint8_t code, size_t optlen, const void *optval); -typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, +typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len, const void *option, void *userdata); -int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message); +int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message); int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type, uint16_t arp_type, size_t optlen, diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index b0ea7576bf..c105196334 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -34,7 +34,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, if (code != SD_DHCP_OPTION_END) /* always make sure there is space for an END option */ - size --; + size--; switch (code) { @@ -135,7 +135,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, } static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, - uint8_t *message_type, char **error_message, dhcp_option_cb_t cb, + uint8_t *message_type, char **error_message, dhcp_option_callback_t cb, void *userdata) { uint8_t code, len; const uint8_t *option; @@ -221,7 +221,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo return 0; } -int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) { +int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) { _cleanup_free_ char *error_message = NULL; uint8_t overload = 0; uint8_t message_type = 0; diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index 8d75d49691..8be774061d 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -66,7 +66,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) { /* wrap around in one's complement */ sum++; - buf_64 ++; + buf_64++; } if (len % sizeof(uint64_t)) { diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index bf123f1439..adb557167a 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "sd-dhcp-server.h" #include "sd-event.h" diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index ee4bdfb07f..2487c470ab 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -62,13 +62,6 @@ enum { #define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC #define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC -enum { - DHCP6_DUID_LLT = 1, - DHCP6_DUID_EN = 2, - DHCP6_DUID_LL = 3, - DHCP6_DUID_UUID = 4, -}; - enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_INFORMATION_REQUEST = 1, diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c deleted file mode 100644 index c8740ce5f0..0000000000 --- a/src/libsystemd-network/lldp-internal.c +++ /dev/null @@ -1,360 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include "sd-lldp.h" - -#include "alloc-util.h" -#include "lldp-internal.h" - -/* We store maximum 1K chassis entries */ -#define LLDP_MIB_MAX_CHASSIS 1024 - -/* Maximum Ports can be attached to any chassis */ -#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32 - -/* 10.5.5.2.2 mibUpdateObjects () - * The mibUpdateObjects () procedure updates the MIB objects corresponding to - * the TLVs contained in the received LLDPDU for the LLDP remote system - * indicated by the LLDP remote systems update process defined in 10.3.5 */ - -int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { - lldp_neighbour_port *p; - uint16_t length, ttl; - uint8_t *data; - uint8_t type; - int r; - - assert_return(c, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - /* Update the packet if we already have */ - LIST_FOREACH(port, p, c->ports) { - - if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) { - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - return r; - - p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - - sd_lldp_packet_unref(p->packet); - p->packet = tlv; - - prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx); - - return 0; - } - } - - return -1; -} - -int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) { - lldp_neighbour_port *p, *q; - uint8_t *data; - uint16_t length; - uint8_t type; - int r; - - assert_return(c, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - LIST_FOREACH_SAFE(port, p, q, c->ports) { - - /* Find the port */ - if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) { - lldp_neighbour_port_remove_and_free(p); - break; - } - } - - return 0; -} - -int lldp_mib_add_objects(Prioq *by_expiry, - Hashmap *neighbour_mib, - tlv_packet *tlv) { - _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; - _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; - lldp_chassis_id chassis_id; - bool new_chassis = false; - uint8_t subtype, *data; - uint16_t ttl, length; - int r; - - assert_return(by_expiry, -EINVAL); - assert_return(neighbour_mib, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length); - if (r < 0) - goto drop; - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - goto drop; - - /* Make hash key */ - chassis_id.type = subtype; - chassis_id.length = length; - chassis_id.data = data; - - /* Try to find the Chassis */ - c = hashmap_get(neighbour_mib, &chassis_id); - if (!c) { - - /* Don't create chassis if ttl 0 is received . Silently drop it */ - if (ttl == 0) { - log_lldp("TTL value 0 received. Skiping Chassis creation."); - goto drop; - } - - /* Admission Control: Can we store this packet ? */ - if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) { - - log_lldp("Exceeding number of chassie: %d. Dropping ...", - hashmap_size(neighbour_mib)); - goto drop; - } - - r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c); - if (r < 0) - goto drop; - - new_chassis = true; - - r = hashmap_put(neighbour_mib, &c->chassis_id, c); - if (r < 0) - goto drop; - - } else { - - /* When the TTL field is set to zero, the receiving LLDP agent is notified all - * system information associated with the LLDP agent/port is to be deleted */ - if (ttl == 0) { - log_lldp("TTL value 0 received . Deleting associated Port ..."); - - lldp_mib_remove_objects(c, tlv); - - c = NULL; - goto drop; - } - - /* if we already have this port just update it */ - r = lldp_mib_update_objects(c, tlv); - if (r >= 0) { - c = NULL; - return r; - } - - /* Admission Control: Can this port attached to the existing chassis ? */ - if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) { - log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref); - - c = NULL; - goto drop; - } - } - - /* This is a new port */ - r = lldp_neighbour_port_new(c, tlv, &p); - if (r < 0) - goto drop; - - r = prioq_put(c->by_expiry, p, &p->prioq_idx); - if (r < 0) - goto drop; - - /* Attach new port to chassis */ - LIST_PREPEND(port, c->ports, p); - c->n_ref ++; - - p = NULL; - c = NULL; - - return 0; - - drop: - sd_lldp_packet_unref(tlv); - - if (new_chassis) - hashmap_remove(neighbour_mib, &c->chassis_id); - - return r; -} - -void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) { - lldp_chassis *c; - - assert(p); - assert(p->c); - - c = p->c; - - prioq_remove(c->by_expiry, p, &p->prioq_idx); - - LIST_REMOVE(port, c->ports, p); - lldp_neighbour_port_free(p); - - /* Drop the Chassis if no port is attached */ - c->n_ref --; - if (c->n_ref <= 1) { - hashmap_remove(c->neighbour_mib, &c->chassis_id); - lldp_chassis_free(c); - } -} - -void lldp_neighbour_port_free(lldp_neighbour_port *p) { - - if(!p) - return; - - sd_lldp_packet_unref(p->packet); - - free(p->data); - free(p); -} - -int lldp_neighbour_port_new(lldp_chassis *c, - tlv_packet *tlv, - lldp_neighbour_port **ret) { - _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; - uint16_t length, ttl; - uint8_t *data; - uint8_t type; - int r; - - assert(tlv); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - return r; - - p = new0(lldp_neighbour_port, 1); - if (!p) - return -ENOMEM; - - p->c = c; - p->type = type; - p->length = length; - p->packet = tlv; - p->prioq_idx = PRIOQ_IDX_NULL; - p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - - p->data = memdup(data, length); - if (!p->data) - return -ENOMEM; - - *ret = p; - p = NULL; - - return 0; -} - -void lldp_chassis_free(lldp_chassis *c) { - - if (!c) - return; - - if (c->n_ref > 1) - return; - - free(c->chassis_id.data); - free(c); -} - -int lldp_chassis_new(tlv_packet *tlv, - Prioq *by_expiry, - Hashmap *neighbour_mib, - lldp_chassis **ret) { - _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; - uint16_t length; - uint8_t *data; - uint8_t type; - int r; - - assert(tlv); - - r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - c = new0(lldp_chassis, 1); - if (!c) - return -ENOMEM; - - c->n_ref = 1; - c->chassis_id.type = type; - c->chassis_id.length = length; - - c->chassis_id.data = memdup(data, length); - if (!c->chassis_id.data) - return -ENOMEM; - - LIST_HEAD_INIT(c->ports); - - c->by_expiry = by_expiry; - c->neighbour_mib = neighbour_mib; - - *ret = c; - c = NULL; - - return 0; -} - -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *packet = NULL; - tlv_packet *p; - uint16_t length; - int r; - - assert(fd); - assert(userdata); - - r = tlv_packet_new(&packet); - if (r < 0) - return r; - - length = read(fd, &packet->pdu, sizeof(packet->pdu)); - - /* Silently drop the packet */ - if ((size_t) length > ETHER_MAX_LEN) - return 0; - - packet->userdata = userdata; - - p = packet; - packet = NULL; - - return lldp_handle_packet(p, (uint16_t) length); -} diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 15b4a11b15..7592bc4305 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,74 +20,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "sd-event.h" +#include "sd-lldp.h" -#include "list.h" -#include "lldp-tlv.h" +#include "hashmap.h" #include "log.h" #include "prioq.h" -typedef struct lldp_neighbour_port lldp_neighbour_port; -typedef struct lldp_chassis lldp_chassis; -typedef struct lldp_chassis_id lldp_chassis_id; -typedef struct lldp_agent_statistics lldp_agent_statistics; +struct sd_lldp { + int ifindex; + int fd; -struct lldp_neighbour_port { - uint8_t type; - uint8_t *data; + sd_event *event; + int64_t event_priority; + sd_event_source *io_event_source; + sd_event_source *timer_event_source; - uint16_t length; - usec_t until; + Prioq *neighbor_by_expiry; + Hashmap *neighbor_by_id; - unsigned prioq_idx; + uint64_t neighbors_max; - lldp_chassis *c; - tlv_packet *packet; + sd_lldp_callback_t callback; + void *userdata; - LIST_FIELDS(lldp_neighbour_port, port); -}; + uint16_t capability_mask; -int lldp_neighbour_port_new(lldp_chassis *c, tlv_packet *tlv, lldp_neighbour_port **ret); -void lldp_neighbour_port_free(lldp_neighbour_port *p); -void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_neighbour_port *, lldp_neighbour_port_free); -#define _cleanup_lldp_neighbour_port_free_ _cleanup_(lldp_neighbour_port_freep) - -struct lldp_chassis_id { - uint8_t type; - uint16_t length; - - uint8_t *data; + struct ether_addr filter_address; }; -struct lldp_chassis { - unsigned n_ref; - - lldp_chassis_id chassis_id; - - Prioq *by_expiry; - Hashmap *neighbour_mib; - - LIST_HEAD(lldp_neighbour_port, ports); -}; - -int lldp_chassis_new(tlv_packet *tlv, - Prioq *by_expiry, - Hashmap *neighbour_mib, - lldp_chassis **ret); - -void lldp_chassis_free(lldp_chassis *c); - -DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_chassis *, lldp_chassis_free); -#define _cleanup_lldp_chassis_free_ _cleanup_(lldp_chassis_freep) - -int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv); -int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv); -int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv); - -int lldp_handle_packet(tlv_packet *m, uint16_t length); -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata); -#define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) +#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) +#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c new file mode 100644 index 0000000000..6a716430e3 --- /dev/null +++ b/src/libsystemd-network/lldp-neighbor.c @@ -0,0 +1,794 @@ +/*** + 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 "alloc-util.h" +#include "escape.h" +#include "ether-addr-util.h" +#include "hexdecoct.h" +#include "in-addr-util.h" +#include "lldp-internal.h" +#include "lldp-neighbor.h" +#include "unaligned.h" + +static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) { + const LLDPNeighborID *id = p; + + siphash24_compress(id->chassis_id, id->chassis_id_size, state); + siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state); + siphash24_compress(id->port_id, id->port_id_size, state); + siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state); +} + +static int lldp_neighbor_id_compare_func(const void *a, const void *b) { + const LLDPNeighborID *x = a, *y = b; + int r; + + r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size)); + if (r != 0) + return r; + + if (x->chassis_id_size < y->chassis_id_size) + return -1; + + if (x->chassis_id_size > y->chassis_id_size) + return 1; + + r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size)); + if (r != 0) + return r; + + if (x->port_id_size < y->port_id_size) + return -1; + if (x->port_id_size > y->port_id_size) + return 1; + + return 0; +} + +const struct hash_ops lldp_neighbor_id_hash_ops = { + .hash = lldp_neighbor_id_hash_func, + .compare = lldp_neighbor_id_compare_func +}; + +int lldp_neighbor_prioq_compare_func(const void *a, const void *b) { + const sd_lldp_neighbor *x = a, *y = b; + + if (x->until < y->until) + return -1; + + if (x->until > y->until) + return 1; + + return 0; +} + +_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) { + if (!n) + return NULL; + + assert(n->n_ref > 0 || n->lldp); + n->n_ref++; + + return n; +} + +static void lldp_neighbor_free(sd_lldp_neighbor *n) { + assert(n); + + free(n->id.port_id); + free(n->id.chassis_id); + free(n->port_description); + free(n->system_name); + free(n->system_description); + free(n->chassis_id_as_string); + free(n->port_id_as_string); + free(n); +} + +_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) { + + /* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from + * the sd_lldp object. */ + + if (!n) + return NULL; + + assert(n->n_ref > 0); + n->n_ref--; + + if (n->n_ref <= 0 && !n->lldp) + lldp_neighbor_free(n); + + return NULL; +} + +sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) { + + /* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */ + + if (!n) + return NULL; + + if (!n->lldp) + return NULL; + + assert_se(hashmap_remove(n->lldp->neighbor_by_id, &n->id) == n); + assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0); + + n->lldp = NULL; + + if (n->n_ref <= 0) + lldp_neighbor_free(n); + + return NULL; +} + +sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) { + sd_lldp_neighbor *n; + + n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size); + if (!n) + return NULL; + + n->raw_size = raw_size; + n->n_ref = 1; + + return n; +} + +static int parse_string(char **s, const void *q, size_t n) { + const char *p = q; + char *k; + + assert(s); + assert(p || n == 0); + + if (*s) { + log_lldp("Found duplicate string, ignoring field."); + return 0; + } + + /* Strip trailing NULs, just to be nice */ + while (n > 0 && p[n-1] == 0) + n--; + + if (n <= 0) /* Ignore empty strings */ + return 0; + + /* Look for inner NULs */ + if (memchr(p, 0, n)) { + log_lldp("Found inner NUL in string, ignoring field."); + return 0; + } + + /* Let's escape weird chars, for security reasons */ + k = cescape_length(p, n); + if (!k) + return -ENOMEM; + + free(*s); + *s = k; + + return 1; +} + +int lldp_neighbor_parse(sd_lldp_neighbor *n) { + struct ether_header h; + const uint8_t *p; + size_t left; + int r; + + assert(n); + + if (n->raw_size < sizeof(struct ether_header)) { + log_lldp("Recieved truncated packet, ignoring."); + return -EBADMSG; + } + + memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h)); + + if (h.ether_type != htobe16(ETHERTYPE_LLDP)) { + log_lldp("Received packet with wrong type, ignoring."); + return -EBADMSG; + } + + if (h.ether_dhost[0] != 0x01 || + h.ether_dhost[1] != 0x80 || + h.ether_dhost[2] != 0xc2 || + h.ether_dhost[3] != 0x00 || + h.ether_dhost[4] != 0x00 || + !IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e)) { + log_lldp("Received packet with wrong destination address, ignoring."); + return -EBADMSG; + } + + memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr)); + memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr)); + + p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header); + left = n->raw_size - sizeof(struct ether_header); + + for (;;) { + uint8_t type; + uint16_t length; + + if (left < 2) { + log_lldp("TLV lacks header, ignoring."); + return -EBADMSG; + } + + type = p[0] >> 1; + length = p[1] + (((uint16_t) (p[0] & 1)) << 8); + p += 2, left -= 2; + + if (left < length) { + log_lldp("TLV truncated, ignoring datagram."); + return -EBADMSG; + } + + switch (type) { + + case SD_LLDP_TYPE_END: + if (length != 0) { + log_lldp("End marker TLV not zero-sized, ignoring datagram."); + return -EBADMSG; + } + if (left != 0) { + log_lldp("Trailing garbage in datagram, ignoring datagram."); + return -EBADMSG; + } + + goto end_marker; + + case SD_LLDP_TYPE_CHASSIS_ID: + if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */ + log_lldp("Chassis ID field size out of range, ignoring datagram."); + return -EBADMSG; + } + if (n->id.chassis_id) { + log_lldp("Duplicate chassis ID field, ignoring datagram."); + return -EBADMSG; + } + + n->id.chassis_id = memdup(p, length); + if (!n->id.chassis_id) + return -ENOMEM; + + n->id.chassis_id_size = length; + break; + + case SD_LLDP_TYPE_PORT_ID: + if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */ + log_lldp("Port ID field size out of range, ignoring datagram."); + return -EBADMSG; + } + if (n->id.port_id) { + log_lldp("Duplicate port ID field, ignoring datagram."); + return -EBADMSG; + } + + n->id.port_id = memdup(p, length); + if (!n->id.port_id) + return -ENOMEM; + + n->id.port_id_size = length; + break; + + case SD_LLDP_TYPE_TTL: + if (length != 2) { + log_lldp("TTL field has wrong size, ignoring datagram."); + return -EBADMSG; + } + + if (n->has_ttl) { + log_lldp("Duplicate TTL field, ignoring datagram."); + return -EBADMSG; + } + + n->ttl = unaligned_read_be16(p); + n->has_ttl = true; + break; + + case SD_LLDP_TYPE_PORT_DESCRIPTION: + r = parse_string(&n->port_description, p, length); + if (r < 0) + return r; + break; + + case SD_LLDP_TYPE_SYSTEM_NAME: + r = parse_string(&n->system_name, p, length); + if (r < 0) + return r; + break; + + case SD_LLDP_TYPE_SYSTEM_DESCRIPTION: + r = parse_string(&n->system_description, p, length); + if (r < 0) + return r; + break; + + case SD_LLDP_TYPE_SYSTEM_CAPABILITIES: + if (length != 4) + log_lldp("System capabilities field has wrong size, ignoring."); + else { + n->system_capabilities = unaligned_read_be16(p); + n->enabled_capabilities = unaligned_read_be16(p + 2); + n->has_capabilities = true; + } + + break; + + case SD_LLDP_TYPE_PRIVATE: + if (length < 4) + log_lldp("Found private TLV that is too short, ignoring."); + + break; + } + + + p += length, left -= length; + } + +end_marker: + if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) { + log_lldp("One or more mandatory TLV missing in datagram. Ignoring."); + return -EBADMSG; + + } + + n->rindex = sizeof(struct ether_header); + + return 0; +} + +void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) { + assert(n); + + if (n->ttl > 0) + n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC); + else + n->until = 0; + + if (n->lldp) + prioq_reshuffle(n->lldp->neighbor_by_expiry, n, &n->prioq_idx); +} + +bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) { + if (a == b) + return true; + + if (!a || !b) + return false; + + if (a->raw_size != b->raw_size) + return false; + + return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0; +} + +_public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) { + assert_return(n, -EINVAL); + assert_return(address, -EINVAL); + + *address = n->source_address; + return 0; +} + +_public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) { + assert_return(n, -EINVAL); + assert_return(address, -EINVAL); + + *address = n->destination_address; + return 0; +} + +_public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + *ret = LLDP_NEIGHBOR_RAW(n); + *size = n->raw_size; + + return 0; +} + +_public_ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + assert(n->id.chassis_id_size > 0); + + *type = *(uint8_t*) n->id.chassis_id; + *ret = (uint8_t*) n->id.chassis_id + 1; + *size = n->id.chassis_id_size - 1; + + return 0; +} + +static int format_mac_address(const void *data, size_t sz, char **ret) { + struct ether_addr a; + char *k; + + assert(data || sz <= 0); + + if (sz != 7) + return 0; + + memcpy(&a, (uint8_t*) data + 1, sizeof(a)); + + k = new(char, ETHER_ADDR_TO_STRING_MAX); + if (!k) + return -ENOMEM; + + *ret = ether_addr_to_string(&a, k); + return 1; +} + +static int format_network_address(const void *data, size_t sz, char **ret) { + union in_addr_union a; + int family, r; + + if (sz == 6 && ((uint8_t*) data)[1] == 1) { + memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in)); + family = AF_INET; + } else if (sz == 18 && ((uint8_t*) data)[1] == 2) { + memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6)); + family = AF_INET6; + } else + return 0; + + r = in_addr_to_string(family, &a, ret); + if (r < 0) + return r; + return 1; +} + +_public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) { + char *k; + int r; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (n->chassis_id_as_string) { + *ret = n->chassis_id_as_string; + return 0; + } + + assert(n->id.chassis_id_size > 0); + + switch (*(uint8_t*) n->id.chassis_id) { + + case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: + case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: + case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: + case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: + case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: + k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1); + if (!k) + return -ENOMEM; + + goto done; + + case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + + case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: + r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + } + + /* Generic fallback */ + k = hexmem(n->id.chassis_id, n->id.chassis_id_size); + if (!k) + return -ENOMEM; + +done: + *ret = n->chassis_id_as_string = k; + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + assert(n->id.port_id_size > 0); + + *type = *(uint8_t*) n->id.port_id; + *ret = (uint8_t*) n->id.port_id + 1; + *size = n->id.port_id_size - 1; + + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) { + char *k; + int r; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (n->port_id_as_string) { + *ret = n->port_id_as_string; + return 0; + } + + assert(n->id.port_id_size > 0); + + switch (*(uint8_t*) n->id.port_id) { + + case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT: + case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1); + if (!k) + return -ENOMEM; + + goto done; + + case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS: + r = format_mac_address(n->id.port_id, n->id.port_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + + case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: + r = format_network_address(n->id.port_id, n->id.port_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + } + + /* Generic fallback */ + k = hexmem(n->id.port_id, n->id.port_id_size); + if (!k) + return -ENOMEM; + +done: + *ret = n->port_id_as_string = k; + return 0; +} + +_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = n->ttl; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->system_name) + return -ENODATA; + + *ret = n->system_name; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->system_description) + return -ENODATA; + + *ret = n->system_description; + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->port_description) + return -ENODATA; + + *ret = n->port_description; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->has_capabilities) + return -ENODATA; + + *ret = n->system_capabilities; + return 0; +} + +_public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->has_capabilities) + return -ENODATA; + + *ret = n->enabled_capabilities; + return 0; +} + +int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + int r; + + assert_return(ret, -EINVAL); + assert_return(raw || raw_size <= 0, -EINVAL); + + n = lldp_neighbor_new(raw_size); + if (!n) + return -ENOMEM; + + memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size); + r = lldp_neighbor_parse(n); + if (r < 0) + return r; + + *ret = n; + n = 0; + + return r; +} + +_public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) { + assert_return(n, -EINVAL); + + assert(n->raw_size >= sizeof(struct ether_header)); + n->rindex = sizeof(struct ether_header); + + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) { + size_t length; + + assert_return(n, -EINVAL); + + if (n->rindex == n->raw_size) /* EOF */ + return -ESPIPE; + + if (n->rindex + 2 > n->raw_size) /* Truncated message */ + return -EBADMSG; + + length = LLDP_NEIGHBOR_LENGTH(n); + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + n->rindex += 2 + length; + return n->rindex < n->raw_size; +} + +_public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + + if (n->rindex == n->raw_size) /* EOF */ + return -ESPIPE; + + if (n->rindex + 2 > n->raw_size) + return -EBADMSG; + + *type = LLDP_NEIGHBOR_TYPE(n); + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) { + uint8_t k; + int r; + + assert_return(n, -EINVAL); + + r = sd_lldp_neighbor_tlv_get_type(n, &k); + if (r < 0) + return r; + + return type == k; +} + +_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype) { + const uint8_t *d; + size_t length; + int r; + + assert_return(n, -EINVAL); + assert_return(oui, -EINVAL); + assert_return(subtype, -EINVAL); + + r = sd_lldp_neighbor_tlv_is_type(n, SD_LLDP_TYPE_PRIVATE); + if (r < 0) + return r; + if (r == 0) + return -ENXIO; + + length = LLDP_NEIGHBOR_LENGTH(n); + if (length < 4) + return -EBADMSG; + + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + d = LLDP_NEIGHBOR_DATA(n); + memcpy(oui, d, 3); + *subtype = d[3]; + + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype) { + uint8_t k[3], st; + int r; + + r = sd_lldp_neighbor_tlv_get_oui(n, k, &st); + if (r == -ENXIO) + return 0; + if (r < 0) + return r; + + return memcmp(k, oui, 3) == 0 && st == subtype; +} + +_public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) { + size_t length; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + /* Note that this returns the full TLV, including the TLV header */ + + if (n->rindex + 2 > n->raw_size) + return -EBADMSG; + + length = LLDP_NEIGHBOR_LENGTH(n); + + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + *ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; + *size = length + 2; + + return 0; +} diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h new file mode 100644 index 0000000000..f203bfa604 --- /dev/null +++ b/src/libsystemd-network/lldp-neighbor.h @@ -0,0 +1,106 @@ +#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 <stdbool.h> +#include <sys/types.h> + +#include "sd-lldp.h" + +#include "hash-funcs.h" +#include "lldp-internal.h" +#include "time-util.h" + +typedef struct LLDPNeighborID { + /* The spec calls this an "MSAP identifier" */ + void *chassis_id; + size_t chassis_id_size; + + void *port_id; + size_t port_id_size; +} LLDPNeighborID; + +struct sd_lldp_neighbor { + /* Neighbor objects stay around as long as they are linked into an "sd_lldp" object or n_ref > 0. */ + sd_lldp *lldp; + unsigned n_ref; + + usec_t until; + unsigned prioq_idx; + + struct ether_addr source_address; + struct ether_addr destination_address; + + LLDPNeighborID id; + + /* The raw packet size. The data is appended to the object, accessible via LLDP_NEIGHBOR_RAW() */ + size_t raw_size; + + /* The current read index for the iterative TLV interface */ + size_t rindex; + + /* And a couple of fields parsed out. */ + bool has_ttl:1; + bool has_capabilities:1; + bool has_port_vlan_id:1; + + uint16_t ttl; + + uint16_t system_capabilities; + uint16_t enabled_capabilities; + + char *port_description; + char *system_name; + char *system_description; + + uint16_t port_vlan_id; + + char *chassis_id_as_string; + char *port_id_as_string; +}; + +static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) { + return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor)); +} + +static inline uint8_t LLDP_NEIGHBOR_TYPE(const sd_lldp_neighbor *n) { + return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1; +} + +static inline size_t LLDP_NEIGHBOR_LENGTH(const sd_lldp_neighbor *n) { + uint8_t *p; + + p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; + return p[1] + (((size_t) (p[0] & 1)) << 8); +} + +static inline void* LLDP_NEIGHBOR_DATA(const sd_lldp_neighbor *n) { + return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2; +} + +extern const struct hash_ops lldp_neighbor_id_hash_ops; +int lldp_neighbor_prioq_compare_func(const void *a, const void *b); + +sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n); +sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size); +int lldp_neighbor_parse(sd_lldp_neighbor *n); +void lldp_neighbor_start_ttl(sd_lldp_neighbor *n); +bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b); diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index 42058c4449..f031760351 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -19,65 +19,58 @@ ***/ #include <linux/filter.h> -#include <linux/if_ether.h> +#include <netinet/if_ether.h> #include "fd-util.h" -#include "lldp-internal.h" #include "lldp-network.h" -#include "lldp-tlv.h" #include "socket-util.h" int lldp_network_bind_raw_socket(int ifindex) { - typedef struct LLDPFrame { - struct ethhdr hdr; - uint8_t tlvs[0]; - } LLDPFrame; - struct sock_filter filter[] = { - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest)), /* A <- 4 bytes of destination MAC */ + static const struct sock_filter filter[] = { + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_proto)), /* A <- protocol */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */ }; - struct sock_fprog fprog = { + static const struct sock_fprog fprog = { .len = ELEMENTSOF(filter), - .filter = filter + .filter = (struct sock_filter*) filter, }; - _cleanup_close_ int s = -1; - union sockaddr_union saddrll = { .ll.sll_family = AF_PACKET, .ll.sll_ifindex = ifindex, }; + _cleanup_close_ int fd = -1; int r; assert(ifindex > 0); - s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (s < 0) + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, htons(ETHERTYPE_LLDP)); + if (fd < 0) return -errno; - r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); + r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); if (r < 0) return -errno; - r = bind(s, &saddrll.sa, sizeof(saddrll.ll)); + r = bind(fd, &saddrll.sa, sizeof(saddrll.ll)); if (r < 0) return -errno; - r = s; - s = -1; + r = fd; + fd = -1; return r; } diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h index dcf31faa95..c4cf8c79f1 100644 --- a/src/libsystemd-network/lldp-network.h +++ b/src/libsystemd-network/lldp-network.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "sd-event.h" int lldp_network_bind_raw_socket(int ifindex); diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c deleted file mode 100644 index c86f62a6c2..0000000000 --- a/src/libsystemd-network/lldp-port.c +++ /dev/null @@ -1,116 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You 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 "async.h" -#include "lldp-internal.h" -#include "lldp-network.h" -#include "lldp-port.h" - -int lldp_port_start(lldp_port *p) { - int r; - - assert_return(p, -EINVAL); - - r = lldp_network_bind_raw_socket(p->ifindex); - if (r < 0) - return r; - - p->rawfd = r; - - r = sd_event_add_io(p->event, &p->lldp_port_rx, - p->rawfd, EPOLLIN, lldp_receive_packet, p); - if (r < 0) { - log_debug_errno(r, "Failed to allocate event source: %m"); - goto fail; - } - - r = sd_event_source_set_priority(p->lldp_port_rx, p->event_priority); - if (r < 0) { - log_debug_errno(r, "Failed to set event priority: %m"); - goto fail; - } - - r = sd_event_source_set_description(p->lldp_port_rx, "lldp-port-rx"); - if (r < 0) { - log_debug_errno(r, "Failed to set event name: %m"); - goto fail; - } - - return 0; - -fail: - lldp_port_stop(p); - - return r; -} - -int lldp_port_stop(lldp_port *p) { - - assert_return(p, -EINVAL); - - p->rawfd = asynchronous_close(p->rawfd); - p->lldp_port_rx = sd_event_source_unref(p->lldp_port_rx); - - return 0; -} - -void lldp_port_free(lldp_port *p) { - if (!p) - return; - - lldp_port_stop(p); - - free(p->ifname); - free(p); -} - -int lldp_port_new(int ifindex, - const char *ifname, - const struct ether_addr *addr, - void *userdata, - lldp_port **ret) { - _cleanup_free_ lldp_port *p = NULL; - - assert_return(ifindex, -EINVAL); - assert_return(ifname, -EINVAL); - assert_return(addr, -EINVAL); - - p = new0(lldp_port, 1); - if (!p) - return -ENOMEM; - - p->rawfd = -1; - p->ifindex = ifindex; - - p->ifname = strdup(ifname); - if (!p->ifname) - return -ENOMEM; - - memcpy(&p->mac, addr, ETH_ALEN); - - p->userdata = userdata; - - *ret = p; - - p = NULL; - - return 0; -} diff --git a/src/libsystemd-network/lldp-port.h b/src/libsystemd-network/lldp-port.h deleted file mode 100644 index 96092f8df9..0000000000 --- a/src/libsystemd-network/lldp-port.h +++ /dev/null @@ -1,69 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - 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 - -#include <net/ethernet.h> - -#include "sd-event.h" -#include "sd-lldp.h" - -#include "util.h" - -typedef struct lldp_port lldp_port; - -typedef enum LLDPPortStatus { - LLDP_PORT_STATUS_NONE, - LLDP_PORT_STATUS_ENABLED, - LLDP_PORT_STATUS_DISABLED, - _LLDP_PORT_STATUS_MAX, - _LLDP_PORT_STATUS_INVALID = -1, -} LLDPPortStatus; - -struct lldp_port { - LLDPPortStatus status; - - int ifindex; - char *ifname; - - struct ether_addr mac; - - int rawfd; - - sd_event *event; - sd_event_source *lldp_port_rx; - - int event_priority; - - void *userdata; -}; - -int lldp_port_new(int ifindex, - const char *ifname, - const struct ether_addr *addr, - void *userdata, - lldp_port **ret); -void lldp_port_free(lldp_port *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_port*, lldp_port_free); -#define _cleanup_lldp_port_free_ _cleanup_(lldp_port_freep) - -int lldp_port_start(lldp_port *p); -int lldp_port_stop(lldp_port *p); diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c deleted file mode 100644 index 9170b50691..0000000000 --- a/src/libsystemd-network/lldp-tlv.c +++ /dev/null @@ -1,638 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You 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 <net/ethernet.h> - -#include "alloc-util.h" -#include "lldp-tlv.h" -#include "macro.h" - -int tlv_section_new(tlv_section **ret) { - tlv_section *s; - - s = new0(tlv_section, 1); - if (!s) - return -ENOMEM; - - *ret = s; - - return 0; -} - -void tlv_section_free(tlv_section *m) { - - if (!m) - return; - - free(m); -} - -int tlv_packet_new(tlv_packet **ret) { - tlv_packet *m; - - m = new0(tlv_packet, 1); - if (!m) - return -ENOMEM; - - LIST_HEAD_INIT(m->sections); - m->n_ref = 1; - - *ret = m; - - return 0; -} - -tlv_packet *sd_lldp_packet_ref(tlv_packet *m) { - - if (!m) - return NULL; - - assert(m->n_ref > 0); - m->n_ref++; - - return m; -} - -tlv_packet *sd_lldp_packet_unref(tlv_packet *m) { - tlv_section *s, *n; - - if (!m) - return NULL; - - assert(m->n_ref > 0); - m->n_ref--; - - if (m->n_ref > 0) - return m; - - LIST_FOREACH_SAFE(section, s, n, m->sections) - tlv_section_free(s); - - free(m); - return NULL; -} - -int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) { - uint8_t *p; - - assert_return(m, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_length, -EINVAL); - - if (m->length + data_length > ETHER_MAX_LEN) - return -ENOMEM; - - p = m->pdu + m->length; - memcpy(p, data, data_length); - m->length += data_length; - - return 0; -} - -int tlv_packet_append_u8(tlv_packet *m, uint8_t data) { - - assert_return(m, -EINVAL); - - return tlv_packet_append_bytes(m, &data, sizeof(uint8_t)); -} - -int tlv_packet_append_u16(tlv_packet *m, uint16_t data) { - uint16_t type; - - assert_return(m, -EINVAL); - - type = htons(data); - - return tlv_packet_append_bytes(m, &type, sizeof(uint16_t)); -} - -int tlv_packet_append_u32(tlv_packet *m, uint32_t data) { - uint32_t type; - - assert_return(m, -EINVAL); - - type = htonl(data); - - return tlv_packet_append_bytes(m, &type, sizeof(uint32_t)); -} - -int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size) { - - assert_return(m, -EINVAL); - - return tlv_packet_append_bytes(m, data, size); -} - -int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type) { - - assert_return(m, -EINVAL); - - m->container_pos = m->pdu + m->length; - - return tlv_packet_append_u16(m, type << 9); -} - -int lldp_tlv_packet_close_container(tlv_packet *m) { - uint16_t type; - - assert_return(m, -EINVAL); - assert_return(m->container_pos, -EINVAL); - - memcpy(&type, m->container_pos, sizeof(uint16_t)); - - type |= htons(((m->pdu + m->length) - (m->container_pos + 2)) & 0x01ff); - memcpy(m->container_pos, &type, sizeof(uint16_t)); - - return 0; -} - -static inline int tlv_packet_read_internal(tlv_section *m, void **data) { - - assert_return(m->read_pos, -EINVAL); - - *data = m->read_pos; - - return 0; -} - -int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(data, val, sizeof(uint8_t)); - - m->container->read_pos ++; - - return 0; -} - -int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) { - uint16_t t; - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(&t, val, sizeof(uint16_t)); - *data = ntohs(t); - - m->container->read_pos += 2; - - return 0; -} - -int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) { - uint32_t t; - void *val; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(&t, val, sizeof(uint32_t)); - *data = ntohl(t); - - m->container->read_pos += 4; - - return r; -} - -int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - *data = (char *) val; - *data_length = m->container->data + m->container->length - m->container->read_pos; - - m->container->read_pos += *data_length; - - return 0; -} - -int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - *data = (uint8_t *) val; - *data_length = m->container->data + m->container->length - m->container->read_pos; - - m->container->read_pos += *data_length; - - return 0; -} - -/* parse raw TLV packet */ -int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { - tlv_section *section, *tail; - uint16_t t, l; - uint8_t *p; - int r; - - assert_return(m, -EINVAL); - assert_return(size, -EINVAL); - - p = m->pdu; - - /* extract Ethernet header */ - memcpy(&m->mac, p, ETH_ALEN); - p += sizeof(struct ether_header); - - for (l = 0; l <= size; ) { - r = tlv_section_new(§ion); - if (r < 0) - return r; - - memcpy(&t, p, sizeof(uint16_t)); - - section->type = ntohs(t) >> 9; - section->length = ntohs(t) & 0x01ff; - - if (section->type == LLDP_TYPE_END || section->type >=_LLDP_TYPE_MAX) { - tlv_section_free(section); - break; - } - - p += 2; - - if (section->type == LLDP_TYPE_PRIVATE && - section->length >= LLDP_OUI_LEN + 1) { - section->oui = p; - p += LLDP_OUI_LEN; - section->subtype = *p++; - - section->length -= LLDP_OUI_LEN + 1; - l += LLDP_OUI_LEN + 1; - } - - section->data = p; - - LIST_FIND_TAIL(section, m->sections, tail); - LIST_INSERT_AFTER(section, m->sections, tail, section); - - p += section->length; - l += (section->length + 2); - } - - return 0; -} - -int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) { - tlv_section *s; - - assert_return(m, -EINVAL); - assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL); - - LIST_FOREACH(section, s, m->sections) - if (s->type == type) - break; - if (!s) - return -1; - - m->container = s; - - m->container->read_pos = s->data; - if (!m->container->read_pos) { - m->container = NULL; - return -1; - } - - return 0; -} - -int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) { - tlv_section *s; - - assert_return(m, -EINVAL); - assert_return(oui, -EINVAL); - - LIST_FOREACH(section, s, m->sections) { - if (s->type == LLDP_TYPE_PRIVATE && - s->oui && - s->subtype == subtype && - !memcmp(s->oui, oui, LLDP_OUI_LEN)) - break; - } - - if (!s) - return -1; - - m->container = s; - - m->container->read_pos = s->data; - if (!m->container->read_pos) { - m->container = NULL; - return -1; - } - - return 0; -} - -int lldp_tlv_packet_exit_container(tlv_packet *m) { - assert_return(m, -EINVAL); - - m->container = 0; - - return 0; -} - -static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, type); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, value); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) { - char *s; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, type); - if (r < 0) - return r; - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (char *) s; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_chassis_id(tlv_packet *tlv, - uint8_t *type, - uint8_t **data, - uint16_t *length) { - uint8_t subtype; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, &subtype); - if (r < 0) - goto out; - - switch (subtype) { - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - - r = tlv_packet_read_bytes(tlv, data, length); - if (r < 0) - goto out; - - break; - default: - r = -EOPNOTSUPP; - break; - } - - *type = subtype; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_port_id(tlv_packet *tlv, - uint8_t *type, - uint8_t **data, - uint16_t *length) { - uint8_t subtype; - char *s; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, &subtype); - if (r < 0) - goto out; - - switch (subtype) { - case LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (uint8_t *) s; - - break; - case LLDP_PORT_SUBTYPE_MAC_ADDRESS: - - r = tlv_packet_read_bytes(tlv, data, length); - if (r < 0) - goto out; - - break; - default: - r = -EOPNOTSUPP; - break; - } - - *type = subtype; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) { - return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl); -} - -int sd_lldp_packet_read_system_name(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length); -} - -int sd_lldp_packet_read_system_description(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length); -} - -int sd_lldp_packet_read_port_description(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length); -} - -int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) { - return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data); -} - -int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, id); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, flags); - if (r >= 0) - r = tlv_packet_read_u16(tlv, id); - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) { - int r, r2; - uint8_t len = 0; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, vlan_id); - if (r >= 0) - r = tlv_packet_read_u8(tlv, &len); - if (r >= 0) - r = tlv_packet_read_string(tlv, name, length); - - if (r >= 0 && len < *length) - *length = len; - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, id); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, status); - if (r >= 0) - r = tlv_packet_read_u32(tlv, id); - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) { - assert_return(tlv, -EINVAL); - assert_return(dest, -EINVAL); - - /* 802.1AB-2009, Table 7-1 */ - if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE; - else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE; - else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE; - else - return -EINVAL; - - return 0; -} diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h deleted file mode 100644 index 8e7706c612..0000000000 --- a/src/libsystemd-network/lldp-tlv.h +++ /dev/null @@ -1,94 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - 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 - -#include <net/ethernet.h> - -#include "sd-lldp.h" - -#include "list.h" -#include "lldp.h" -#include "util.h" - -typedef struct sd_lldp_packet tlv_packet; -typedef struct sd_lldp_section tlv_section; - -#define LLDP_OUI_LEN 3 - -struct sd_lldp_section { - uint16_t type; - uint16_t length; - uint8_t *oui; - uint8_t subtype; - - uint8_t *read_pos; - uint8_t *data; - - LIST_FIELDS(tlv_section, section); -}; - -#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } -#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 } -#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 } - -int tlv_section_new(tlv_section **ret); -void tlv_section_free(tlv_section *ret); - -struct sd_lldp_packet { - unsigned n_ref; - - uint16_t type; - uint16_t length; - usec_t ts; - - uint8_t *container_pos; - uint8_t pdu[ETHER_MAX_LEN]; - - void *userdata; - - struct ether_addr mac; - tlv_section *container; - - LIST_HEAD(tlv_section, sections); -}; - -int tlv_packet_new(tlv_packet **ret); - -int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); -int lldp_tlv_packet_close_container(tlv_packet *m); - -int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length); -int tlv_packet_append_u8(tlv_packet *m, uint8_t data); -int tlv_packet_append_u16(tlv_packet *m, uint16_t data); -int tlv_packet_append_u32(tlv_packet *m, uint32_t data); -int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size); - -int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type); -int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype); -int lldp_tlv_packet_exit_container(tlv_packet *m); - -int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length); -int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length); -int tlv_packet_read_u8(tlv_packet *m, uint8_t *data); -int tlv_packet_read_u16(tlv_packet *m, uint16_t *data); -int tlv_packet_read_u32(tlv_packet *m, uint32_t *data); - -int tlv_packet_parse_pdu(tlv_packet *t, uint16_t size); diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h deleted file mode 100644 index d2c7164633..0000000000 --- a/src/libsystemd-network/lldp.h +++ /dev/null @@ -1,126 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - 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 - -#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } - -#define ETHERTYPE_LLDP 0x88cc - -/* IEEE 802.3AB Clause 9: TLV Types */ -typedef enum LLDPTypes { - LLDP_TYPE_END = 0, - LLDP_TYPE_CHASSIS_ID = 1, - LLDP_TYPE_PORT_ID = 2, - LLDP_TYPE_TTL = 3, - LLDP_TYPE_PORT_DESCRIPTION = 4, - LLDP_TYPE_SYSTEM_NAME = 5, - LLDP_TYPE_SYSTEM_DESCRIPTION = 6, - LLDP_TYPE_SYSTEM_CAPABILITIES = 7, - LLDP_TYPE_MGMT_ADDRESS = 8, - LLDP_TYPE_PRIVATE = 127, - _LLDP_TYPE_MAX, - _LLDP_TYPE_INVALID = -1, -} LLDPTypes; - -/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ -typedef enum LLDPChassisSubtypes { - LLDP_CHASSIS_SUBTYPE_RESERVED = 0, - LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, - LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2, - LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3, - LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4, - LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, - LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, - LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, - _LLDP_CHASSIS_SUBTYPE_MAX, - _LLDP_CHASSIS_SUBTYPE_INVALID = -1, -} LLDPChassisSubtypes; - -/* IEEE 802.3AB Clause 9.5.3: Port subtype */ -typedef enum LLDPPortSubtypes { - LLDP_PORT_SUBTYPE_RESERVED = 0, - LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, - LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, - LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, - LLDP_PORT_SUBTYPE_NETWORK = 4, - LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, - LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, - LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, - _LLDP_PORT_SUBTYPE_MAX, - _LLDP_PORT_SUBTYPE_INVALID = -1 -} LLDPPortSubtypes; - -typedef enum LLDPSystemCapabilities { - LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, - LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, - LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, - LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3, - LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4, - LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5, - LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6, - LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, - LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, - LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, - LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, - _LLDP_SYSTEM_CAPABILITIES_MAX, - _LLDP_SYSTEM_CAPABILITIES_INVALID = -1, -} LLDPSystemCapabilities; - -typedef enum LLDPMedSubtype { - LLDP_MED_SUBTYPE_RESERVED = 0, - LLDP_MED_SUBTYPE_CAPABILITIES = 1, - LLDP_MED_SUBTYPE_NETWORK_POLICY = 2, - LLDP_MED_SUBTYPE_LOCATION_ID = 3, - LLDP_MED_SUBTYPE_EXTENDED_PVMDI = 4, - LLDP_MED_SUBTYPE_INV_HWREV = 5, - LLDP_MED_SUBTYPE_INV_FWREV = 6, - LLDP_MED_SUBTYPE_INV_SWREV = 7, - LLDP_MED_SUBTYPE_INV_SERIAL = 8, - LLDP_MED_SUBTYPE_INV_MANUFACTURER = 9, - LLDP_MED_SUBTYPE_INV_MODELNAME = 10, - LLDP_MED_SUBTYPE_INV_ASSETID = 11, - _LLDP_MED_SUBTYPE_MAX, - _LLDP_MED_SUBTYPE_INVALID = -1, -} LLDPMedSubtype; - -typedef enum LLDPMedCapability { - LLDP_MED_CAPABILITY_CAPAPILITIES = 1 << 0, - LLDP_MED_CAPABILITY_NETWORK_POLICY = 1 << 1, - LLDP_MED_CAPABILITY_LOCATION_ID = 1 << 2, - LLDP_MED_CAPABILITY_EXTENDED_PSE = 1 << 3, - LLDP_MED_CAPABILITY_EXTENDED_PD = 1 << 4, - LLDP_MED_CAPABILITY_INVENTORY = 1 << 5, - LLDP_MED_CAPABILITY_MAX, - LLDP_MED_CAPABILITY_INVALID = -1, -} LLDPMedCapability; - -#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } -#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } - -enum { - LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1, - LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2, - LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3, - LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4, - LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5, - LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6, - LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7, -}; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index fdafcd84d8..0e2d757b2b 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -335,6 +335,35 @@ int config_parse_hwaddr(const char *unit, return 0; } +int config_parse_iaid(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + uint32_t iaid; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou32(rvalue, &iaid); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); + return r; + } + + *((uint32_t *)data) = iaid; + + return 0; +} + void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { unsigned i; @@ -375,7 +404,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { if (r <= 0) continue; - size ++; + size++; } *ret = addresses; @@ -482,7 +511,7 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t return -ENOMEM; entry = strndup(word, len); - if(!entry) + if (!entry) return -ENOMEM; tok = entry; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index c8a531ab0f..72432774d7 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -62,6 +62,10 @@ int config_parse_ifalias(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_iaid(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 62099dd3f4..287b6e26fa 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,7 +82,7 @@ struct sd_dhcp_client { } _packed_ ll; struct { /* 255: Node-specific (RFC 4361) */ - uint32_t iaid; + be32_t iaid; struct duid duid; } _packed_ ns; struct { @@ -101,7 +101,7 @@ struct sd_dhcp_client { sd_event_source *timeout_t1; sd_event_source *timeout_t2; sd_event_source *timeout_expire; - sd_dhcp_client_cb_t cb; + sd_dhcp_client_callback_t cb; void *userdata; sd_dhcp_lease *lease; usec_t start_delay; @@ -121,7 +121,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd, uint32_t revents, void *userdata); static void client_stop(sd_dhcp_client *client, int error); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, +int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb, void *userdata) { assert_return(client, -EINVAL); @@ -298,6 +298,52 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, + uint16_t duid_type, uint8_t *duid, size_t duid_len) { + DHCP_CLIENT_DONT_DESTROY(client); + int r; + assert_return(client, -EINVAL); + zero(client->client_id); + + client->client_id.type = 255; + + /* If IAID is not configured, generate it. */ + if (iaid == 0) { + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, + client->mac_addr_len, + &client->client_id.ns.iaid); + if (r < 0) + return r; + } else + client->client_id.ns.iaid = htobe32(iaid); + + /* If DUID is not configured, generate DUID-EN. */ + if (duid_len == 0) { + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, + &duid_len); + if (r < 0) + return r; + } else { + r = dhcp_validate_duid_len(client->client_id.type, duid_len); + if (r < 0) + return r; + client->client_id.ns.duid.type = htobe16(duid_type); + memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); + duid_len += sizeof(client->client_id.ns.duid.type); + } + + client->client_id_len = sizeof(client->client_id.type) + duid_len + + sizeof(client->client_id.ns.iaid); + + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { + log_dhcp_client(client, "Configured IAID+DUID, restarting."); + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + sd_dhcp_client_start(client); + } + + return 0; +} + int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname) { char *new_hostname = NULL; @@ -408,7 +454,7 @@ static void client_stop(sd_dhcp_client *client, int error) { static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, uint8_t type, size_t *_optlen, size_t *_optoffset) { - _cleanup_free_ DHCPPacket *packet; + _cleanup_free_ DHCPPacket *packet = NULL; size_t optlen, optoffset, size; be16_t max_size; usec_t time_now; @@ -1691,8 +1737,7 @@ int sd_dhcp_client_stop(sd_dhcp_client *client) { return 0; } -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, - int priority) { +int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) { int r; assert_return(client, -EINVAL); diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 7a119fd488..ef50ed17a1 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -825,7 +825,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); if (r >= 0) { - _cleanup_free_ char *client_id_hex; + _cleanup_free_ char *client_id_hex = NULL; client_id_hex = hexmem(client_id, client_id_len); if (!client_id_hex) { diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 54ff1a3f28..9adf8ec19d 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -208,8 +208,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) { return 0; } -int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, - int priority) { +int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) { int r; assert_return(server, -EINVAL); @@ -281,10 +280,11 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, } static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination, + uint16_t destination_port, DHCPMessage *message, size_t len) { union sockaddr_union dest = { .in.sin_family = AF_INET, - .in.sin_port = htobe16(DHCP_PORT_CLIENT), + .in.sin_port = htobe16(destination_port), .in.sin_addr.s_addr = destination, }; struct iovec iov = { @@ -343,6 +343,7 @@ int dhcp_server_send_packet(sd_dhcp_server *server, DHCPRequest *req, DHCPPacket *packet, int type, size_t optoffset) { be32_t destination = INADDR_ANY; + uint16_t destination_port = DHCP_PORT_CLIENT; int r; assert(server); @@ -387,17 +388,19 @@ int dhcp_server_send_packet(sd_dhcp_server *server, */ if (req->message->giaddr) { destination = req->message->giaddr; + destination_port = DHCP_PORT_SERVER; if (type == DHCP_NAK) packet->dhcp.flags = htobe16(0x8000); } else if (req->message->ciaddr && type != DHCP_NAK) destination = req->message->ciaddr; if (destination != INADDR_ANY) - return dhcp_server_send_udp(server, destination, &packet->dhcp, + return dhcp_server_send_udp(server, destination, + destination_port, &packet->dhcp, sizeof(DHCPMessage) + optoffset); else if (requested_broadcast(req) || type == DHCP_NAK) return dhcp_server_send_udp(server, INADDR_BROADCAST, - &packet->dhcp, + destination_port, &packet->dhcp, sizeof(DHCPMessage) + optoffset); else /* we cannot send UDP packet to specific MAC address when the @@ -580,7 +583,8 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN); - r = dhcp_server_send_udp(server, address, &packet->dhcp, + r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT, + &packet->dhcp, sizeof(DHCPMessage) + optoffset); if (r < 0) return r; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 7d56d4cc60..ee4fb4fc1e 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -64,7 +64,7 @@ struct sd_dhcp6_client { uint8_t retransmit_count; sd_event_source *timeout_resend; sd_event_source *timeout_resend_expire; - sd_dhcp6_client_cb_t cb; + sd_dhcp6_client_callback_t cb; void *userdata; struct duid duid; size_t duid_len; @@ -111,7 +111,7 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int); static int client_start(sd_dhcp6_client *client, enum DHCP6State state); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) { +int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_callback_t cb, void *userdata) { assert_return(client, -EINVAL); client->cb = cb; @@ -180,41 +180,29 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid( - sd_dhcp6_client *client, - uint16_t type, - uint8_t *duid, size_t duid_len) { +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, + uint8_t *duid, size_t duid_len) { + int r; assert_return(client, -EINVAL); - assert_return(duid, -EINVAL); - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - switch (type) { - case DHCP6_DUID_LLT: - if (duid_len <= sizeof(client->duid.llt)) - return -EINVAL; - break; - case DHCP6_DUID_EN: - if (duid_len != sizeof(client->duid.en)) - return -EINVAL; - break; - case DHCP6_DUID_LL: - if (duid_len <= sizeof(client->duid.ll)) - return -EINVAL; - break; - case DHCP6_DUID_UUID: - if (duid_len != sizeof(client->duid.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; + if (duid_len > 0) { + r = dhcp_validate_duid_len(duid_type, duid_len); + if (r < 0) + return r; + client->duid.type = htobe16(duid_type); + memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = duid_len + sizeof(client->duid.type); } - client->duid.type = htobe16(type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + sizeof(client->duid.type); + return 0; +} + +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) { + assert_return(client, -EINVAL); + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->ia_na.id = htobe32(iaid); return 0; } @@ -1204,7 +1192,7 @@ error: return r; } -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) { +int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) { int r; assert_return(client, -EINVAL); diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index f7880a891c..cc7436db6b 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -92,7 +92,7 @@ struct sd_ipv4acd { struct ether_addr mac_addr; sd_event *event; int event_priority; - sd_ipv4acd_cb_t cb; + sd_ipv4acd_callback_t cb; void* userdata; }; @@ -428,7 +428,7 @@ int sd_ipv4acd_detach_event(sd_ipv4acd *ll) { return 0; } -int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) { +int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) { int r; assert_return(ll, -EINVAL); @@ -447,7 +447,7 @@ int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) { return 0; } -int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) { +int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) { assert_return(ll, -EINVAL); ll->cb = cb; @@ -456,7 +456,7 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) return 0; } -int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){ +int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address) { assert_return(ll, -EINVAL); assert_return(address, -EINVAL); assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index db6cf22aaa..2a06418c53 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -52,7 +52,7 @@ struct sd_ipv4ll { /* External */ be32_t claimed_address; - sd_ipv4ll_cb_t cb; + sd_ipv4ll_callback_t cb; void* userdata; }; @@ -160,7 +160,7 @@ int sd_ipv4ll_detach_event(sd_ipv4ll *ll) { return sd_ipv4acd_detach_event(ll->acd); } -int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) { +int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) { int r; assert_return(ll, -EINVAL); @@ -172,7 +172,7 @@ int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) { return 0; } -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) { +int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) { assert_return(ll, -EINVAL); ll->cb = cb; @@ -181,7 +181,7 @@ int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) { return 0; } -int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){ +int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) { assert_return(ll, -EINVAL); assert_return(address, -EINVAL); diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 885ca62425..9d4587c80e 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -1,21 +1,21 @@ /*** - This file is part of systemd. + This file is part of systemd. - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. + You 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> @@ -24,733 +24,473 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" -#include "hashmap.h" #include "lldp-internal.h" -#include "lldp-port.h" -#include "lldp-tlv.h" -#include "prioq.h" -#include "siphash24.h" -#include "string-util.h" - -typedef enum LLDPAgentRXState { - LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4, - LLDP_AGENT_RX_DELETE_AGED_INFO, - LLDP_AGENT_RX_LLDP_INITIALIZE, - LLDP_AGENT_RX_WAIT_FOR_FRAME, - LLDP_AGENT_RX_RX_FRAME, - LLDP_AGENT_RX_DELETE_INFO, - LLDP_AGENT_RX_UPDATE_INFO, - _LLDP_AGENT_RX_STATE_MAX, - _LLDP_AGENT_RX_INVALID = -1, -} LLDPAgentRXState; - -/* Section 10.5.2.2 Reception counters */ -struct lldp_agent_statistics { - uint64_t stats_ageouts_total; - uint64_t stats_frames_discarded_total; - uint64_t stats_frames_in_errors_total; - uint64_t stats_frames_in_total; - uint64_t stats_tlvs_discarded_total; - uint64_t stats_tlvs_unrecognized_total; -}; - -struct sd_lldp { - lldp_port *port; - - Prioq *by_expiry; - Hashmap *neighbour_mib; - - sd_lldp_cb_t cb; - - void *userdata; - - LLDPAgentRXState rx_state; - lldp_agent_statistics statistics; -}; - -static void chassis_id_hash_func(const void *p, struct siphash *state) { - const lldp_chassis_id *id = p; - - assert(id); - assert(id->data); - - siphash24_compress(&id->length, sizeof(id->length), state); - siphash24_compress(id->data, id->length, state); -} +#include "lldp-neighbor.h" +#include "lldp-network.h" +#include "socket-util.h" +#include "ether-addr-util.h" -static int chassis_id_compare_func(const void *_a, const void *_b) { - const lldp_chassis_id *a, *b; +#define LLDP_DEFAULT_NEIGHBORS_MAX 128U - a = _a; - b = _b; +static void lldp_flush_neighbors(sd_lldp *lldp) { + sd_lldp_neighbor *n; - assert(!a->length || a->data); - assert(!b->length || b->data); + assert(lldp); - if (a->type != b->type) - return -1; + while ((n = hashmap_first(lldp->neighbor_by_id))) + lldp_neighbor_unlink(n); +} - if (a->length != b->length) - return a->length < b->length ? -1 : 1; +static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { + assert(lldp); + assert(n); - return memcmp(a->data, b->data, a->length); -} + log_lldp("Invoking callback for '%c'.", event); -static const struct hash_ops chassis_id_hash_ops = { - .hash = chassis_id_hash_func, - .compare = chassis_id_compare_func -}; + if (!lldp->callback) + return; -static void lldp_mib_delete_objects(sd_lldp *lldp); -static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state); -static void lldp_run_state_machine(sd_lldp *ll); + lldp->callback(lldp, event, n, lldp->userdata); +} -static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { - int r; +static int lldp_make_space(sd_lldp *lldp, size_t extra) { + usec_t t = USEC_INFINITY; + bool changed = false; assert(lldp); - assert(tlv); - - /* Remove expired packets */ - if (prioq_size(lldp->by_expiry) > 0) { - lldp_set_state(lldp, LLDP_AGENT_RX_DELETE_INFO); + /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries + * are free. */ - lldp_mib_delete_objects(lldp); - } + for (;;) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; - r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv); - if (r < 0) - goto out; + n = prioq_peek(lldp->neighbor_by_expiry); + if (!n) + break; - lldp_set_state(lldp, LLDP_AGENT_RX_UPDATE_INFO); + sd_lldp_neighbor_ref(n); - log_lldp("Packet added. MIB size: %d , PQ size: %d", - hashmap_size(lldp->neighbour_mib), - prioq_size(lldp->by_expiry)); + if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra)) + goto remove_one; - lldp->statistics.stats_frames_in_total ++; + if (t == USEC_INFINITY) + t = now(clock_boottime_or_monotonic()); - out: - if (r < 0) - log_lldp("Receive frame failed: %s", strerror(-r)); + if (n->until > t) + break; - lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); + remove_one: + lldp_neighbor_unlink(n); + lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); + changed = true; + } - return 0; + return changed; } -/* 10.3.2 LLDPDU validation: rxProcessFrame() */ -int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { - bool system_description = false, system_name = false, chassis_id = false; - bool malformed = false, port_id = false, ttl = false, end = false; - uint16_t type, len, i, l, t; - lldp_port *port; - uint8_t *p, *q; - sd_lldp *lldp; - int r; - - assert(tlv); - assert(length > 0); - - port = (lldp_port *) tlv->userdata; - lldp = (sd_lldp *) port->userdata; - - if (lldp->port->status == LLDP_PORT_STATUS_DISABLED) { - log_lldp("Port: %s is disabled. Dropping.", lldp->port->ifname); - goto out; - } +static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { + assert(lldp); + assert(n); - lldp_set_state(lldp, LLDP_AGENT_RX_RX_FRAME); + /* Don't keep data with a zero TTL */ + if (n->ttl <= 0) + return false; - p = tlv->pdu; - p += sizeof(struct ether_header); + /* Filter out data from the filter address */ + if (!ether_addr_is_null(&lldp->filter_address) && + ether_addr_equal(&lldp->filter_address, &n->source_address)) + return false; - for (i = 1, l = 0; l <= length; i++) { + /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with + * no caps field set. */ + if (n->has_capabilities && + (n->enabled_capabilities & lldp->capability_mask) == 0) + return false; - memcpy(&t, p, sizeof(uint16_t)); + /* Keep everything else */ + return true; +} - type = ntohs(t) >> 9; - len = ntohs(t) & 0x01ff; +static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor); - if (type == LLDP_TYPE_END) { - if (len != 0) { - log_lldp("TLV type end must be length 0 (not %d). Dropping.", len); +static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL; + bool keep; + int r; - malformed = true; - goto out; - } + assert(lldp); + assert(n); + assert(!n->lldp); - end = true; + keep = lldp_keep_neighbor(lldp, n); - break; - } else if (type >=_LLDP_TYPE_MAX) { - log_lldp("TLV type: %d not recognized. Dropping.", type); + /* First retrieve the old entry for this MSAP */ + old = hashmap_get(lldp->neighbor_by_id, &n->id); + if (old) { + sd_lldp_neighbor_ref(old); - malformed = true; - goto out; + if (!keep) { + lldp_neighbor_unlink(old); + lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old); + return 0; } - /* skip type and length encoding */ - p += 2; - q = p; - - p += len; - l += (len + 2); + if (lldp_neighbor_equal(n, old)) { + /* Is this equal, then restart the TTL counter, but don't do anyting else. */ + lldp_start_timer(lldp, old); + lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); + return 0; + } - if (i <= 3) { - if (i != type) { - log_lldp("TLV missing or out of order. Dropping."); + /* Data changed, remove the old entry, and add a new one */ + lldp_neighbor_unlink(old); - malformed = true; - goto out; - } - } + } else if (!keep) + return 0; - switch(type) { - case LLDP_TYPE_CHASSIS_ID: + /* Then, make room for at least one new neighbor */ + lldp_make_space(lldp, 1); - if (len < 2) { - log_lldp("Received malformed Chassis ID TLV length: %d. Dropping.", len); + r = hashmap_put(lldp->neighbor_by_id, &n->id, n); + if (r < 0) + goto finish; - malformed = true; - goto out; - } + r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx); + if (r < 0) { + assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n); + goto finish; + } - if (chassis_id) { - log_lldp("Duplicate Chassis ID TLV found. Dropping."); + n->lldp = lldp; - malformed = true; - goto out; - } + lldp_start_timer(lldp, n); + lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n); - /* Look what subtype it has */ - if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) { - log_lldp("Unknown subtype: %d found in Chassis ID TLV. Dropping.", *q); + return 1; - malformed = true; - goto out; +finish: + if (old) + lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); - } + return r; +} - chassis_id = true; +static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { + int r; - break; - case LLDP_TYPE_PORT_ID: + assert(lldp); + assert(n); - if (len < 2) { - log_lldp("Received malformed Port ID TLV length: %d. Dropping.", len); + r = lldp_neighbor_parse(n); + if (r == -EBADMSG) /* Ignore bad messages */ + return 0; + if (r < 0) + return r; - malformed = true; - goto out; - } + r = lldp_add_neighbor(lldp, n); + if (r < 0) { + log_lldp_errno(r, "Failed to add datagram. Ignoring."); + return 0; + } - if (port_id) { - log_lldp("Duplicate Port ID TLV found. Dropping."); + log_lldp("Successfully processed LLDP datagram."); + return 0; +} - malformed = true; - goto out; - } +static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + ssize_t space, length; + sd_lldp *lldp = userdata; - /* Look what subtype it has */ - if (*q == LLDP_PORT_SUBTYPE_RESERVED || *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) { - log_lldp("Unknown subtype: %d found in Port ID TLV. Dropping.", *q); + assert(fd >= 0); + assert(lldp); - malformed = true; - goto out; + space = next_datagram_size_fd(fd); + if (space < 0) + return log_lldp_errno(space, "Failed to determine datagram size to read: %m"); - } + n = lldp_neighbor_new(space); + if (!n) + return -ENOMEM; - port_id = true; + length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT); + if (length < 0) + return log_lldp_errno(errno, "Failed to read LLDP datagram: %m"); - break; - case LLDP_TYPE_TTL: + if ((size_t) length != n->raw_size) { + log_lldp("Packet size mismatch."); + return -EINVAL; + } - if(len != 2) { - log_lldp("Received invalid TTL TLV lenth: %d. Dropping.", len); + return lldp_handle_datagram(lldp, n); +} - malformed = true; - goto out; - } +_public_ int sd_lldp_start(sd_lldp *lldp) { + int r; - if (ttl) { - log_lldp("Duplicate TTL TLV found. Dropping."); + assert_return(lldp, -EINVAL); - malformed = true; - goto out; - } + if (lldp->fd >= 0) + return 0; - ttl = true; + assert(!lldp->io_event_source); - break; - case LLDP_TYPE_SYSTEM_NAME: + lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex); + if (lldp->fd < 0) + return lldp->fd; - /* According to RFC 1035 the length of a FQDN is limited to 255 characters */ - if (len > 255) { - log_lldp("Received invalid system name length: %d. Dropping.", len); - malformed = true; - goto out; - } + if (lldp->event) { + r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); + if (r < 0) + goto fail; - if (system_name) { - log_lldp("Duplicate system name found. Dropping."); - malformed = true; - goto out; - } + r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); + if (r < 0) + goto fail; - system_name = true; + (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); + } - break; - case LLDP_TYPE_SYSTEM_DESCRIPTION: - - /* 0 <= n <= 255 octets */ - if (len > 255) { - log_lldp("Received invalid system description length: %d. Dropping.", len); - malformed = true; - goto out; - } - - if (system_description) { - log_lldp("Duplicate system description found. Dropping."); - malformed = true; - goto out; - } - - system_description = true; - break; - default: + return 1; - if (len == 0) { - log_lldp("TLV type: %d length 0 received. Dropping.", type); +fail: + lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); + lldp->fd = safe_close(lldp->fd); - malformed = true; - goto out; - } - break; - } - } + return r; +} - if(!chassis_id || !port_id || !ttl || !end) { - log_lldp("One or more mandatory TLV missing. Dropping."); +_public_ int sd_lldp_stop(sd_lldp *lldp) { + assert_return(lldp, -EINVAL); - malformed = true; - goto out; + if (lldp->fd < 0) + return 0; - } + lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); + lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); + lldp->fd = safe_close(lldp->fd); - r = tlv_packet_parse_pdu(tlv, length); - if (r < 0) { - log_lldp("Failed to parse the TLV. Dropping."); + lldp_flush_neighbors(lldp); - malformed = true; - goto out; - } + return 1; +} - return lldp_receive_frame(lldp, tlv); +_public_ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { + int r; - out: - lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); + assert_return(lldp, -EINVAL); + assert_return(lldp->fd < 0, -EBUSY); + assert_return(!lldp->event, -EBUSY); - if (malformed) { - lldp->statistics.stats_frames_discarded_total ++; - lldp->statistics.stats_frames_in_errors_total ++; + if (event) + lldp->event = sd_event_ref(event); + else { + r = sd_event_default(&lldp->event); + if (r < 0) + return r; } - sd_lldp_packet_unref(tlv); + lldp->event_priority = priority; return 0; } -static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) { - const lldp_neighbour_port *p = a, *q = b; +_public_ int sd_lldp_detach_event(sd_lldp *lldp) { - if (p->until < q->until) - return -1; - - if (p->until > q->until) - return 1; + assert_return(lldp, -EINVAL); + assert_return(lldp->fd < 0, -EBUSY); + lldp->event = sd_event_unref(lldp->event); return 0; } -static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state) { - - assert(lldp); - assert(state < _LLDP_AGENT_RX_STATE_MAX); +_public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { + assert_return(lldp, -EINVAL); - lldp->rx_state = state; + lldp->callback = cb; + lldp->userdata = userdata; - lldp_run_state_machine(lldp); + return 0; } -static void lldp_run_state_machine(sd_lldp *lldp) { - if (!lldp->cb) - return; - - switch (lldp->rx_state) { - case LLDP_AGENT_RX_UPDATE_INFO: - lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata); - break; - default: - break; - } -} +_public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { -/* 10.5.5.2.1 mibDeleteObjects () - * The mibDeleteObjects () procedure deletes all information in the LLDP remote - * systems MIB associated with the MSAP identifier if an LLDPDU is received with - * an rxTTL value of zero (see 10.3.2) or the timing counter rxInfoTTL expires. */ + if (!lldp) + return NULL; -static void lldp_mib_delete_objects(sd_lldp *lldp) { - lldp_neighbour_port *p; - usec_t t = 0; + lldp_flush_neighbors(lldp); - /* Remove all entries that are past their TTL */ - for (;;) { + hashmap_free(lldp->neighbor_by_id); + prioq_free(lldp->neighbor_by_expiry); - if (prioq_size(lldp->by_expiry) <= 0) - break; + sd_event_source_unref(lldp->io_event_source); + sd_event_source_unref(lldp->timer_event_source); + sd_event_unref(lldp->event); + safe_close(lldp->fd); - p = prioq_peek(lldp->by_expiry); - if (!p) - break; + free(lldp); - if (t <= 0) - t = now(clock_boottime_or_monotonic()); + return NULL; +} - if (p->until > t) - break; +_public_ int sd_lldp_new(sd_lldp **ret, int ifindex) { + _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; + int r; - lldp_neighbour_port_remove_and_free(p); + assert_return(ret, -EINVAL); + assert_return(ifindex > 0, -EINVAL); - lldp->statistics.stats_ageouts_total ++; - } -} + lldp = new0(sd_lldp, 1); + if (!lldp) + return -ENOMEM; -static void lldp_mib_objects_flush(sd_lldp *lldp) { - lldp_neighbour_port *p, *q; - lldp_chassis *c; + lldp->fd = -1; + lldp->ifindex = ifindex; + lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX; + lldp->capability_mask = (uint16_t) -1; - assert(lldp); - assert(lldp->neighbour_mib); - assert(lldp->by_expiry); + lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops); + if (!lldp->neighbor_by_id) + return -ENOMEM; - /* Drop all packets */ - while ((c = hashmap_steal_first(lldp->neighbour_mib))) { + r = prioq_ensure_allocated(&lldp->neighbor_by_expiry, lldp_neighbor_prioq_compare_func); + if (r < 0) + return r; - LIST_FOREACH_SAFE(port, p, q, c->ports) { - lldp_neighbour_port_remove_and_free(p); - } - } + *ret = lldp; + lldp = NULL; - assert(hashmap_size(lldp->neighbour_mib) == 0); - assert(prioq_size(lldp->by_expiry) == 0); + return 0; } -int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - uint8_t *mac, *port_id, type; - lldp_neighbour_port *p; - uint16_t data = 0, length = 0; - char buf[LINE_MAX]; - lldp_chassis *c; - usec_t time; - Iterator i; - int r; +static int neighbor_compare_func(const void *a, const void *b) { + const sd_lldp_neighbor * const*x = a, * const *y = b; - assert(lldp); - assert(lldp_file); + return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id); +} - r = fopen_temporary(lldp_file, &f, &temp_path); - if (r < 0) - goto fail; - - fchmod(fileno(f), 0644); - - HASHMAP_FOREACH(c, lldp->neighbour_mib, i) { - LIST_FOREACH(port, p, c->ports) { - _cleanup_free_ char *s = NULL; - char *k, *t; - - r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length); - if (r < 0) - continue; - - sprintf(buf, "'_Chassis=%02x:%02x:%02x:%02x:%02x:%02x' '_CType=%d' ", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); - - s = strdup(buf); - if (!s) { - r = -ENOMEM; - goto fail; - } - - r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length); - if (r < 0) - continue; - - if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) { - k = strndup((char *) port_id, length -1); - if (!k) { - r = -ENOMEM; - goto fail; - } - - sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type); - free(k); - } else { - mac = port_id; - sprintf(buf, "'_Port=%02x:%02x:%02x:%02x:%02x:%02x' '_PType=%d' ", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); - } - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - time = now(clock_boottime_or_monotonic()); - - /* Don't write expired packets */ - if (time - p->until <= 0) - continue; - - sprintf(buf, "'_TTL="USEC_FMT"' ", p->until); - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - r = sd_lldp_packet_read_system_name(p->packet, &k, &length); - if (r < 0) - k = strappend(s, "'_NAME=N/A' "); - else { - t = strndup(k, length); - if (!t) { - r = -ENOMEM; - goto fail; - } - - k = strjoin(s, "'_NAME=", t, "' ", NULL); - free(t); - } - - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - (void) sd_lldp_packet_read_system_capability(p->packet, &data); - - sprintf(buf, "'_CAP=%x'", data); - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - fprintf(f, "%s\n", s); - } - } +static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { + sd_lldp *lldp = userdata; + int r, q; - r = fflush_and_check(f); + r = lldp_make_space(lldp, 0); if (r < 0) - goto fail; + return log_lldp_errno(r, "Failed to make space: %m"); - if (rename(temp_path, lldp_file) < 0) { - r = -errno; - goto fail; - } + q = lldp_start_timer(lldp, NULL); + if (q < 0) + return log_lldp_errno(q, "Failed to restart timer: %m"); return 0; - - fail: - if (temp_path) - (void) unlink(temp_path); - - return log_error_errno(r, "Failed to save lldp data %s: %m", lldp_file); } -int sd_lldp_start(sd_lldp *lldp) { +static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) { + sd_lldp_neighbor *n; int r; - assert_return(lldp, -EINVAL); - assert_return(lldp->port, -EINVAL); + assert(lldp); - lldp->port->status = LLDP_PORT_STATUS_ENABLED; + if (neighbor) + lldp_neighbor_start_ttl(neighbor); - lldp_set_state(lldp, LLDP_AGENT_RX_LLDP_INITIALIZE); + n = prioq_peek(lldp->neighbor_by_expiry); + if (!n) { - r = lldp_port_start(lldp->port); - if (r < 0) { - log_lldp("Failed to start Port : %s , %s", - lldp->port->ifname, - strerror(-r)); + if (lldp->timer_event_source) + return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF); - lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL); - - return r; + return 0; } - lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); - - return 0; -} - -int sd_lldp_stop(sd_lldp *lldp) { - int r; + if (lldp->timer_event_source) { + r = sd_event_source_set_time(lldp->timer_event_source, n->until); + if (r < 0) + return r; - assert_return(lldp, -EINVAL); - assert_return(lldp->port, -EINVAL); + return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT); + } - lldp->port->status = LLDP_PORT_STATUS_DISABLED; + if (!lldp->event) + return 0; - r = lldp_port_stop(lldp->port); + r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp); if (r < 0) return r; - lldp_mib_objects_flush(lldp); + r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority); + if (r < 0) + return r; + (void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer"); return 0; } -int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority) { - int r; +_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { + sd_lldp_neighbor **l = NULL, *n; + Iterator i; + int k = 0, r; assert_return(lldp, -EINVAL); - assert_return(!lldp->port->event, -EBUSY); + assert_return(ret, -EINVAL); - if (event) - lldp->port->event = sd_event_ref(event); - else { - r = sd_event_default(&lldp->port->event); - if (r < 0) - return r; + if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */ + *ret = NULL; + return 0; } - lldp->port->event_priority = priority; + l = new0(sd_lldp_neighbor*, hashmap_size(lldp->neighbor_by_id)); + if (!l) + return -ENOMEM; - return 0; -} + r = lldp_start_timer(lldp, NULL); + if (r < 0) { + free(l); + return r; + } -int sd_lldp_detach_event(sd_lldp *lldp) { + HASHMAP_FOREACH(n, lldp->neighbor_by_id, i) + l[k++] = sd_lldp_neighbor_ref(n); - assert_return(lldp, -EINVAL); + assert((size_t) k == hashmap_size(lldp->neighbor_by_id)); - lldp->port->event = sd_event_unref(lldp->port->event); + /* Return things in a stable order */ + qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func); + *ret = l; - return 0; + return k; } -int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata) { +_public_ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) { assert_return(lldp, -EINVAL); + assert_return(m <= 0, -EINVAL); - lldp->cb = cb; - lldp->userdata = userdata; + lldp->neighbors_max = m; + lldp_make_space(lldp, 0); return 0; } -sd_lldp* sd_lldp_unref(sd_lldp *lldp) { - - if (!lldp) - return NULL; - - /* Drop all packets */ - lldp_mib_objects_flush(lldp); - - lldp_port_free(lldp->port); - - hashmap_free(lldp->neighbour_mib); - prioq_free(lldp->by_expiry); - - free(lldp); - return NULL; -} - -int sd_lldp_new(int ifindex, - const char *ifname, - const struct ether_addr *mac, - sd_lldp **ret) { - _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; - int r; - - assert_return(ret, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - assert_return(ifname, -EINVAL); - assert_return(mac, -EINVAL); - - lldp = new0(sd_lldp, 1); - if (!lldp) - return -ENOMEM; - - r = lldp_port_new(ifindex, ifname, mac, lldp, &lldp->port); - if (r < 0) - return r; - - lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops); - if (!lldp->neighbour_mib) - return -ENOMEM; - - r = prioq_ensure_allocated(&lldp->by_expiry, - ttl_expiry_item_prioq_compare_func); - if (r < 0) - return r; - - lldp->rx_state = LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL; +_public_ int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) { + assert_return(lldp, -EINVAL); + assert_return(mask != 0, -EINVAL); - *ret = lldp; - lldp = NULL; + lldp->capability_mask = mask; return 0; } -int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) { - lldp_neighbour_port *p; - lldp_chassis *c; - Iterator iter; - unsigned count = 0, i; - +_public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *addr) { assert_return(lldp, -EINVAL); - assert_return(tlvs, -EINVAL); - HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { - LIST_FOREACH(port, p, c->ports) - count++; - } + /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so + * that our own can be filtered out here. */ - if (!count) { - *tlvs = NULL; + if (!addr) { + zero(lldp->filter_address); return 0; } - *tlvs = new(sd_lldp_packet *, count); - if (!*tlvs) - return -ENOMEM; - - i = 0; - HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { - LIST_FOREACH(port, p, c->ports) - (*tlvs)[i++] = sd_lldp_packet_ref(p->packet); - } - - return count; + lldp->filter_address = *addr; + return 0; } diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index bae6a49fe6..fb4ef55673 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -166,7 +166,7 @@ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { } -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) { +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { int r; assert_return(nd, -EINVAL); diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index b8490073dd..1aae2253c0 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -22,6 +22,7 @@ #include <net/ethernet.h> #include <stdio.h> #include <string.h> +#include <unistd.h> #include "sd-event.h" #include "sd-lldp.h" @@ -29,8 +30,6 @@ #include "alloc-util.h" #include "fd-util.h" #include "lldp-network.h" -#include "lldp-tlv.h" -#include "lldp.h" #include "macro.h" #include "string-util.h" @@ -38,211 +37,8 @@ #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp" #define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc" -static int test_fd[2]; - -static struct ether_addr mac_addr = { - .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} -}; - -static int lldp_build_tlv_packet(tlv_packet **ret) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *m = NULL; - const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR; - struct ether_header ether = { - .ether_type = htons(ETHERTYPE_LLDP), - }; - - /* Append Ethernet header */ - memcpy(ðer.ether_dhost, lldp_dst, ETHER_ADDR_LEN); - memcpy(ðer.ether_shost, &mac_addr, ETHER_ADDR_LEN); - - assert_se(tlv_packet_new(&m) >= 0); - - assert_se(tlv_packet_append_bytes(m, ðer, sizeof(struct ether_header)) >= 0); - - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0); - - assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0); - assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* port name */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0); - - assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0); - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* ttl */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0); - - assert_se(tlv_packet_append_u16(m, 170) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* system name */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0); - - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME, - strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0); - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* system descrition */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0); - - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC, - strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* Mark end of packet */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0); - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - *ret = m; - - m = NULL; - - return 0; -} - -static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) { - uint8_t *p, subtype; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0); - assert_se(tlv_packet_read_u8(m, &subtype) >= 0); - - switch (subtype) { - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - - *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS; - assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0); - - assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0); - - break; - default: - assert_not_reached("Unhandled option"); - } - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_port_id_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - uint8_t subtype; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0); - - assert_se(tlv_packet_read_u8(m, &subtype) >= 0); - - switch (subtype) { - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length-1); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_PORT) == 1); - break; - default: - assert_not_reached("Unhandled option"); - } - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_system_name_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0); - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 1; -} - -static int lldp_parse_system_desc_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0); - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_ttl_tlv(tlv_packet *m) { - uint16_t ttl; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0); - assert_se(tlv_packet_read_u16(m, &ttl) >= 0); - - assert_se(ttl == 170); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_get_destination_type(tlv_packet *m) { - int dest; - - assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0); - assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE); - - return 0; -} - -static int lldp_parse_tlv_packet(tlv_packet *m, int len) { - uint8_t subtype; - - assert_se(tlv_packet_parse_pdu(m, len) >= 0); - assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0); - assert_se(lldp_parse_port_id_tlv(m) >= 0); - assert_se(lldp_parse_system_name_tlv(m) >= 0); - assert_se(lldp_parse_ttl_tlv(m) >= 0); - assert_se(lldp_parse_system_desc_tlv(m) >= 0); - - assert_se(lldp_get_destination_type(m) >= 0); - - return 0; -} - -static void test_parser(void) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *tlv = NULL; - - /* form a packet */ - lldp_build_tlv_packet(&tlv); - /* parse the packet */ - tlv_packet_parse_pdu(tlv, tlv->length); - /* verify */ - lldp_parse_tlv_packet(tlv, tlv->length); -} +static int test_fd[2] = { -1, -1 }; +static int lldp_handler_calls; int lldp_network_bind_raw_socket(int ifindex) { if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0) @@ -251,28 +47,27 @@ int lldp_network_bind_raw_socket(int ifindex) { return test_fd[0]; } -static int lldp_handler_calls; -static void lldp_handler (sd_lldp *lldp, int event, void *userdata) { +static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) { lldp_handler_calls++; } -static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) { +static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) { int r; - r = sd_lldp_new(42, "dummy", &mac_addr, lldp); - if (r) + r = sd_lldp_new(lldp, 42); + if (r < 0) return r; r = sd_lldp_attach_event(*lldp, e, 0); - if (r) + if (r < 0) return r; r = sd_lldp_set_callback(*lldp, cb, cb_data); - if (r) + if (r < 0) return r; r = sd_lldp_start(*lldp); - if (r) + if (r < 0) return r; return 0; @@ -282,11 +77,11 @@ static int stop_lldp(sd_lldp *lldp) { int r; r = sd_lldp_stop(lldp); - if (r) + if (r < 0) return r; r = sd_lldp_detach_event(lldp); - if (r) + if (r < 0) return r; sd_lldp_unref(lldp); @@ -296,13 +91,8 @@ static int stop_lldp(sd_lldp *lldp) { } static void test_receive_basic_packet(sd_event *e) { - sd_lldp *lldp; - sd_lldp_packet **packets; - uint8_t type, *data; - uint16_t length, ttl; - int dest_type; - char *str; - uint8_t frame[] = { + + static const uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ @@ -319,51 +109,53 @@ static void test_receive_basic_packet(sd_event *e) { 0x00, 0x00 /* End Of LLDPDU */ }; + sd_lldp *lldp; + sd_lldp_neighbor **neighbors; + uint8_t type; + const void *data; + uint16_t ttl; + size_t length; + const char *str; + lldp_handler_calls = 0; assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0); assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 1); - assert_se(sd_lldp_get_packets(lldp, &packets) == 1); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1); - assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0); - assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS); + assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0); + assert_se(type == SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS); assert_se(length == ETH_ALEN); assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN)); - assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0); - assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME); + assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0); + assert_se(type == SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME); assert_se(length == 3); assert_se(strneq((char *) data, "1/3", 3)); - assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0); - assert_se(length == 4); - assert_se(strneq(str, "Port", 4)); + assert_se(sd_lldp_neighbor_get_port_description(neighbors[0], &str) == 0); + assert_se(streq(str, "Port")); - assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0); - assert_se(length == 3); - assert_se(strneq(str, "SYS", 3)); + assert_se(sd_lldp_neighbor_get_system_name(neighbors[0], &str) == 0); + assert_se(streq(str, "SYS")); - assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0); - assert_se(length == 4); /* This is the real length in the TLV packet */ - assert_se(strneq(str, "foo", 3)); + assert_se(sd_lldp_neighbor_get_system_description(neighbors[0], &str) == 0); + assert_se(streq(str, "foo")); - assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0); + assert_se(sd_lldp_neighbor_get_ttl(neighbors[0], &ttl) == 0); assert_se(ttl == 120); - assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0); - assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE); - - sd_lldp_packet_unref(packets[0]); - free(packets); + sd_lldp_neighbor_unref(neighbors[0]); + free(neighbors); assert_se(stop_lldp(lldp) == 0); } static void test_receive_incomplete_packet(sd_event *e) { sd_lldp *lldp; - sd_lldp_packet **packets; + sd_lldp_neighbor **neighbors; uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ @@ -383,18 +175,14 @@ static void test_receive_incomplete_packet(sd_event *e) { assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 0); - assert_se(sd_lldp_get_packets(lldp, &packets) == 0); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 0); assert_se(stop_lldp(lldp) == 0); } static void test_receive_oui_packet(sd_event *e) { sd_lldp *lldp; - sd_lldp_packet **packets; - uint32_t id32; - uint16_t id16, len; - uint8_t flags; - char *str; + sd_lldp_neighbor **neighbors; uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ @@ -426,29 +214,30 @@ static void test_receive_oui_packet(sd_event *e) { assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 1); - assert_se(sd_lldp_get_packets(lldp, &packets) == 1); - - assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0); - assert_se(id16 == 0x1234); - - assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0); - assert_se(flags == 1); - assert_se(id16 == 0x7788); - - assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0); - assert_se(id16 == 0x1234); - assert_se(len == 6); - assert_se(strneq(str, "Vlan51", 6)); - - assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0); - assert_se(id16 == 0x0102); - - assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0); - assert_se(flags == 1); - assert_se(id32 == 0x00140012); - - sd_lldp_packet_unref(packets[0]); - free(packets); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1); + + assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_CHASSIS_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_PORT_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_TTL) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_END) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0); + + sd_lldp_neighbor_unref(neighbors[0]); + free(neighbors); assert_se(stop_lldp(lldp) == 0); } @@ -456,7 +245,7 @@ static void test_receive_oui_packet(sd_event *e) { int main(int argc, char *argv[]) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; - test_parser(); + log_set_max_level(LOG_DEBUG); /* LLDP reception tests */ assert_se(sd_event_new(&e) == 0); diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 7c81e7a25d..5964a01c4f 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -198,7 +198,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { else if (type == SD_BUS_TYPE_DICT_ENTRY) fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents); - level ++; + level++; continue; } diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index c2e913f62a..b8958ec7bb 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -1131,10 +1131,7 @@ _public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) { assert_return(!m->sealed, -EPERM); assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM); - if (b) - m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED; - else - m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + SET_FLAG(m->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED, !b); return 0; } @@ -1143,10 +1140,7 @@ _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) { assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - if (b) - m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START; - else - m->header->flags |= BUS_MESSAGE_NO_AUTO_START; + SET_FLAG(m->header->flags, BUS_MESSAGE_NO_AUTO_START, !b); return 0; } @@ -1155,10 +1149,7 @@ _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message * assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - if (b) - m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; - else - m->header->flags &= ~BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; + SET_FLAG(m->header->flags, BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION, b); return 0; } @@ -1198,7 +1189,7 @@ struct bus_body_part *message_append_part(sd_bus_message *m) { part->memfd = -1; m->body_end = part; - m->n_body_parts ++; + m->n_body_parts++; return part; } @@ -1643,7 +1634,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void } if (type == SD_BUS_TYPE_UNIX_FD) - m->n_fds ++; + m->n_fds++; if (c->enclosing != SD_BUS_TYPE_ARRAY) c->index++; @@ -2387,9 +2378,9 @@ int bus_message_append_ap( t = types; if (n_array != (unsigned) -1) - n_array --; + n_array--; else { - types ++; + types++; n_struct--; } @@ -3866,7 +3857,7 @@ static int build_struct_offsets( if (r < 0) return r; if (r == 0 && p[n] != 0) /* except the last item */ - n_variable ++; + n_variable++; n_total++; p += n; @@ -4466,9 +4457,9 @@ static int message_read_ap( t = types; if (n_array != (unsigned) -1) - n_array --; + n_array--; else { - types ++; + types++; n_struct--; } diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 1f285ae8a6..9bd07ffcab 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -145,7 +145,7 @@ static int add_enumerated_to_set( continue; } - if (!object_path_is_valid(*k)){ + if (!object_path_is_valid(*k)) { free(*k); r = -EINVAL; continue; @@ -337,7 +337,7 @@ static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, if (cap == 0) cap = CAP_SYS_ADMIN; else - cap --; + cap--; r = sd_bus_query_sender_privilege(m, cap); if (r < 0) diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c index a8c74011bf..8e9074c7df 100644 --- a/src/libsystemd/sd-bus/bus-slot.c +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -206,7 +206,7 @@ _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) { assert(slot->n_ref > 0); if (slot->n_ref > 1) { - slot->n_ref --; + slot->n_ref--; return NULL; } diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 13d0aef4b5..f1e2a06050 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -60,7 +60,7 @@ static void iovec_advance(struct iovec iov[], unsigned *idx, size_t size) { i->iov_base = NULL; i->iov_len = 0; - (*idx) ++; + (*idx)++; } } diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index bdbf7d4a85..1f436fe560 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -129,7 +129,7 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) { assert(track->n_ref > 0); if (track->n_ref > 1) { - track->n_ref --; + track->n_ref--; return NULL; } diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 772ab62d5b..56bd5863a8 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -62,15 +62,6 @@ static bool arg_allow_interactive_authorization = true; static bool arg_augment_creds = true; static usec_t arg_timeout = 0; -static void pager_open_if_enabled(void) { - - /* Cache result before we open the pager */ - if (arg_no_pager) - return; - - pager_open(false); -} - #define NAME_IS_ACQUIRED INT_TO_PTR(1) #define NAME_IS_ACTIVATABLE INT_TO_PTR(2) @@ -95,7 +86,7 @@ static int list_bus_names(sd_bus *bus, char **argv) { if (r < 0) return log_error_errno(r, "Failed to list names: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); names = hashmap_new(&string_hash_ops); if (!names) @@ -289,7 +280,7 @@ static void print_subtree(const char *prefix, const char *path, char **l) { static void print_tree(const char *prefix, char **l) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); prefix = strempty(prefix); @@ -409,7 +400,7 @@ static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool m p = NULL; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); l = set_get_strv(done); if (!l) @@ -438,7 +429,7 @@ static int tree(sd_bus *bus, char **argv) { if (r < 0) return log_error_errno(r, "Failed to get name list: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); STRV_FOREACH(i, names) { int q; @@ -468,7 +459,7 @@ static int tree(sd_bus *bus, char **argv) { printf("\n"); if (argv[2]) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal()); } @@ -992,7 +983,7 @@ static int introspect(sd_bus *bus, char **argv) { return bus_log_parse_error(r); } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); name_width = strlen("NAME"); type_width = strlen("TYPE"); @@ -1559,7 +1550,7 @@ static int call(sd_bus *bus, char *argv[]) { if (r == 0 && !arg_quiet) { if (arg_verbose) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = bus_message_dump(reply, stdout, 0); if (r < 0) @@ -1614,7 +1605,7 @@ static int get_property(sd_bus *bus, char *argv[]) { return bus_log_parse_error(r); if (arg_verbose) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY); if (r < 0) diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index c6f626d8aa..862f26aad7 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -313,10 +313,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) { assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - if (b) - bus->creds_mask |= mask; - else - bus->creds_mask &= ~mask; + SET_FLAG(bus->creds_mask, mask, b); /* The well knowns we need unconditionally, so that matches can work */ bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; @@ -530,7 +527,7 @@ static void skip_address_key(const char **p) { *p += strcspn(*p, ","); if (**p == ',') - (*p) ++; + (*p)++; } static int parse_unix_address(sd_bus *b, const char **p, char **guid) { @@ -695,7 +692,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) { goto fail; } - (*p) ++; + (*p)++; if (ul >= n_argv) { if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) { @@ -1668,7 +1665,7 @@ static int dispatch_wqueue(sd_bus *bus) { * it got full, then all bets are off * anyway. */ - bus->wqueue_size --; + bus->wqueue_size--; sd_bus_message_unref(bus->wqueue[0]); memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size); bus->windex = 0; @@ -1717,7 +1714,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd /* Dispatch a queued message */ *m = bus->rqueue[0]; - bus->rqueue_size --; + bus->rqueue_size--; memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size); return 1; } @@ -1809,7 +1806,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1)) return -ENOMEM; - bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m); + bus->wqueue[bus->wqueue_size++] = sd_bus_message_ref(m); } finish: @@ -2257,7 +2254,7 @@ static int process_timeout(sd_bus *bus) { slot = container_of(c, sd_bus_slot, reply_callback); - bus->iteration_counter ++; + bus->iteration_counter++; bus->current_message = m; bus->current_slot = sd_bus_slot_ref(slot); diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 46d18abd29..66a3874f10 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -146,7 +146,7 @@ static void dump_mapping_table(void) { } printf("%s -> %i/%s\n", strna(m->name), m->code, strna(errno_to_name(m->code))); - m ++; + m++; } printf("---------------------------\n"); } diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 4e50b61979..bd1c7f15ff 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -465,7 +465,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char have_pid = pid != 0 && pid != getpid(); if (n_fds > 0 || have_pid) { - /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */ + /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */ msghdr.msg_controllen = (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) + (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0); diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h index b96441de56..ab222e27de 100644 --- a/src/libsystemd/sd-device/device-internal.h +++ b/src/libsystemd/sd-device/device-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "hashmap.h" #include "set.h" diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index f2af3ab3ae..9082d377f4 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -890,7 +890,7 @@ void device_cleanup_tags(sd_device *device) { set_free_free(device->tags); device->tags = NULL; device->property_tags_outdated = true; - device->tags_generation ++; + device->tags_generation++; } void device_cleanup_devlinks(sd_device *device) { @@ -899,7 +899,7 @@ void device_cleanup_devlinks(sd_device *device) { set_free_free(device->devlinks); device->devlinks = NULL; device->property_devlinks_outdated = true; - device->devlinks_generation ++; + device->devlinks_generation++; } void device_remove_tag(sd_device *device, const char *tag) { @@ -908,7 +908,7 @@ void device_remove_tag(sd_device *device, const char *tag) { free(set_remove(device->tags, tag)); device->property_tags_outdated = true; - device->tags_generation ++; + device->tags_generation++; } static int device_tag(sd_device *device, const char *tag, bool add) { diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 9633e46ce0..8657e61cd9 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -136,7 +136,7 @@ int device_add_property_aux(sd_device *device, const char *_key, const char *_va } if (!db) { - device->properties_generation ++; + device->properties_generation++; device->properties_buf_outdated = true; } @@ -309,7 +309,7 @@ _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *s if (name[len] == '/') name[len] = '!'; - len ++; + len++; } syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name); @@ -669,7 +669,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { return -EINVAL; sysname[0] = '\0'; - sysname ++; + sysname++; return sd_device_new_from_subsystem_sysname(ret, subsys, sysname); } @@ -971,7 +971,7 @@ static int device_set_sysname(sd_device *device) { pos = strrchr(device->devpath, '/'); if (!pos) return -EINVAL; - pos ++; + pos++; /* devpath is not a root directory */ if (*pos == '\0' || pos <= device->devpath) @@ -986,7 +986,7 @@ static int device_set_sysname(sd_device *device) { if (sysname[len] == '!') sysname[len] = '/'; - len ++; + len++; } /* trailing number */ @@ -1066,7 +1066,7 @@ int device_add_tag(sd_device *device, const char *tag) { if (r < 0) return r; - device->tags_generation ++; + device->tags_generation++; device->property_tags_outdated = true; return 0; @@ -1086,7 +1086,7 @@ int device_add_devlink(sd_device *device, const char *devlink) { if (r < 0) return r; - device->devlinks_generation ++; + device->devlinks_generation++; device->property_devlinks_outdated = true; return 0; @@ -1397,7 +1397,7 @@ _public_ const char *sd_device_get_tag_first(sd_device *device) { device->tags_iterator_generation = device->tags_generation; device->tags_iterator = ITERATOR_FIRST; - set_iterate(device->tags, &device->tags_iterator, &v); + (void) set_iterate(device->tags, &device->tags_iterator, &v); return v; } @@ -1411,7 +1411,7 @@ _public_ const char *sd_device_get_tag_next(sd_device *device) { if (device->tags_iterator_generation != device->tags_generation) return NULL; - set_iterate(device->tags, &device->tags_iterator, &v); + (void) set_iterate(device->tags, &device->tags_iterator, &v); return v; } @@ -1425,7 +1425,7 @@ _public_ const char *sd_device_get_devlink_first(sd_device *device) { device->devlinks_iterator_generation = device->devlinks_generation; device->devlinks_iterator = ITERATOR_FIRST; - set_iterate(device->devlinks, &device->devlinks_iterator, &v); + (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v); return v; } @@ -1439,7 +1439,7 @@ _public_ const char *sd_device_get_devlink_next(sd_device *device) { if (device->devlinks_iterator_generation != device->devlinks_generation) return NULL; - set_iterate(device->devlinks, &device->devlinks_iterator, &v); + (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v); return v; } @@ -1606,7 +1606,7 @@ _public_ const char *sd_device_get_sysattr_first(sd_device *device) { device->sysattrs_iterator = ITERATOR_FIRST; - set_iterate(device->sysattrs, &device->sysattrs_iterator, &v); + (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v); return v; } @@ -1618,7 +1618,7 @@ _public_ const char *sd_device_get_sysattr_next(sd_device *device) { if (!device->sysattrs_read) return NULL; - set_iterate(device->sysattrs, &device->sysattrs_iterator, &v); + (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v); return v; } diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 2b46a1ff06..841358ed03 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -951,7 +951,7 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t sd_event_ref(e); LIST_PREPEND(sources, e->sources, s); - e->n_sources ++; + e->n_sources++; return s; } @@ -1235,7 +1235,7 @@ _public_ int sd_event_add_child( return r; } - e->n_enabled_child_sources ++; + e->n_enabled_child_sources++; r = event_make_signal_data(e, SIGCHLD, NULL); if (r < 0) { diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index daea4126f8..fd31588b8f 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -291,7 +291,7 @@ static int n_rtqueue = 0; static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { last_rtqueue_sigval = si->ssi_int; - n_rtqueue ++; + n_rtqueue++; return 0; } diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h index 13fddfc8ad..8ffb5e5c74 100644 --- a/src/libsystemd/sd-hwdb/hwdb-internal.h +++ b/src/libsystemd/sd-hwdb/hwdb-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -16,7 +18,6 @@ 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 #include "sparse-endian.h" #include "util.h" diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 3a866fdafe..f56798674c 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -34,7 +34,7 @@ #include "util.h" #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL) -#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; +#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK) #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK) @@ -107,10 +107,7 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) { m->hdr->nlmsg_type == RTM_GETNEIGH, -EINVAL); - if (dump) - m->hdr->nlmsg_flags |= NLM_F_DUMP; - else - m->hdr->nlmsg_flags &= ~NLM_F_DUMP; + SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump); return 0; } @@ -467,7 +464,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type if (r < 0) return r; - m->containers[m->n_containers ++].offset = r; + m->containers[m->n_containers++].offset = r; return 0; } @@ -498,7 +495,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor if (r < 0) return r; - m->containers[m->n_containers ++].offset = r; + m->containers[m->n_containers++].offset = r; return 0; } @@ -510,7 +507,7 @@ int sd_netlink_message_close_container(sd_netlink_message *m) { assert_return(m->n_containers > 0, -EINVAL); m->containers[m->n_containers].type_system = NULL; - m->n_containers --; + m->n_containers--; return 0; } @@ -528,7 +525,7 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t attribute = &m->containers[m->n_containers].attributes[type]; - if(!attribute->offset) + if (!attribute->offset) return -ENODATA; rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset); @@ -735,7 +732,7 @@ static int netlink_container_parse(sd_netlink_message *m, _cleanup_free_ struct netlink_attribute *attributes = NULL; attributes = new0(struct netlink_attribute, count); - if(!attributes) + if (!attributes) return -ENOMEM; for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) { @@ -842,7 +839,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ else size = (size_t)r; - m->n_containers ++; + m->n_containers++; r = netlink_container_parse(m, &m->containers[m->n_containers], @@ -850,7 +847,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ container, size); if (r < 0) { - m->n_containers --; + m->n_containers--; return r; } @@ -867,7 +864,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m) { m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes); m->containers[m->n_containers].type_system = NULL; - m->n_containers --; + m->n_containers--; return 0; } diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 590fc53fc7..c165fa3359 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -82,7 +82,7 @@ static int broadcast_groups_get(sd_netlink *nl) { return r; for (i = 0; i < len; i++) { - for (j = 0; j < sizeof(uint32_t) * 8; j ++) { + for (j = 0; j < sizeof(uint32_t) * 8; j++) { uint32_t offset; unsigned group; @@ -168,7 +168,7 @@ int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) { n_ref = broadcast_group_get_ref(nl, group); - n_ref ++; + n_ref++; r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL); if (r < 0) @@ -216,7 +216,7 @@ int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) { assert(n_ref > 0); - n_ref --; + n_ref--; r = broadcast_group_set_ref(nl, group, n_ref); if (r < 0) @@ -444,14 +444,14 @@ int socket_read_message(sd_netlink *rtnl) { if (r < 0) return r; - rtnl->rqueue[rtnl->rqueue_size ++] = first; + rtnl->rqueue[rtnl->rqueue_size++] = first; first = NULL; if (multi_part && (i < rtnl->rqueue_partial_size)) { /* remove the message form the partial read queue */ memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1, sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1)); - rtnl->rqueue_partial_size --; + rtnl->rqueue_partial_size--; } return 1; @@ -465,7 +465,7 @@ int socket_read_message(sd_netlink *rtnl) { if (r < 0) return r; - rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first; + rtnl->rqueue_partial[rtnl->rqueue_partial_size++] = first; } first = NULL; diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 090552f576..255526bf32 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -616,7 +616,7 @@ int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) { return 0; } -int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) { +int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) { struct ifinfomsg *ifi; assert_return(m, -EINVAL); diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 4833815b43..91701405a5 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -279,7 +279,7 @@ static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) { /* Dispatch a queued message */ *message = rtnl->rqueue[0]; - rtnl->rqueue_size --; + rtnl->rqueue_size--; memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size); return 1; @@ -774,7 +774,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) { return 1; } -int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) { +int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) { int r; assert_return(rtnl, -EINVAL); diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index de5e0ffc8f..f9b6787187 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -234,7 +234,7 @@ static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) int *counter = userdata; int r; - (*counter) --; + (*counter)--; r = sd_netlink_message_get_errno(m); @@ -276,10 +276,10 @@ static void test_pipe(int ifindex) { assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0); - counter ++; + counter++; assert_se(sd_netlink_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0); - counter ++; + counter++; assert_se(sd_netlink_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0); while (counter > 0) { diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 62051992ef..f8e18f23fd 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -31,6 +31,7 @@ #include "fs-util.h" #include "macro.h" #include "parse-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -102,16 +103,16 @@ _public_ int sd_network_get_route_domains(char ***ret) { } static int network_link_get_string(int ifindex, const char *field, char **ret) { - _cleanup_free_ char *s = NULL, *p = NULL; + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; + _cleanup_free_ char *s = NULL; int r; assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%i", ifindex) < 0) - return -ENOMEM; + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); - r = parse_env_file(p, NEWLINE, field, &s, NULL); + r = parse_env_file(path, NEWLINE, field, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -126,17 +127,16 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) { } static int network_link_get_strv(int ifindex, const char *key, char ***ret) { - _cleanup_free_ char *p = NULL, *s = NULL; + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; _cleanup_strv_free_ char **a = NULL; + _cleanup_free_ char *s = NULL; int r; assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, key, &s, NULL); + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); + r = parse_env_file(path, NEWLINE, key, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -187,32 +187,7 @@ _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char return network_link_get_strv(ifindex, "DNSSEC_NTA", nta); } -_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) { - _cleanup_free_ char *s = NULL, *p = NULL; - size_t size; - int r; - - assert_return(ifindex > 0, -EINVAL); - assert_return(lldp, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0) - return -ENOMEM; - - r = read_full_file(p, &s, &size); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (size <= 0) - return -ENODATA; - - *lldp = s; - s = NULL; - - return 0; -} - -int sd_network_link_get_timezone(int ifindex, char **ret) { +_public_ int sd_network_link_get_timezone(int ifindex, char **ret) { return network_link_get_string(ifindex, "TIMEZONE", ret); } @@ -232,12 +207,64 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) { return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret); } -_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) { - return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret); +static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; + _cleanup_free_ int *ifis = NULL; + _cleanup_free_ char *s = NULL; + size_t allocated = 0, c = 0; + const char *x; + int r; + + assert_return(ifindex > 0, -EINVAL); + assert_return(ret, -EINVAL); + + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); + r = parse_env_file(path, NEWLINE, key, &s, NULL); + if (r == -ENOENT) + return -ENODATA; + if (r < 0) + return r; + if (isempty(s)) { + *ret = NULL; + return 0; + } + + x = s; + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&x, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + + r = parse_ifindex(word, &ifindex); + if (r < 0) + return r; + + if (!GREEDY_REALLOC(ifis, allocated, c + 1)) + return -ENOMEM; + + ifis[c++] = ifindex; + } + + if (!GREEDY_REALLOC(ifis, allocated, c + 1)) + return -ENOMEM; + ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/ + + *ret = ifis; + ifis = NULL; + + return c; +} + +_public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) { + return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret); } -_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) { - return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret); +_public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) { + return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret); } static inline int MONITOR_TO_FD(sd_network_monitor *m) { diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c index 480f1ad065..b7aec1f20a 100644 --- a/src/libsystemd/sd-path/sd-path.c +++ b/src/libsystemd/sd-path/sd-path.c @@ -89,7 +89,8 @@ static int from_home_dir(const char *envname, const char *suffix, char **buffer, static int from_user_dir(const char *field, char **buffer, const char **ret) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *b = NULL; - const char *fn = NULL; + _cleanup_free_ const char *fn = NULL; + const char *c = NULL; char line[LINE_MAX]; size_t n; int r; @@ -98,10 +99,14 @@ static int from_user_dir(const char *field, char **buffer, const char **ret) { assert(buffer); assert(ret); - r = from_home_dir(NULL, ".config/user-dirs.dirs", &b, &fn); + r = from_home_dir("XDG_CONFIG_HOME", ".config", &b, &c); if (r < 0) return r; + fn = strappend(c, "/user-dirs.dirs"); + if (!fn) + return -ENOMEM; + f = fopen(fn, "re"); if (!f) { if (errno == ENOENT) diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index de17a6112e..37585048b8 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -403,7 +403,7 @@ static void* thread_worker(void *p) { assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0); /* Assign a pretty name to this thread */ - prctl(PR_SET_NAME, (unsigned long) "sd-resolve"); + (void) prctl(PR_SET_NAME, (unsigned long) "sd-resolve"); while (!resolve->dead) { union { @@ -447,7 +447,7 @@ static int start_threads(sd_resolve *resolve, unsigned extra) { if (r != 0) return -r; - resolve->n_valid_workers ++; + resolve->n_valid_workers++; } return 0; @@ -657,7 +657,7 @@ static int complete_query(sd_resolve *resolve, sd_resolve_query *q) { assert(q->resolve == resolve); q->done = true; - resolve->n_done ++; + resolve->n_done++; resolve->current = sd_resolve_query_ref(q); @@ -1191,7 +1191,7 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd return 1; } -_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) { +_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) { int r; assert_return(resolve, -EINVAL); diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h index 40d59201cf..0e9af8ec09 100644 --- a/src/libudev/libudev-device-internal.h +++ b/src/libudev/libudev-device-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "libudev.h" #include "sd-device.h" diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c index e416e178b4..3b8abfb260 100644 --- a/src/libudev/libudev-enumerate.c +++ b/src/libudev/libudev-enumerate.c @@ -112,7 +112,7 @@ _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) { **/ _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) { if (udev_enumerate) - udev_enumerate->refcount ++; + udev_enumerate->refcount++; return udev_enumerate; } diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h index eb58740d26..3f6d0ed16c 100644 --- a/src/libudev/libudev.h +++ b/src/libudev/libudev.h @@ -21,6 +21,7 @@ #define _LIBUDEV_H_ #include <stdarg.h> +#include <sys/sysmacros.h> #include <sys/types.h> #ifdef __cplusplus diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 365c79aa51..4865335349 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -46,14 +46,6 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; static char *arg_host = NULL; static bool arg_convert = true; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void polkit_agent_open_if_enabled(void) { /* Open the polkit agent as a child process if necessary */ @@ -124,11 +116,11 @@ static void print_overridden_variables(void) { if (variables[j]) { if (print_warning) { log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n" - " Command Line: %s=%s", locale_variable_to_string(j), variables[j]); + " Command Line: %s=%s", locale_variable_to_string(j), variables[j]); print_warning = false; } else - log_warning(" %s=%s", locale_variable_to_string(j), variables[j]); + log_warning(" %s=%s", locale_variable_to_string(j), variables[j]); } finish: for (j = 0; j < _VARIABLE_LC_MAX; j++) @@ -139,7 +131,7 @@ static void print_status_info(StatusInfo *i) { assert(i); if (strv_isempty(i->locale)) - puts(" System Locale: n/a\n"); + puts(" System Locale: n/a"); else { char **j; @@ -239,7 +231,7 @@ static int list_locales(sd_bus *bus, char **args, unsigned n) { if (r < 0) return log_error_errno(r, "Failed to read list of locales: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); strv_print(l); return 0; @@ -341,7 +333,7 @@ static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) { strv_sort(l); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); strv_print(l); @@ -479,7 +471,7 @@ static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) { strv_sort(list); strv_uniq(list); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); strv_print(list); return 0; diff --git a/src/locale/localed.c b/src/locale/localed.c index f0fe59cc67..46405ca68a 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -542,7 +542,7 @@ static int read_next_mapping(const char* filename, return 0; } - (*n) ++; + (*n)++; l = strstrip(line); if (l[0] == 0 || l[0] == '#') @@ -1296,7 +1296,7 @@ int main(int argc, char *argv[]) { log_open(); umask(0022); - mac_selinux_init("/etc"); + mac_selinux_init(); if (argc != 1) { log_error("This program takes no arguments."); diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules index 694df2cfc8..886c5bfcdf 100644 --- a/src/login/70-uaccess.rules +++ b/src/login/70-uaccess.rules @@ -42,8 +42,9 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" -# DRI video devices +# DRI and frame buffer video devices SUBSYSTEM=="drm", KERNEL=="card*|renderD*", TAG+="uaccess" +SUBSYSTEM=="graphics", KERNEL=="fb*", TAG+="uaccess" # KVM SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" @@ -75,4 +76,7 @@ SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess" # software-defined radio communication devices ENV{ID_SOFTWARE_RADIO}=="?*", TAG+="uaccess" +# 3D printers, CNC machines, laser cutters, 3D scanners, etc. +ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess" + LABEL="uaccess_end" diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 6ad3d089bd..c9a5cd796b 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -59,14 +59,6 @@ static bool arg_ask_password = true; static unsigned arg_lines = 10; static OutputMode arg_output = OUTPUT_SHORT; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void polkit_agent_open_if_enabled(void) { /* Open the polkit agent as a child process if necessary */ @@ -101,7 +93,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) { assert(bus); assert(argv); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -148,7 +140,7 @@ static int list_users(int argc, char *argv[], void *userdata) { assert(bus); assert(argv); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -194,7 +186,7 @@ static int list_seats(int argc, char *argv[], void *userdata) { assert(bus); assert(argv); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -858,7 +850,7 @@ static int show_session(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (argc <= 1) { /* If not argument is specified inspect the manager @@ -914,7 +906,7 @@ static int show_user(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (argc <= 1) { /* If not argument is specified inspect the manager @@ -974,7 +966,7 @@ static int show_seat(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (argc <= 1) { /* If not argument is specified inspect the manager diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c index 11a91c3947..29ab00eb1f 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-utmp.c @@ -65,7 +65,7 @@ bool logind_wall_tty_filter(const char *tty, void *userdata) { assert(m); - if (!startswith(tty, "/dev/")) + if (!startswith(tty, "/dev/") || !m->scheduled_shutdown_tty) return true; return !streq(tty + 5, m->scheduled_shutdown_tty); diff --git a/src/login/logind.c b/src/login/logind.c index 933602eb08..d5f6757bd3 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1126,7 +1126,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = mac_selinux_init("/run"); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "Could not initialize labelling: %m"); goto finish; diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 71f20b3f07..c5bbf2fbde 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -20,6 +20,7 @@ #include <errno.h> #include <string.h> #include <sys/mount.h> +#include <sys/wait.h> /* When we include libgen.h because we need dirname() we immediately * undefine basename() since libgen.h defines it as a macro to the POSIX diff --git a/src/machine/machine.c b/src/machine/machine.c index 7a7a1bb42b..7d4270a8ff 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -310,7 +310,7 @@ int machine_load(Machine *m) { int *ni = NULL; p = netif; - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL; int ifi; diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 4853139321..e49c90fd1b 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -80,14 +80,6 @@ static const char* arg_format = NULL; static const char *arg_uid = NULL; static char **arg_setenv = NULL; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void polkit_agent_open_if_enabled(void) { /* Open the polkit agent as a child process if necessary */ @@ -135,7 +127,7 @@ static int list_machines(int argc, char *argv[], void *userdata) { assert(bus); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -180,7 +172,7 @@ static int list_machines(int argc, char *argv[], void *userdata) { if (l > max_service) max_service = l; - n_machines ++; + n_machines++; } if (r < 0) return bus_log_parse_error(r); @@ -238,7 +230,7 @@ static int list_images(int argc, char *argv[], void *userdata) { assert(bus); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -707,7 +699,7 @@ static int show_machine(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (properties && argc <= 1) { @@ -956,7 +948,7 @@ static int show_image(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (argc <= 1) { @@ -1763,7 +1755,7 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) { r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { - log_error("Failed transfer image: %s", bus_error_message(&error, -r)); + log_error("Failed to transfer image: %s", bus_error_message(&error, -r)); return r; } @@ -2189,7 +2181,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) { double progress; int r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -2236,7 +2228,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) { if (id > max_id) max_id = id; - n_transfers ++; + n_transfers++; } if (r < 0) return bus_log_parse_error(r); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index b933099330..20894433e7 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -1212,7 +1212,7 @@ int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_err r = unit_name_from_dbus_path(path, &unit); if (r == -EINVAL) /* not for a unit */ return 0; - if (r < 0){ + if (r < 0) { log_oom(); return 0; } diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 60724fce80..b22a0f648a 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -23,6 +23,7 @@ #include "sd-device.h" #include "sd-hwdb.h" +#include "sd-lldp.h" #include "sd-netlink.h" #include "sd-network.h" @@ -30,18 +31,20 @@ #include "arphrd-list.h" #include "device-util.h" #include "ether-addr-util.h" +#include "fd-util.h" #include "hwdb-util.h" -#include "lldp.h" #include "local-addresses.h" #include "locale-util.h" #include "netlink-util.h" #include "pager.h" #include "parse-util.h" #include "socket-util.h" +#include "sparse-endian.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "strxcpyx.h" #include "terminal-util.h" #include "util.h" #include "verbs.h" @@ -50,15 +53,7 @@ static bool arg_no_pager = false; static bool arg_legend = true; static bool arg_all = false; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - -static int link_get_type_string(int iftype, sd_device *d, char **ret) { +static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) { const char *t; char *p; @@ -70,7 +65,7 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) { * to show a more useful type string for * them */ - (void)sd_device_get_devtype(d, &devtype); + (void) sd_device_get_devtype(d, &devtype); if (streq_ptr(devtype, "wlan")) id = "wlan"; @@ -103,10 +98,46 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) { return 0; } +static void operational_state_to_color(const char *state, const char **on, const char **off) { + assert(on); + assert(off); + + if (streq_ptr(state, "routable")) { + *on = ansi_highlight_green(); + *off = ansi_normal(); + } else if (streq_ptr(state, "degraded")) { + *on = ansi_highlight_yellow(); + *off = ansi_normal(); + } else + *on = *off = ""; +} + +static void setup_state_to_color(const char *state, const char **on, const char **off) { + assert(on); + assert(off); + + if (streq_ptr(state, "configured")) { + *on = ansi_highlight_green(); + *off = ansi_normal(); + } else if (streq_ptr(state, "configuring")) { + *on = ansi_highlight_yellow(); + *off = ansi_normal(); + } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) { + *on = ansi_highlight_red(); + *off = ansi_normal(); + } else + *on = *off = ""; +} + typedef struct LinkInfo { - const char *name; + char name[IFNAMSIZ+1]; int ifindex; - unsigned iftype; + unsigned short iftype; + struct ether_addr mac_address; + uint32_t mtu; + + bool has_mac_address:1; + bool has_mtu:1; } LinkInfo; static int link_info_compare(const void *a, const void *b) { @@ -115,44 +146,84 @@ static int link_info_compare(const void *a, const void *b) { return x->ifindex - y->ifindex; } -static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { +static int decode_link(sd_netlink_message *m, LinkInfo *info) { + const char *name; + uint16_t type; + int r; + + assert(m); + assert(info); + + r = sd_netlink_message_get_type(m, &type); + if (r < 0) + return r; + + if (type != RTM_NEWLINK) + return 0; + + r = sd_rtnl_message_link_get_ifindex(m, &info->ifindex); + if (r < 0) + return r; + + r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name); + if (r < 0) + return r; + + r = sd_rtnl_message_link_get_type(m, &info->iftype); + if (r < 0) + return r; + + strscpy(info->name, sizeof info->name, name); + + info->has_mac_address = + sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 && + memcmp(&info->mac_address, ÐER_ADDR_NULL, sizeof(struct ether_addr)) != 0; + + info->has_mtu = + sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu) && + info->mtu > 0; + + return 1; +} + +static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) { _cleanup_free_ LinkInfo *links = NULL; - size_t size = 0, c = 0; - sd_netlink_message *i; + char **i; + size_t c = 0; int r; - for (i = m; i; i = sd_netlink_message_next(i)) { - const char *name; - unsigned iftype; - uint16_t type; - int ifindex; + assert(rtnl); + assert(ret); - r = sd_netlink_message_get_type(i, &type); - if (r < 0) - return r; + links = new(LinkInfo, strv_length(l)); + if (!links) + return log_oom(); - if (type != RTM_NEWLINK) - continue; + STRV_FOREACH(i, l) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + int ifindex; + + if (parse_ifindex(*i, &ifindex) >= 0) + r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex); + else { + r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); + if (r < 0) + return rtnl_log_create_error(r); - r = sd_rtnl_message_link_get_ifindex(i, &ifindex); + r = sd_netlink_message_append_string(req, IFLA_IFNAME, *i); + } if (r < 0) - return r; + return rtnl_log_create_error(r); - r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name); + r = sd_netlink_call(rtnl, req, 0, &reply); if (r < 0) - return r; + return log_error_errno(r, "Failed to request link: %m"); - r = sd_rtnl_message_link_get_type(i, &iftype); + r = decode_link(reply, links + c); if (r < 0) return r; - - if (!GREEDY_REALLOC(links, size, c+1)) - return -ENOMEM; - - links[c].name = name; - links[c].ifindex = ifindex; - links[c].iftype = iftype; - c++; + if (r > 0) + c++; } qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); @@ -163,48 +234,15 @@ static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { return (int) c; } -static void operational_state_to_color(const char *state, const char **on, const char **off) { - assert(on); - assert(off); - - if (streq_ptr(state, "routable")) { - *on = ansi_highlight_green(); - *off = ansi_normal(); - } else if (streq_ptr(state, "degraded")) { - *on = ansi_highlight_yellow(); - *off = ansi_normal(); - } else - *on = *off = ""; -} - -static void setup_state_to_color(const char *state, const char **on, const char **off) { - assert(on); - assert(off); - - if (streq_ptr(state, "configured")) { - *on = ansi_highlight_green(); - *off = ansi_normal(); - } else if (streq_ptr(state, "configuring")) { - *on = ansi_highlight_yellow(); - *off = ansi_normal(); - } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) { - *on = ansi_highlight_red(); - *off = ansi_normal(); - } else - *on = *off = ""; -} - -static int list_links(int argc, char *argv[], void *userdata) { +static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; - int r, c, i; - - pager_open_if_enabled(); + size_t allocated = 0, c = 0; + sd_netlink_message *i; + int r; - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); + assert(rtnl); + assert(ret); r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); if (r < 0) @@ -218,12 +256,50 @@ static int list_links(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to enumerate links: %m"); - if (arg_legend) - printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP"); + for (i = reply; i; i = sd_netlink_message_next(i)) { + if (!GREEDY_REALLOC(links, allocated, c+1)) + return -ENOMEM; + + r = decode_link(i, links + c); + if (r < 0) + return r; + if (r > 0) + c++; + } - c = decode_and_sort_links(reply, &links); + qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); + + *ret = links; + links = NULL; + + return (int) c; +} + +static int list_links(int argc, char *argv[], void *userdata) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_free_ LinkInfo *links = NULL; + int c, i, r; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + if (argc > 1) + c = acquire_link_info_strv(rtnl, argv + 1, &links); + else + c = acquire_link_info_all(rtnl, &links); if (c < 0) - return rtnl_log_parse_error(c); + return c; + + pager_open(arg_no_pager, false); + + if (arg_legend) + printf("%3s %-16s %-18s %-11s %-10s\n", + "IDX", + "LINK", + "TYPE", + "OPERATIONAL", + "SETUP"); for (i = 0; i < c; i++) { _cleanup_free_ char *setup_state = NULL, *operational_state = NULL; @@ -233,16 +309,18 @@ static int list_links(int argc, char *argv[], void *userdata) { char devid[2 + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *t = NULL; - sd_network_link_get_operational_state(links[i].ifindex, &operational_state); + (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - sd_network_link_get_setup_state(links[i].ifindex, &setup_state); + r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state); + if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */ + setup_state = strdup("unmanaged"); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); - sprintf(devid, "n%i", links[i].ifindex); - (void)sd_device_new_from_device_id(&d, devid); + xsprintf(devid, "n%i", links[i].ifindex); + (void) sd_device_new_from_device_id(&d, devid); - link_get_type_string(links[i].iftype, d, &t); + (void) link_get_type_string(links[i].iftype, d, &t); printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n", links[i].ifindex, links[i].name, strna(t), @@ -257,7 +335,7 @@ static int list_links(int argc, char *argv[], void *userdata) { } /* IEEE Organizationally Unique Identifier vendor string */ -static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) { +static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) { const char *description; char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc; int r; @@ -404,6 +482,9 @@ static int dump_gateways( _cleanup_free_ struct local_address *local = NULL; int r, n, i; + assert(rtnl); + assert(prefix); + n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local); if (n < 0) return n; @@ -453,6 +534,9 @@ static int dump_addresses( _cleanup_free_ struct local_address *local = NULL; int r, n, i; + assert(rtnl); + assert(prefix); + n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local); if (n < 0) return n; @@ -485,6 +569,116 @@ static int dump_addresses( return 0; } +static int open_lldp_neighbors(int ifindex, FILE **ret) { + _cleanup_free_ char *p = NULL; + FILE *f; + + if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0) + return -ENOMEM; + + f = fopen(p, "re"); + if (!f) + return -errno; + + *ret = f; + return 0; +} + +static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) { + _cleanup_free_ void *raw = NULL; + size_t l; + le64_t u; + int r; + + assert(f); + assert(ret); + + l = fread(&u, 1, sizeof(u), f); + if (l == 0 && feof(f)) + return 0; + if (l != sizeof(u)) + return -EBADMSG; + + raw = new(uint8_t, le64toh(u)); + if (!raw) + return -ENOMEM; + + if (fread(raw, 1, le64toh(u), f) != le64toh(u)) + return -EBADMSG; + + r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u)); + if (r < 0) + return r; + + return 1; +} + +static int dump_lldp_neighbors(const char *prefix, int ifindex) { + _cleanup_fclose_ FILE *f = NULL; + int r, c = 0; + + assert(prefix); + assert(ifindex > 0); + + r = open_lldp_neighbors(ifindex, &f); + if (r < 0) + return r; + + for (;;) { + const char *system_name = NULL, *port_id = NULL, *port_description = NULL; + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + + r = next_lldp_neighbor(f, &n); + if (r < 0) + return r; + if (r == 0) + break; + + printf("%*s", + (int) strlen(prefix), + c == 0 ? prefix : ""); + + (void) sd_lldp_neighbor_get_system_name(n, &system_name); + (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); + (void) sd_lldp_neighbor_get_port_description(n, &port_description); + + printf("%s on port %s", strna(system_name), strna(port_id)); + + if (!isempty(port_description)) + printf(" (%s)", port_description); + + putchar('\n'); + + c++; + } + + return c; +} + +static void dump_ifindexes(const char *prefix, const int *ifindexes) { + unsigned c; + + assert(prefix); + + if (!ifindexes || ifindexes[0] <= 0) + return; + + for (c = 0; ifindexes[c] > 0; c++) { + char name[IF_NAMESIZE+1]; + + printf("%*s", + (int) strlen(prefix), + c == 0 ? prefix : ""); + + if (if_indextoname(ifindexes[c], name)) + fputs(name, stdout); + else + printf("%i", ifindexes[c]); + + fputc('\n', stdout); + } +} + static void dump_list(const char *prefix, char **l) { char **i; @@ -502,85 +696,36 @@ static void dump_list(const char *prefix, char **l) { static int link_status_one( sd_netlink *rtnl, sd_hwdb *hwdb, - const char *name) { + const LinkInfo *info) { + _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL; _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL; - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_device_unrefp) sd_device *d = NULL; char devid[2 + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *t = NULL, *network = NULL; const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL; const char *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup; - _cleanup_strv_free_ char **carrier_bound_to = NULL; - _cleanup_strv_free_ char **carrier_bound_by = NULL; - struct ether_addr e; - unsigned iftype; - int r, ifindex; - bool have_mac; - uint32_t mtu; + _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL; + int r; assert(rtnl); - assert(name); - - if (parse_ifindex(name, &ifindex) >= 0) - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex); - else { - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_message_append_string(req, IFLA_IFNAME, name); - } + assert(info); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return log_error_errno(r, "Failed to query link: %m"); - - r = sd_rtnl_message_link_get_ifindex(reply, &ifindex); - if (r < 0) - return rtnl_log_parse_error(r); - - r = sd_netlink_message_read_string(reply, IFLA_IFNAME, &name); - if (r < 0) - return rtnl_log_parse_error(r); - - r = sd_rtnl_message_link_get_type(reply, &iftype); - if (r < 0) - return rtnl_log_parse_error(r); - - have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0; - if (have_mac) { - const uint8_t *p; - bool all_zeroes = true; - - for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++) - if (*p != 0) { - all_zeroes = false; - break; - } - - if (all_zeroes) - have_mac = false; - } - - (void) sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu); - - (void) sd_network_link_get_operational_state(ifindex, &operational_state); + (void) sd_network_link_get_operational_state(info->ifindex, &operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - (void) sd_network_link_get_setup_state(ifindex, &setup_state); + r = sd_network_link_get_setup_state(info->ifindex, &setup_state); + if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */ + setup_state = strdup("unmanaged"); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); - (void) sd_network_link_get_dns(ifindex, &dns); - (void) sd_network_link_get_search_domains(ifindex, &search_domains); - (void) sd_network_link_get_route_domains(ifindex, &route_domains); - (void) sd_network_link_get_ntp(ifindex, &ntp); + (void) sd_network_link_get_dns(info->ifindex, &dns); + (void) sd_network_link_get_search_domains(info->ifindex, &search_domains); + (void) sd_network_link_get_route_domains(info->ifindex, &route_domains); + (void) sd_network_link_get_ntp(info->ifindex, &ntp); - sprintf(devid, "n%i", ifindex); + xsprintf(devid, "n%i", info->ifindex); (void) sd_device_new_from_device_id(&d, devid); @@ -598,14 +743,14 @@ static int link_status_one( (void) sd_device_get_property_value(d, "ID_MODEL", &model); } - link_get_type_string(iftype, d, &t); + (void) link_get_type_string(info->iftype, d, &t); - sd_network_link_get_network_file(ifindex, &network); + (void) sd_network_link_get_network_file(info->ifindex, &network); - sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to); - sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by); + (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to); + (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by); - printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name); + printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, info->ifindex, info->name); printf(" Link File: %s\n" " Network File: %s\n" @@ -626,23 +771,23 @@ static int link_status_one( if (model) printf(" Model: %s\n", model); - if (have_mac) { + if (info->has_mac_address) { _cleanup_free_ char *description = NULL; char ea[ETHER_ADDR_TO_STRING_MAX]; - ieee_oui(hwdb, &e, &description); + (void) ieee_oui(hwdb, &info->mac_address, &description); if (description) - printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description); + printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info->mac_address, ea), description); else - printf(" HW Address: %s\n", ether_addr_to_string(&e, ea)); + printf(" HW Address: %s\n", ether_addr_to_string(&info->mac_address, ea)); } - if (mtu > 0) - printf(" MTU: %u\n", mtu); + if (info->has_mtu) + printf(" MTU: %u\n", info->mtu); - dump_addresses(rtnl, " Address: ", ifindex); - dump_gateways(rtnl, hwdb, " Gateway: ", ifindex); + (void) dump_addresses(rtnl, " Address: ", info->ifindex); + (void) dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex); dump_list(" DNS: ", dns); dump_list(" Search Domains: ", search_domains); @@ -650,362 +795,237 @@ static int link_status_one( dump_list(" NTP: ", ntp); - dump_list("Carrier Bound To: ", carrier_bound_to); - dump_list("Carrier Bound By: ", carrier_bound_by); + dump_ifindexes("Carrier Bound To: ", carrier_bound_to); + dump_ifindexes("Carrier Bound By: ", carrier_bound_by); - (void) sd_network_link_get_timezone(ifindex, &tz); + (void) sd_network_link_get_timezone(info->ifindex, &tz); if (tz) - printf(" Time Zone: %s", tz); + printf(" Time Zone: %s\n", tz); + + (void) dump_lldp_neighbors(" Connected To: ", info->ifindex); return 0; } -static int link_status(int argc, char *argv[], void *userdata) { - _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - char **name; - int r; - - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); - - r = sd_hwdb_new(&hwdb); - if (r < 0) - log_debug_errno(r, "Failed to open hardware database: %m"); - - if (argc <= 1 && !arg_all) { - _cleanup_free_ char *operational_state = NULL; - _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains; - const char *on_color_operational, *off_color_operational; - - sd_network_get_operational_state(&operational_state); - operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - - printf("%s%s%s State: %s%s%s\n", - on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, - on_color_operational, strna(operational_state), off_color_operational); - - dump_addresses(rtnl, " Address: ", 0); - dump_gateways(rtnl, hwdb, " Gateway: ", 0); - - sd_network_get_dns(&dns); - dump_list(" DNS: ", dns); - - sd_network_get_search_domains(&search_domains); - dump_list("Search Domains: ", search_domains); - - sd_network_get_route_domains(&route_domains); - dump_list(" Route Domains: ", route_domains); - - sd_network_get_ntp(&ntp); - dump_list(" NTP: ", ntp); - - return 0; - } +static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { + _cleanup_free_ char *operational_state = NULL; + _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL; + const char *on_color_operational, *off_color_operational; - pager_open_if_enabled(); + assert(rtnl); - if (arg_all) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_free_ LinkInfo *links = NULL; - int c, i; + (void) sd_network_get_operational_state(&operational_state); + operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); - if (r < 0) - return rtnl_log_create_error(r); + printf("%s%s%s State: %s%s%s\n", + on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, + on_color_operational, strna(operational_state), off_color_operational); - r = sd_netlink_message_request_dump(req, true); - if (r < 0) - return rtnl_log_create_error(r); + (void) dump_addresses(rtnl, " Address: ", 0); + (void) dump_gateways(rtnl, hwdb, " Gateway: ", 0); - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return log_error_errno(r, "Failed to enumerate links: %m"); + (void) sd_network_get_dns(&dns); + dump_list(" DNS: ", dns); - c = decode_and_sort_links(reply, &links); - if (c < 0) - return rtnl_log_parse_error(c); + (void) sd_network_get_search_domains(&search_domains); + dump_list("Search Domains: ", search_domains); - for (i = 0; i < c; i++) { - if (i > 0) - fputc('\n', stdout); + (void) sd_network_get_route_domains(&route_domains); + dump_list(" Route Domains: ", route_domains); - link_status_one(rtnl, hwdb, links[i].name); - } - } else { - STRV_FOREACH(name, argv + 1) { - if (name != argv + 1) - fputc('\n', stdout); - - link_status_one(rtnl, hwdb, *name); - } - } + (void) sd_network_get_ntp(&ntp); + dump_list(" NTP: ", ntp); return 0; } -const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_; -LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_; - -static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = { - [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O", - [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P", - [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B", - [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W", - [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R", - [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T", - [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D", - [LLDP_SYSTEM_CAPABILITIES_STATION] = "A", - [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C", - [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S", - [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M", - [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A", -}; - -DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities); - -static char *lldp_system_caps(uint16_t cap) { - _cleanup_free_ char *s = NULL, *t = NULL; - char *capability; - - t = strdup("[ "); - if (!t) - return NULL; - - if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } +static int link_status(int argc, char *argv[], void *userdata) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; + _cleanup_free_ LinkInfo *links = NULL; + int r, c, i; - if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL); - if (!s) - return NULL; + pager_open(arg_no_pager, false); - free(t); - t = s; - } + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); - if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL); - if (!s) - return NULL; + r = sd_hwdb_new(&hwdb); + if (r < 0) + log_debug_errno(r, "Failed to open hardware database: %m"); - free(t); - t = s; - } + if (arg_all) + c = acquire_link_info_all(rtnl, &links); + else if (argc <= 1) + return system_status(rtnl, hwdb); + else + c = acquire_link_info_strv(rtnl, argv + 1, &links); + if (c < 0) + return c; - if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL); - if (!s) - return NULL; + for (i = 0; i < c; i++) { + if (i > 0) + fputc('\n', stdout); - free(t); - t = s; + link_status_one(rtnl, hwdb, links + i); } - if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } + return 0; +} - if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) { - s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR)); - if (!s) - return NULL; +static char *lldp_capabilities_to_string(uint16_t x) { + static const char characters[] = { + 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm', + }; + char *ret; + unsigned i; - free(t); - } + ret = new(char, ELEMENTSOF(characters) + 1); + if (!ret) + return NULL; - if (!s) { - s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX)); - if (!s) - return NULL; + for (i = 0; i < ELEMENTSOF(characters); i++) + ret[i] = (x & (1U << i)) ? characters[i] : '.'; - free(t); - } + ret[i] = 0; + return ret; +} - t = strappend(s, "]"); - if (!t) - return NULL; +static void lldp_capabilities_legend(uint16_t x) { + unsigned w, i, cols = columns(); + static const char* const table[] = { + "o - Other", + "p - Repeater", + "b - Bridge", + "w - WLAN Access Point", + "r - Router", + "t - Telephone", + "d - DOCSIS cable device", + "a - Station", + "c - Customer VLAN", + "s - Service VLAN", + "m - Two-port MAC Relay (TPMR)", + }; - free(s); - capability = t; + if (x == 0) + return; - s = NULL; - t = NULL; + printf("\nCapability Flags:\n"); + for (w = 0, i = 0; i < ELEMENTSOF(table); i++) + if (x & (1U << i) || arg_all) { + bool newline; - return capability; + newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols; + if (newline) + w = 0; + w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]); + } + puts(""); } static int link_lldp_status(int argc, char *argv[], void *userdata) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; - double ttl = -1; - uint32_t capability; - int i, r, c, j; - const char *p; - char **s; - - pager_open_if_enabled(); + int i, r, c, m = 0; + uint16_t all = 0; r = sd_netlink_open(&rtnl); if (r < 0) return log_error_errno(r, "Failed to connect to netlink: %m"); - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_message_request_dump(req, true); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return log_error_errno(r, "Failed to enumerate links: %m"); - - c = decode_and_sort_links(reply, &links); + if (argc > 1) + c = acquire_link_info_strv(rtnl, argv + 1, &links); + else + c = acquire_link_info_all(rtnl, &links); if (c < 0) - return rtnl_log_parse_error(c); + return c; + + pager_open(arg_no_pager, false); if (arg_legend) - printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability"); + printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", + "LINK", + "CHASSIS ID", + "SYSTEM NAME", + "CAPS", + "PORT ID", + "PORT DESCRIPTION"); - for (i = j = 0; i < c; i++) { - _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL; - _cleanup_strv_free_ char **l = NULL; + for (i = 0; i < c; i++) { + _cleanup_fclose_ FILE *f = NULL; - r = sd_network_link_get_lldp(links[i].ifindex, &lldp); - if (r < 0) + r = open_lldp_neighbors(links[i].ifindex, &f); + if (r == -ENOENT) continue; + if (r < 0) { + log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex); + continue; + } - l = strv_split_newlines(lldp); - if (!l) - return -ENOMEM; - - STRV_FOREACH(s, l) { - - p = *s; - for (;;) { - _cleanup_free_ char *a = NULL, *b = NULL, *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s); - - if (r == 0) - break; - - r = split_pair(word, "=", &a, &b); - if (r < 0) - continue; - - if (streq(a, "_Chassis")) { - r = free_and_strdup(&chassis, b); - if (r < 0) - return r; - - } else if (streq(a, "_Port")) { - r = free_and_strdup(&port, b); - if (r < 0) - return r; - - } else if (streq(a, "_TTL")) { - long long unsigned x = 0; - usec_t time; + for (;;) { + _cleanup_free_ char *cid = NULL, *pid = NULL, *sname = NULL, *pdesc = NULL; + const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL, *capabilities = NULL; + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + uint16_t cc; - r = safe_atollu(b, &x); - if (r < 0 || (usec_t) x != x) - return log_warning_errno(r < 0 ? r : ERANGE, - "Failed to parse TTL \"%s\": %m", b); + r = next_lldp_neighbor(f, &n); + if (r < 0) { + log_warning_errno(r, "Failed to read neighbor data: %m"); + break; + } + if (r == 0) + break; - time = now(clock_boottime_or_monotonic()); - if (x < time) - continue; + (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id); + (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); + (void) sd_lldp_neighbor_get_system_name(n, &system_name); + (void) sd_lldp_neighbor_get_port_description(n, &port_description); - ttl = (double) (x - time) / USEC_PER_SEC; + if (chassis_id) { + cid = ellipsize(chassis_id, 17, 100); + if (cid) + chassis_id = cid; + } - } else if (streq(a, "_CAP")) { - sscanf(b, "%x", &capability); + if (port_id) { + pid = ellipsize(port_id, 17, 100); + if (pid) + port_id = pid; + } - cap = lldp_system_caps(capability); - } + if (system_name) { + sname = ellipsize(system_name, 16, 100); + if (sname) + system_name = sname; + } + if (port_description) { + pdesc = ellipsize(port_description, 16, 100); + if (pdesc) + port_description = pdesc; } - if (ttl >= 0) { - printf("%10s %24s %16s %16f %16s\n", - links[i].name, - strna(chassis), strna(port), - ttl, cap); - j++; + if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) { + capabilities = lldp_capabilities_to_string(cc); + all |= cc; } + + printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", + links[i].name, + strna(chassis_id), + strna(system_name), + strna(capabilities), + strna(port_id), + strna(port_description)); + + m++; } } if (arg_legend) { - printf("\nCapability Codes:\n" - "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n" - "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n" - "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n"); - - printf("Total entries displayed: %d\n", j); + lldp_capabilities_legend(all); + printf("\n%i neighbors listed.\n", m); } return 0; @@ -1020,9 +1040,9 @@ static void help(void) { " --no-legend Do not show the headers and footers\n" " -a --all Show status for all links\n\n" "Commands:\n" - " list List links\n" + " list [LINK...] List links\n" " status [LINK...] Show link status\n" - " lldp Show lldp information\n" + " lldp [LINK...] Show LLDP neighbors\n" , program_invocation_short_name); } @@ -1084,15 +1104,23 @@ static int parse_argv(int argc, char *argv[]) { static int networkctl_main(int argc, char *argv[]) { const Verb verbs[] = { - { "list", VERB_ANY, 1, VERB_DEFAULT, list_links }, - { "status", 1, VERB_ANY, 0, link_status }, - { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status }, + { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links }, + { "status", VERB_ANY, VERB_ANY, 0, link_status }, + { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status }, {} }; return dispatch_verb(argc, argv, verbs, NULL); } +static void warn_networkd_missing(void) { + + if (access("/run/systemd/netif/state", F_OK) >= 0) + return; + + fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n"); +} + int main(int argc, char* argv[]) { int r; @@ -1103,6 +1131,8 @@ int main(int argc, char* argv[]) { if (r <= 0) goto finish; + warn_networkd_missing(); + r = networkctl_main(argc, argv); finish: diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c new file mode 100644 index 0000000000..8b149124b3 --- /dev/null +++ b/src/network/networkd-conf.c @@ -0,0 +1,155 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Vinay Kulkarni <kulkarniv@vmware.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 <ctype.h> + +#include "conf-parser.h" +#include "def.h" +#include "dhcp-identifier.h" +#include "networkd-conf.h" +#include "string-table.h" + +int manager_parse_config_file(Manager *m) { + assert(m); + + return config_parse_many(PKGSYSCONFDIR "/networkd.conf", + CONF_PATHS_NULSTR("systemd/networkd.conf.d"), + "DUID\0", + config_item_perf_lookup, networkd_gperf_lookup, + false, m); +} + +static const char* const duid_type_table[_DUID_TYPE_MAX] = { + [DUID_TYPE_RAW] = "raw", + [DUID_TYPE_LLT] = "link-layer-time", + [DUID_TYPE_EN] = "vendor", + [DUID_TYPE_LL] = "link-layer", + [DUID_TYPE_UUID] = "uuid" +}; +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); +DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type"); + +int config_parse_duid_rawdata( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + int r; + long byte; + char *cbyte, *pnext; + const char *pduid = rvalue; + size_t count = 0, duid_index = 0; + Manager *m; + Network *n; + DUIDType *duid_type; + uint16_t *dhcp_duid_type; + size_t *dhcp_duid_len; + uint8_t *dhcp_duid; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(userdata); + + if (ltype == DUID_CONFIG_SOURCE_GLOBAL) { + m = userdata; + duid_type = &m->duid_type; + dhcp_duid_type = &m->dhcp_duid_type; + dhcp_duid_len = &m->dhcp_duid_len; + dhcp_duid = m->dhcp_duid; + } else { + /* DUID_CONFIG_SOURCE_NETWORK */ + n = userdata; + duid_type = &n->duid_type; + dhcp_duid_type = &n->dhcp_duid_type; + dhcp_duid_len = &n->dhcp_duid_len; + dhcp_duid = n->dhcp_duid; + } + + if (*duid_type == _DUID_TYPE_INVALID) + *duid_type = DUID_TYPE_RAW; + + switch (*duid_type) { + case DUID_TYPE_LLT: + /* RawData contains DUID-LLT link-layer address (offset 6) */ + duid_index = 6; + break; + case DUID_TYPE_EN: + /* RawData contains DUID-EN identifier (offset 4) */ + duid_index = 4; + break; + case DUID_TYPE_LL: + /* RawData contains DUID-LL link-layer address (offset 2) */ + duid_index = 2; + break; + case DUID_TYPE_UUID: + /* RawData specifies UUID (offset 0) - fall thru */ + case DUID_TYPE_RAW: + /* First two bytes of RawData is DUID Type - fall thru */ + default: + break; + } + + if (*duid_type != DUID_TYPE_RAW) + *dhcp_duid_type = (uint16_t)(*duid_type); + + /* RawData contains DUID in format " NN:NN:NN... " */ + while (true) { + r = extract_first_word(&pduid, &cbyte, ":", 0); + if (r < 0) { + log_error("Failed to read DUID."); + return -EINVAL; + } + if (r == 0) + break; + if (duid_index >= MAX_DUID_LEN) { + log_error("DUID length exceeds maximum length."); + return -EINVAL; + } + + errno = 0; + byte = strtol(cbyte, &pnext, 16); + if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) + || (errno != 0 && byte == 0) || (cbyte == pnext)) { + log_error("Invalid DUID byte: %s.", cbyte); + return -EINVAL; + } + + /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */ + if ((*duid_type == DUID_TYPE_RAW) && (count < 2)) { + *dhcp_duid_type |= (byte << (8 * (1 - count))); + count++; + continue; + } + + dhcp_duid[duid_index++] = byte; + } + + *dhcp_duid_len = duid_index; + + return 0; +} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h new file mode 100644 index 0000000000..efc370f839 --- /dev/null +++ b/src/network/networkd-conf.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Vinay Kulkarni <kulkarniv@vmware.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 "networkd.h" + +typedef enum DuidConfigSource { + DUID_CONFIG_SOURCE_GLOBAL = 0, + DUID_CONFIG_SOURCE_NETWORK, +} DuidConfigSource; + +int manager_parse_config_file(Manager *m); + +const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); + +int config_parse_duid_type(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_duid_rawdata(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 03c28bbcb6..0589ebf227 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -34,7 +34,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, assert(link); assert(link->dhcp4_messages > 0); - link->dhcp4_messages --; + link->dhcp4_messages--; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -96,7 +96,7 @@ static int link_set_dhcp_routes(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "Could not set host route: %m"); - link->dhcp4_messages ++; + link->dhcp4_messages++; route->family = AF_INET; route->gw.in = gateway; @@ -110,7 +110,7 @@ static int link_set_dhcp_routes(Link *link) { return r; } - link->dhcp4_messages ++; + link->dhcp4_messages++; } n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes); @@ -137,7 +137,7 @@ static int link_set_dhcp_routes(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "Could not set host route: %m"); - link->dhcp4_messages ++; + link->dhcp4_messages++; } return 0; @@ -625,7 +625,21 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: - /* Library defaults to this. */ + /* If configured, apply user specified DUID and/or IAID */ + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return r; break; case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 5f7a005c36..d4b2fbfc57 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -230,6 +230,23 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; + r = sd_dhcp6_client_set_iaid(client, link->network->iaid); + if (r < 0) + goto error; + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp6_client_set_duid(client, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp6_client_set_duid(client, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + goto error; + r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 1538caa204..241f486211 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -37,7 +37,7 @@ int fdb_entry_new_static(Network *const network, assert(network); /* search entry in hashmap first. */ - if(section) { + if (section) { fdb_entry = hashmap_get(network->fdb_entries_by_section, UINT_TO_PTR(section)); if (fdb_entry) { *ret = fdb_entry; @@ -141,10 +141,10 @@ int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) { /* remove and FDB entry. */ void fdb_entry_free(FdbEntry *fdb_entry) { - if(!fdb_entry) + if (!fdb_entry) return; - if(fdb_entry->network) { + if (fdb_entry->network) { LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, fdb_entry); diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf new file mode 100644 index 0000000000..0625fb335b --- /dev/null +++ b/src/network/networkd-gperf.gperf @@ -0,0 +1,18 @@ +%{ +#include <stddef.h> +#include "conf-parser.h" +#include "networkd-conf.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name networkd_gperf_hash +%define lookup-function-name networkd_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +DUID.Type, config_parse_duid_type, 0, offsetof(Manager, duid_type) +DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 949c75337c..e05fd3eea7 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -165,7 +165,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { return 0; } -static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){ +static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) { Link *link = userdata; int r; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 692c0bf63d..88b3cbe90a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -29,6 +29,7 @@ #include "netlink-util.h" #include "network-internal.h" #include "networkd-link.h" +#include "networkd-lldp-tx.h" #include "networkd-netdev.h" #include "set.h" #include "socket-util.h" @@ -38,7 +39,9 @@ #include "util.h" #include "virt.h" -bool link_dhcp6_enabled(Link *link) { +static bool link_dhcp6_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -48,7 +51,9 @@ bool link_dhcp6_enabled(Link *link) { return link->network->dhcp & ADDRESS_FAMILY_IPV6; } -bool link_dhcp4_enabled(Link *link) { +static bool link_dhcp4_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -58,7 +63,9 @@ bool link_dhcp4_enabled(Link *link) { return link->network->dhcp & ADDRESS_FAMILY_IPV4; } -bool link_dhcp4_server_enabled(Link *link) { +static bool link_dhcp4_server_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -68,7 +75,9 @@ bool link_dhcp4_server_enabled(Link *link) { return link->network->dhcp_server; } -bool link_ipv4ll_enabled(Link *link) { +static bool link_ipv4ll_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -78,7 +87,9 @@ bool link_ipv4ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV4; } -bool link_ipv6ll_enabled(Link *link) { +static bool link_ipv6ll_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -88,20 +99,42 @@ bool link_ipv6ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV6; } -bool link_lldp_enabled(Link *link) { +static bool link_lldp_rx_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; + if (link->iftype != ARPHRD_ETHER) + return false; + if (!link->network) return false; if (link->network->bridge) return false; - return link->network->lldp; + return link->network->lldp_mode != LLDP_MODE_NO; +} + +static bool link_lldp_tx_enabled(Link *link) { + assert(link); + + if (link->flags & IFF_LOOPBACK) + return false; + + if (link->iftype != ARPHRD_ETHER) + return false; + + if (!link->network) + return false; + + return link->network->lldp_emit; } static bool link_ipv4_forward_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -115,6 +148,7 @@ static bool link_ipv4_forward_enabled(Link *link) { } static bool link_ipv6_forward_enabled(Link *link) { + assert(link); if (!socket_ipv6_is_supported()) return false; @@ -131,7 +165,9 @@ static bool link_ipv6_forward_enabled(Link *link) { return link->network->ip_forward & ADDRESS_FAMILY_IPV6; } -bool link_ipv6_accept_ra_enabled(Link *link) { +static bool link_ipv6_accept_ra_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -300,6 +336,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { uint16_t type; const char *ifname; int r, ifindex; + unsigned short iftype; assert(manager); assert(message); @@ -317,6 +354,10 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { else if (ifindex <= 0) return -EINVAL; + r = sd_rtnl_message_link_get_type(message, &iftype); + if (r < 0) + return r; + r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname); if (r < 0) return r; @@ -330,30 +371,24 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { link->state = LINK_STATE_PENDING; link->rtnl_extended_attrs = true; link->ifindex = ifindex; + link->iftype = iftype; link->ifname = strdup(ifname); if (!link->ifname) return -ENOMEM; r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac); if (r < 0) - log_link_debug(link, "MAC address not found for new device, continuing without"); + log_link_debug_errno(link, r, "MAC address not found for new device, continuing without"); - r = asprintf(&link->state_file, "/run/systemd/netif/links/%d", - link->ifindex); - if (r < 0) + if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0) return -ENOMEM; - r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", - link->ifindex); - if (r < 0) + if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0) return -ENOMEM; - r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", - link->ifindex); - if (r < 0) + if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0) return -ENOMEM; - r = hashmap_ensure_allocated(&manager->links, NULL); if (r < 0) return r; @@ -399,10 +434,11 @@ static void link_free(Link *link) { sd_dhcp_client_unref(link->dhcp_client); sd_dhcp_lease_unref(link->dhcp_lease); + link_lldp_tx_stop(link); + free(link->lease_file); sd_lldp_unref(link->lldp); - free(link->lldp_file); sd_ipv4ll_unref(link->ipv4ll); @@ -436,7 +472,7 @@ Link *link_unref(Link *link) { assert(link->n_ref > 0); - link->n_ref --; + link->n_ref--; if (link->n_ref > 0) return NULL; @@ -452,7 +488,7 @@ Link *link_ref(Link *link) { assert(link->n_ref > 0); - link->n_ref ++; + link->n_ref++; return link; } @@ -506,33 +542,28 @@ static int link_stop_clients(Link *link) { if (link->dhcp_client) { k = sd_dhcp_client_stop(link->dhcp_client); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop DHCPv4 client: %m"); + r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m"); } if (link->ipv4ll) { k = sd_ipv4ll_stop(link->ipv4ll); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m"); + r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m"); } if (link->dhcp6_client) { k = sd_dhcp6_client_stop(link->dhcp6_client); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m"); + r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m"); } if (link->ndisc_router_discovery) { k = sd_ndisc_stop(link->ndisc_router_discovery); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m"); - } - - if (link->lldp) { - k = sd_lldp_stop(link->lldp); - if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop LLDP: %m"); + r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } + link_lldp_tx_stop(link); return r; } @@ -645,7 +676,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED, LINK_STATE_LINGER)); - link->link_messages --; + link->link_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; @@ -681,7 +712,7 @@ static int link_enter_set_routes(Link *link) { return r; } - link->link_messages ++; + link->link_messages++; } if (link->link_messages == 0) { @@ -723,7 +754,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES, LINK_STATE_FAILED, LINK_STATE_LINGER)); - link->link_messages --; + link->link_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; @@ -850,7 +881,7 @@ static int link_enter_set_addresses(Link *link) { return r; } - link->link_messages ++; + link->link_messages++; } /* now that we can figure out a default address for the dhcp server, @@ -999,7 +1030,7 @@ static int link_set_bridge_fdb(Link *const link) { LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) { r = fdb_entry_configure(link, fdb_entry); - if(r < 0) { + if (r < 0) { log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m"); break; } @@ -1211,7 +1242,7 @@ static int link_set_bridge(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m"); - if(link->network->cost != 0) { + if (link->network->cost != 0) { r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m"); @@ -1230,23 +1261,93 @@ static int link_set_bridge(Link *link) { return r; } -static void lldp_handler(sd_lldp *lldp, int event, void *userdata) { +static int link_lldp_save(Link *link) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + sd_lldp_neighbor **l = NULL; + int n = 0, r, i; + + assert(link); + assert(link->lldp_file); + + if (!link->lldp) { + (void) unlink(link->lldp_file); + return 0; + } + + r = sd_lldp_get_neighbors(link->lldp, &l); + if (r < 0) + goto finish; + if (r == 0) { + (void) unlink(link->lldp_file); + goto finish; + } + + n = r; + + r = fopen_temporary(link->lldp_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); + + for (i = 0; i < n; i++) { + const void *p; + le64_t u; + size_t sz; + + r = sd_lldp_neighbor_get_raw(l[i], &p, &sz); + if (r < 0) + goto finish; + + u = htole64(sz); + (void) fwrite(&u, 1, sizeof(u), f); + (void) fwrite(p, 1, sz, f); + } + + r = fflush_and_check(f); + if (r < 0) + goto finish; + + if (rename(temp_path, link->lldp_file) < 0) { + r = -errno; + goto finish; + } + +finish: + if (r < 0) { + (void) unlink(link->lldp_file); + if (temp_path) + (void) unlink(temp_path); + + log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file); + } + + if (l) { + for (i = 0; i < n; i++) + sd_lldp_neighbor_unref(l[i]); + free(l); + } + + return r; +} + +static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) { Link *link = userdata; int r; assert(link); - assert(link->network); - assert(link->manager); - switch (event) { - case SD_LLDP_EVENT_UPDATE_INFO: - r = sd_lldp_save(link->lldp, link->lldp_file); - if (r < 0) - log_link_warning_errno(link, r, "Could not save LLDP: %m"); + (void) link_lldp_save(link); + + if (link_lldp_tx_enabled(link) && event == SD_LLDP_EVENT_ADDED) { + /* If we received information about a new neighbor, restart the LLDP "fast" logic */ - break; - default: - break; + log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission."); + + r = link_lldp_tx_start(link); + if (r < 0) + log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m"); } } @@ -1311,14 +1412,10 @@ static int link_acquire_conf(Link *link) { return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m"); } - if (link_lldp_enabled(link)) { - assert(link->lldp); - - log_link_debug(link, "Starting LLDP"); - - r = sd_lldp_start(link->lldp); + if (link_lldp_tx_enabled(link)) { + r = link_lldp_tx_start(link); if (r < 0) - return log_link_warning_errno(link, r, "Could not start LLDP: %m"); + return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m"); } return 0; @@ -1559,7 +1656,7 @@ static int link_new_bound_by_list(Link *link) { m = link->manager; - HASHMAP_FOREACH (carrier, m->links, i) { + HASHMAP_FOREACH(carrier, m->links, i) { if (!carrier->network) continue; @@ -1578,7 +1675,7 @@ static int link_new_bound_by_list(Link *link) { if (list_updated) link_dirty(link); - HASHMAP_FOREACH (carrier, link->bound_by_links, i) { + HASHMAP_FOREACH(carrier, link->bound_by_links, i) { r = link_put_carrier(carrier, link, &carrier->bound_to_links); if (r < 0) return r; @@ -1738,7 +1835,7 @@ static int link_joined(Link *link) { } } - if(link->network->bridge) { + if (link->network->bridge) { r = link_set_bridge(link); if (r < 0) log_link_error_errno(link, r, "Could not set bridge message: %m"); @@ -1754,7 +1851,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us assert(link); assert(link->network); - link->enslaving --; + link->enslaving--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; @@ -1810,7 +1907,7 @@ static int link_enter_join_netdev(Link *link) { return r; } - link->enslaving ++; + link->enslaving++; } if (link->network->bridge) { @@ -1831,7 +1928,7 @@ static int link_enter_join_netdev(Link *link) { return r; } - link->enslaving ++; + link->enslaving++; } HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { @@ -1853,7 +1950,7 @@ static int link_enter_join_netdev(Link *link) { return r; } - link->enslaving ++; + link->enslaving++; } return 0; @@ -2030,6 +2127,27 @@ static int link_drop_foreign_config(Link *link) { return 0; } +static int link_update_lldp(Link *link) { + int r; + + assert(link); + + if (!link->lldp) + return 0; + + if (link->flags & IFF_UP) { + r = sd_lldp_start(link->lldp); + if (r > 0) + log_link_debug(link, "Started LLDP."); + } else { + r = sd_lldp_stop(link->lldp); + if (r > 0) + log_link_debug(link, "Stopped LLDP."); + } + + return r; +} + static int link_configure(Link *link) { int r; @@ -2108,8 +2226,19 @@ static int link_configure(Link *link) { return r; } - if (link_lldp_enabled(link)) { - r = sd_lldp_new(link->ifindex, link->ifname, &link->mac, &link->lldp); + if (link_lldp_rx_enabled(link)) { + r = sd_lldp_new(&link->lldp, link->ifindex); + if (r < 0) + return r; + + r = sd_lldp_match_capabilities(link->lldp, + link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ? + SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS : + SD_LLDP_SYSTEM_CAPABILITIES_ALL); + if (r < 0) + return r; + + r = sd_lldp_set_filter_address(link->lldp, &link->mac); if (r < 0) return r; @@ -2117,8 +2246,11 @@ static int link_configure(Link *link) { if (r < 0) return r; - r = sd_lldp_set_callback(link->lldp, - lldp_handler, link); + r = sd_lldp_set_callback(link->lldp, lldp_handler, link); + if (r < 0) + return r; + + r = link_update_lldp(link); if (r < 0) return r; } @@ -2307,7 +2439,7 @@ network_file_fail: continue; } - *prefixlen_str ++ = '\0'; + *prefixlen_str++ = '\0'; r = sscanf(prefixlen_str, "%hhu", &prefixlen); if (r != 1) { @@ -2354,7 +2486,7 @@ network_file_fail: continue; } - *prefixlen_str ++ = '\0'; + *prefixlen_str++ = '\0'; r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime); if (r != 5) { @@ -2562,7 +2694,6 @@ int link_carrier_reset(Link *link) { return 0; } - int link_update(Link *link, sd_netlink_message *m) { struct ether_addr mac; const char *ifname; @@ -2649,6 +2780,21 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { @@ -2658,6 +2804,24 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m"); + + r = sd_dhcp6_client_set_iaid(link->dhcp6_client, + link->network->iaid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } } } @@ -2668,6 +2832,10 @@ int link_update(Link *link, sd_netlink_message *m) { if (r < 0) return r; + r = link_update_lldp(link); + if (r < 0) + return r; + carrier_gained = !had_carrier && link_has_carrier(link); carrier_lost = had_carrier && !link_has_carrier(link); @@ -2683,12 +2851,34 @@ int link_update(Link *link, sd_netlink_message *m) { r = link_carrier_lost(link); if (r < 0) return r; - } return 0; } +static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { + bool space = false; + Iterator i; + Link *link; + + assert(f); + assert(prefix); + + if (hashmap_isempty(h)) + return; + + fputs(prefix, f); + HASHMAP_FOREACH(link, h, i) { + if (space) + fputc(' ', f); + + fprintf(f, "%i", link->ifindex); + space = true; + } + + fputc('\n', f); +} + int link_save(Link *link) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -2708,6 +2898,8 @@ int link_save(Link *link) { return 0; } + link_lldp_save(link); + admin_state = link_state_to_string(link->state); assert(admin_state); @@ -2887,27 +3079,8 @@ int link_save(Link *link) { fputc('\n', f); } - if (!hashmap_isempty(link->bound_to_links)) { - Link *carrier; - bool space = false; - - fputs("CARRIER_BOUND_TO=", f); - HASHMAP_FOREACH(carrier, link->bound_to_links, i) - fputs_with_space(f, carrier->ifname, NULL, &space); - - fputc('\n', f); - } - - if (!hashmap_isempty(link->bound_by_links)) { - Link *carrier; - bool space = false; - - fputs("CARRIER_BOUND_BY=", f); - HASHMAP_FOREACH(carrier, link->bound_by_links, i) - fputs_with_space(f, carrier->ifname, NULL, &space); - - fputc('\n', f); - } + print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links); + print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links); if (link->dhcp_lease) { struct in_addr address; @@ -2947,19 +3120,6 @@ int link_save(Link *link) { } } - if (link->lldp) { - assert(link->network); - - r = sd_lldp_save(link->lldp, link->lldp_file); - if (r < 0) - goto fail; - - fprintf(f, - "LLDP_FILE=%s\n", - link->lldp_file); - } else - unlink(link->lldp_file); - r = fflush_and_check(f); if (r < 0) goto fail; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 0e6a7b6f21..f2a64ca9b5 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -65,6 +65,7 @@ struct Link { int ifindex; char *ifname; + unsigned short iftype; char *state_file; struct ether_addr mac; struct in6_addr ipv6ll_address; @@ -111,9 +112,14 @@ struct Link { sd_dhcp6_client *dhcp6_client; bool rtnl_extended_attrs; + /* This is about LLDP reception */ sd_lldp *lldp; char *lldp_file; + /* This is about LLDP transmission */ + unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */ + sd_event_source *lldp_tx_event_source; + Hashmap *bound_by_links; Hashmap *bound_to_links; }; @@ -154,14 +160,6 @@ int dhcp6_configure(Link *link); int dhcp6_request_address(Link *link); int ndisc_configure(Link *link); -bool link_lldp_enabled(Link *link); -bool link_ipv4ll_enabled(Link *link); -bool link_ipv6ll_enabled(Link *link); -bool link_dhcp4_server_enabled(Link *link); -bool link_dhcp4_enabled(Link *link); -bool link_dhcp6_enabled(Link *link); -bool link_ipv6_accept_ra_enabled(Link *link); - const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c new file mode 100644 index 0000000000..5af2a31ea7 --- /dev/null +++ b/src/network/networkd-lldp-tx.c @@ -0,0 +1,346 @@ +/*** + 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 <endian.h> +#include <inttypes.h> +#include <string.h> + +#include "fd-util.h" +#include "fileio.h" +#include "hostname-util.h" +#include "networkd-lldp-tx.h" +#include "random-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "unaligned.h" + +/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */ +#define LLDP_TX_FAST_INIT 4U + +/* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */ +#define LLDP_TX_HOLD 4U + +/* The jitter range to add, see 9.2.2. */ +#define LLDP_JITTER_USEC (400U * USEC_PER_MSEC) + +/* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */ +#define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2) + +/* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */ +#define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2) + +static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) { + assert(p); + + if (id > 127) + return -EBADMSG; + if (sz > 511) + return -ENOBUFS; + + (*p)[0] = (id << 1) | !!(sz & 256); + (*p)[1] = sz & 255; + + *p = *p + 2; + return 0; +} + +static int lldp_make_packet( + const struct ether_addr *hwaddr, + const char *machine_id, + const char *ifname, + uint16_t ttl, + const char *port_description, + const char *hostname, + const char *pretty_hostname, + uint16_t system_capabilities, + uint16_t enabled_capabilities, + void **ret, size_t *sz) { + + size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0; + _cleanup_free_ void *packet = NULL; + struct ether_header *h; + uint8_t *p; + size_t l; + int r; + + assert(hwaddr); + assert(machine_id); + assert(ifname); + assert(ret); + assert(sz); + + machine_id_length = strlen(machine_id); + ifname_length = strlen(ifname); + + if (port_description) + port_description_length = strlen(port_description); + + if (hostname) + hostname_length = strlen(hostname); + + if (pretty_hostname) + pretty_hostname_length = strlen(pretty_hostname); + + l = sizeof(struct ether_header) + + /* Chassis ID */ + 2 + 1 + machine_id_length + + /* Port ID */ + 2 + 1 + ifname_length + + /* TTL */ + 2 + 2 + + /* System Capabilities */ + 2 + 4 + + /* End */ + 2; + + /* Port Description */ + if (port_description) + l += 2 + port_description_length; + + /* System Name */ + if (hostname) + l += 2 + hostname_length; + + /* System Description */ + if (pretty_hostname) + l += 2 + pretty_hostname_length; + + packet = malloc(l); + if (!packet) + return -ENOMEM; + + h = (struct ether_header*) packet; + h->ether_type = htobe16(ETHERTYPE_LLDP); + memcpy(h->ether_dhost, &(struct ether_addr) { SD_LLDP_MULTICAST_ADDR }, ETH_ALEN); + memcpy(h->ether_shost, hwaddr, ETH_ALEN); + + p = (uint8_t*) packet + sizeof(struct ether_header); + + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length); + if (r < 0) + return r; + *(p++) = SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED; + p = mempcpy(p, machine_id, machine_id_length); + + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_ID, 1 + ifname_length); + if (r < 0) + return r; + *(p++) = SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME; + p = mempcpy(p, ifname, ifname_length); + + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_TTL, 2); + if (r < 0) + return r; + unaligned_write_be16(p, ttl); + p += 2; + + if (port_description) { + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_DESCRIPTION, port_description_length); + if (r < 0) + return r; + p = mempcpy(p, port_description, port_description_length); + } + + if (hostname) { + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_NAME, hostname_length); + if (r < 0) + return r; + p = mempcpy(p, hostname, hostname_length); + } + + if (pretty_hostname) { + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length); + if (r < 0) + return r; + p = mempcpy(p, pretty_hostname, pretty_hostname_length); + } + + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4); + if (r < 0) + return r; + unaligned_write_be16(p, system_capabilities); + p += 2; + unaligned_write_be16(p, enabled_capabilities); + p += 2; + + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_END, 0); + if (r < 0) + return r; + + assert(p == (uint8_t*) packet + l); + + *ret = packet; + *sz = l; + + packet = NULL; + return 0; +} + +static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) { + + union sockaddr_union sa = { + .ll.sll_family = AF_PACKET, + .ll.sll_protocol = htobe16(ETHERTYPE_LLDP), + .ll.sll_ifindex = ifindex, + .ll.sll_halen = ETH_ALEN, + .ll.sll_addr = SD_LLDP_MULTICAST_ADDR, + }; + + _cleanup_close_ int fd = -1; + ssize_t l; + + assert(ifindex > 0); + assert(packet || packet_size <= 0); + + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW); + if (fd < 0) + return -errno; + + l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll)); + if (l < 0) + return -errno; + + if ((size_t) l != packet_size) + return -EIO; + + return 0; +} + +static int link_send_lldp(Link *link) { + char machine_id_string[SD_ID128_STRING_MAX]; + _cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL; + _cleanup_free_ void *packet = NULL; + size_t packet_size = 0; + sd_id128_t machine_id; + uint16_t caps; + usec_t ttl; + int r; + + r = sd_id128_get_machine(&machine_id); + if (r < 0) + return r; + + (void) gethostname_strict(&hostname); + (void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL); + + ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC); + if (ttl > (usec_t) UINT16_MAX) + ttl = (usec_t) UINT16_MAX; + + caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ? + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER : + SD_LLDP_SYSTEM_CAPABILITIES_STATION; + + r = lldp_make_packet(&link->mac, + sd_id128_to_string(machine_id, machine_id_string), + link->ifname, + (uint16_t) ttl, + link->network ? link->network->description : NULL, + hostname, + pretty_hostname, + SD_LLDP_SYSTEM_CAPABILITIES_STATION|SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE|SD_LLDP_SYSTEM_CAPABILITIES_ROUTER, + caps, + &packet, &packet_size); + if (r < 0) + return r; + + return lldp_send_packet(link->ifindex, packet, packet_size); +} + +static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { + Link *link = userdata; + usec_t current, delay, next; + int r; + + assert(s); + assert(userdata); + + log_link_debug(link, "Sending LLDP packet..."); + + r = link_send_lldp(link); + if (r < 0) + log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m"); + + if (link->lldp_tx_fast > 0) + link->lldp_tx_fast--; + + assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), ¤t) >= 0); + + delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC; + next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC); + + r = sd_event_source_set_time(s, next); + if (r < 0) + return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m"); + + r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); + if (r < 0) + return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m"); + + return 0; +} + +int link_lldp_tx_start(Link *link) { + usec_t next; + int r; + + assert(link); + + /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */ + + link->lldp_tx_fast = LLDP_TX_FAST_INIT; + + next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC), + (usec_t) random_u64() % LLDP_JITTER_USEC); + + if (link->lldp_tx_event_source) { + usec_t old; + + /* Lower the timeout, maybe */ + r = sd_event_source_get_time(link->lldp_tx_event_source, &old); + if (r < 0) + return r; + + if (old <= next) + return 0; + + return sd_event_source_set_time(link->lldp_tx_event_source, next); + } else { + r = sd_event_add_time( + link->manager->event, + &link->lldp_tx_event_source, + clock_boottime_or_monotonic(), + next, + 0, + on_lldp_timer, + link); + if (r < 0) + return r; + + (void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx"); + } + + return 0; +} + +void link_lldp_tx_stop(Link *link) { + assert(link); + + link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source); +} diff --git a/src/bootchart/store.h b/src/network/networkd-lldp-tx.h index 6e9acf2a6f..8c7f403005 100644 --- a/src/bootchart/store.h +++ b/src/network/networkd-lldp-tx.h @@ -3,10 +3,7 @@ /*** This file is part of systemd. - Copyright (C) 2009-2013 Intel Corporation - - Authors: - Auke Kok <auke-jan.h.kok@intel.com> + 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 @@ -22,15 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <dirent.h> - -#include "bootchart.h" +#include "networkd-link.h" -double gettime_ns(void); -void log_uptime(void); -int log_sample(DIR *proc, - int sample, - struct ps_struct *ps_first, - struct list_sample_data **ptr, - int *pscount, - int *cpus); +int link_lldp_tx_start(Link *link); +void link_lldp_tx_stop(Link *link); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b8cb7f875d..d355aaa19c 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,6 +1037,8 @@ int manager_new(Manager **ret) { if (r < 0) return r; + m->duid_type = _DUID_TYPE_INVALID; + *ret = m; m = NULL; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index f2287be20a..4577292e44 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -19,6 +19,7 @@ #include <netinet/ether.h> #include <netinet/icmp6.h> +#include <netinet/in.h> #include <linux/if.h> #include "sd-ndisc.h" @@ -32,7 +33,7 @@ static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void * assert(link); assert(link->ndisc_messages > 0); - link->ndisc_messages --; + link->ndisc_messages--; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -76,15 +77,15 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8); else { /* see RFC4291 section 2.5.1 */ - address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0]; - address->in_addr.in6.__in6_u.__u6_addr8[8] ^= 1 << 1; - address->in_addr.in6.__in6_u.__u6_addr8[9] = link->mac.ether_addr_octet[1]; - address->in_addr.in6.__in6_u.__u6_addr8[10] = link->mac.ether_addr_octet[2]; - address->in_addr.in6.__in6_u.__u6_addr8[11] = 0xff; - address->in_addr.in6.__in6_u.__u6_addr8[12] = 0xfe; - address->in_addr.in6.__in6_u.__u6_addr8[13] = link->mac.ether_addr_octet[3]; - address->in_addr.in6.__in6_u.__u6_addr8[14] = link->mac.ether_addr_octet[4]; - address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5]; + address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0]; + address->in_addr.in6.s6_addr[8] ^= 1 << 1; + address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1]; + address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2]; + address->in_addr.in6.s6_addr[11] = 0xff; + address->in_addr.in6.s6_addr[12] = 0xfe; + address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3]; + address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4]; + address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5]; } address->prefixlen = prefixlen; address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR; @@ -98,7 +99,7 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr return; } - link->ndisc_messages ++; + link->ndisc_messages++; } static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) { @@ -136,7 +137,7 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre return; } - link->ndisc_messages ++; + link->ndisc_messages++; } static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) { @@ -186,7 +187,7 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a return; } - link->ndisc_messages ++; + link->ndisc_messages++; } static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index 106f15fabc..6b9cbcded6 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -375,7 +375,7 @@ int config_parse_arp_ip_target_address(const char *unit, } LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer); - b->n_arp_ip_targets ++; + b->n_arp_ip_targets++; buffer = NULL; } diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index b2bf7e15f1..27f26f7870 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct Bridge Bridge; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h index 29f75a149b..42da62ebe4 100644 --- a/src/network/networkd-netdev-dummy.h +++ b/src/network/networkd-netdev-dummy.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct Dummy Dummy; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/networkd-netdev-ipvlan.h index 5b85ef2150..4bd0b67866 100644 --- a/src/network/networkd-netdev-ipvlan.h +++ b/src/network/networkd-netdev-ipvlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct IPVlan IPVlan; #include "missing.h" diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h index 8b42684de6..622ef9ef53 100644 --- a/src/network/networkd-netdev-macvlan.h +++ b/src/network/networkd-netdev-macvlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct MacVlan MacVlan; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 46ff2974f4..7aaa041ba3 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -54,7 +54,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin assert(link); assert(m); assert(t); - assert(t->family == AF_INET || t->family != -1); + assert(IN_SET(t->family, AF_INET, AF_UNSPEC)); r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex); if (r < 0) @@ -87,7 +87,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink assert(link); assert(m); assert(t); - assert(t->family == AF_INET || t->family != -1); + assert(IN_SET(t->family, AF_INET, AF_UNSPEC)); r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex); if (r < 0) @@ -124,7 +124,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink t = GRETAP(netdev); assert(t); - assert(t->family == AF_INET || t->family != -1); + assert(IN_SET(t->family, AF_INET, AF_UNSPEC)); assert(link); assert(m); @@ -497,7 +497,7 @@ static void ipip_init(NetDev *n) { assert(t); t->pmtudisc = true; - t->family = -1; + t->family = AF_UNSPEC; } static void sit_init(NetDev *n) { @@ -507,7 +507,7 @@ static void sit_init(NetDev *n) { assert(t); t->pmtudisc = true; - t->family = -1; + t->family = AF_UNSPEC; } static void vti_init(NetDev *n) { @@ -538,7 +538,7 @@ static void gre_init(NetDev *n) { assert(t); t->pmtudisc = true; - t->family = -1; + t->family = AF_UNSPEC; } static void ip6gre_init(NetDev *n) { diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index ea1d9a79e7..0d41f80a3c 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct Tunnel Tunnel; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index ab9a1b0426..32917fe6d5 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -20,6 +20,7 @@ #include <net/if.h> #include <sys/ioctl.h> #include <linux/if_tun.h> +#include <netinet/if_ether.h> #include "alloc-util.h" #include "fd-util.h" @@ -87,7 +88,7 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) { assert(t); - if(t->user_name) { + if (t->user_name) { user = t->user_name; @@ -126,7 +127,7 @@ static int netdev_create_tuntap(NetDev *netdev) { int r; r = netdev_fill_tuntap_message(netdev, &ifr); - if(r < 0) + if (r < 0) return r; return netdev_tuntap_add(netdev, &ifr); diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h index b970b0ce3b..cbb7ee05a6 100644 --- a/src/network/networkd-netdev-tuntap.h +++ b/src/network/networkd-netdev-tuntap.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct TunTap TunTap; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h index f7fdf906ab..ae5785783c 100644 --- a/src/network/networkd-netdev-veth.h +++ b/src/network/networkd-netdev-veth.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct Veth Veth; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h index 8701c4b785..1de6a1cc36 100644 --- a/src/network/networkd-netdev-vlan.h +++ b/src/network/networkd-netdev-vlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct VLan VLan; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c index eb9a2c06b3..dabbd97c87 100644 --- a/src/network/networkd-netdev-vxlan.c +++ b/src/network/networkd-netdev-vxlan.c @@ -54,13 +54,13 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m"); - if(v->ttl) { + if (v->ttl) { r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TTL attribute: %m"); } - if(v->tos) { + if (v->tos) { r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TOS, v->tos); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TOS attribute: %m"); @@ -86,7 +86,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L3MISS attribute: %m"); - if(v->fdb_ageing) { + if (v->fdb_ageing) { r = sd_netlink_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m"); diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index 459ce53f5e..a4bb44635a 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - typedef struct VxLan VxLan; #include "in-addr-util.h" diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 3eacee824b..7ea825fcb4 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "list.h" typedef struct NetDev NetDev; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 409df1709f..9793938080 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -2,6 +2,7 @@ #include <stddef.h> #include "conf-parser.h" #include "networkd.h" +#include "networkd-conf.h" #include "network-internal.h" %} struct ConfigPerfItem; @@ -26,6 +27,9 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Link.IAID, config_parse_iaid, 0, offsetof(Network, iaid) +DUID.Type, config_parse_duid_type, 0, offsetof(Network, duid_type) +DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) @@ -40,7 +44,8 @@ Network.DHCPServer, config_parse_bool, Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) -Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) +Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) +Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 4315790093..5946ba18dc 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -119,6 +119,8 @@ static int network_load_one(Manager *manager, const char *filename) { network->allow_port_to_be_root = true; network->unicast_flood = true; + network->lldp_mode = LLDP_MODE_ROUTERS_ONLY; + network->llmnr = RESOLVE_SUPPORT_YES; network->mdns = RESOLVE_SUPPORT_NO; network->dnssec_mode = _DNSSEC_MODE_INVALID; @@ -129,10 +131,12 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_accept_ra = -1; network->ipv6_dad_transmits = -1; network->ipv6_hop_limit = -1; + network->duid_type = _DUID_TYPE_INVALID; r = config_parse(NULL, filename, file, "Match\0" "Link\0" + "DUID\0" "Network\0" "Address\0" "Route\0" @@ -627,10 +631,7 @@ int config_parse_ipv4ll( * config_parse_address_family_boolean(), except that it * applies only to IPv4 */ - if (parse_boolean(rvalue)) - *link_local |= ADDRESS_FAMILY_IPV4; - else - *link_local &= ~ADDRESS_FAMILY_IPV4; + SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue)); return 0; } @@ -994,6 +995,10 @@ int config_parse_dnssec_negative_trust_anchors( continue; } + r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops); + if (r < 0) + return log_oom(); + r = set_put(n->dnssec_negative_trust_anchors, w); if (r < 0) return log_oom(); @@ -1013,3 +1018,13 @@ static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES); + +DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting."); + +static const char* const lldp_mode_table[_LLDP_MODE_MAX] = { + [LLDP_MODE_NO] = "no", + [LLDP_MODE_YES] = "yes", + [LLDP_MODE_ROUTERS_ONLY] = "routers-only", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 03c3f206c3..5400a8bc9d 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -24,6 +24,7 @@ typedef struct Network Network; +#include "dhcp-identifier.h" #include "networkd-address.h" #include "networkd-fdb.h" #include "networkd-netdev.h" @@ -58,6 +59,14 @@ typedef enum DHCPUseDomains { _DHCP_USE_DOMAINS_INVALID = -1, } DHCPUseDomains; +typedef enum LLDPMode { + LLDP_MODE_NO = 0, + LLDP_MODE_YES = 1, + LLDP_MODE_ROUTERS_ONLY = 2, + _LLDP_MODE_MAX, + _LLDP_MODE_INVALID = -1, +} LLDPMode; + struct Network { Manager *manager; @@ -136,8 +145,16 @@ struct Network { struct ether_addr *mac; unsigned mtu; + uint32_t iaid; + /* Value of Type in [DUID] section */ + DUIDType duid_type; + /* DUID type code - RFC 3315 */ + uint16_t dhcp_duid_type; + size_t dhcp_duid_len; + uint8_t dhcp_duid[MAX_DUID_LEN]; - bool lldp; + LLDPMode lldp_mode; /* LLDP reception */ + bool lldp_emit; /* LLDP transmission */ LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); @@ -181,6 +198,7 @@ int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigne int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_lldp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* Legacy IPv4LL support */ int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); @@ -197,3 +215,6 @@ IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_; DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_; + +const char* lldp_mode_to_string(LLDPMode m) _const_; +LLDPMode lldp_mode_from_string(const char *s) _pure_; diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h index 421c2bdf44..f91995c306 100644 --- a/src/network/networkd-wait-online.h +++ b/src/network/networkd-wait-online.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "sd-event.h" #include "sd-netlink.h" #include "sd-network.h" diff --git a/src/network/networkd.c b/src/network/networkd.c index 3a2615e6fd..c8f81a2ca6 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -21,6 +21,7 @@ #include "capability-util.h" #include "networkd.h" +#include "networkd-conf.h" #include "signal-util.h" #include "user-util.h" @@ -89,6 +90,10 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_parse_config_file(m); + if (r < 0) + log_warning_errno(r, "Failed to parse configuration file: %m"); + r = manager_load_config(m); if (r < 0) { log_error_errno(r, "Could not load configuration files: %m"); diff --git a/src/network/networkd.h b/src/network/networkd.h index 7ee922621a..72a2438ac8 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <arpa/inet.h> #include "sd-bus.h" @@ -31,6 +31,7 @@ typedef struct Manager Manager; +#include "dhcp-identifier.h" #include "networkd-address-pool.h" #include "networkd-link.h" #include "networkd-network.h" @@ -61,6 +62,13 @@ struct Manager { LIST_HEAD(AddressPool, address_pools); usec_t network_dirs_ts_usec; + + /* Value of Type in [DUID] section */ + DUIDType duid_type; + /* DUID type code - RFC 3315 */ + uint16_t dhcp_duid_type; + size_t dhcp_duid_len; + uint8_t dhcp_duid[MAX_DUID_LEN]; }; extern const char* const network_dirs[]; diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index 1db5ba7116..f50f1ad6c2 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -55,8 +55,7 @@ int chown_cgroup(pid_t pid, uid_t uid_shift) { "cgroup.events", "cgroup.clone_children", "cgroup.controllers", - "cgroup.subtree_control", - "cgroup.populated") + "cgroup.subtree_control") if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, "Failed to chown() cgroup file %s, ignoring: %m", fn); @@ -73,7 +72,7 @@ int sync_cgroup(pid_t pid, bool unified_requested) { unified = cg_unified(); if (unified < 0) - return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m"); + return log_error_errno(unified, "Failed to determine whether the unified hierarchy is used: %m"); if ((unified > 0) == unified_requested) return 0; @@ -94,7 +93,7 @@ int sync_cgroup(pid_t pid, bool unified_requested) { if (unified) r = mount("cgroup", tree, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "none,name=systemd,xattr"); else - r = mount("cgroup", tree, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "__DEVEL__sane_behavior"); + r = mount("cgroup", tree, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); if (r < 0) { r = log_error_errno(errno, "Failed to mount unified hierarchy: %m"); goto finish; @@ -135,7 +134,7 @@ int create_subcgroup(pid_t pid, bool unified_requested) { unified = cg_unified(); if (unified < 0) - return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m"); + return log_error_errno(unified, "Failed to determine whether the unified hierarchy is used: %m"); if (unified == 0) return 0; diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 70cca15278..8e2d2d543c 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -438,21 +438,22 @@ static int mount_bind(const char *dest, CustomMount *m) { r = mkdir_parents_label(where, 0755); if (r < 0) return log_error_errno(r, "Failed to make parents of %s: %m", where); + + /* Create the mount point. Any non-directory file can be + * mounted on any non-directory file (regular, fifo, socket, + * char, block). + */ + if (S_ISDIR(source_st.st_mode)) + r = mkdir_label(where, 0755); + else + r = touch(where); + if (r < 0) + return log_error_errno(r, "Failed to create mount point %s: %m", where); + } else { return log_error_errno(errno, "Failed to stat %s: %m", where); } - /* Create the mount point. Any non-directory file can be - * mounted on any non-directory file (regular, fifo, socket, - * char, block). - */ - if (S_ISDIR(source_st.st_mode)) - r = mkdir_label(where, 0755); - else - r = touch(where); - if (r < 0 && r != -EEXIST) - return log_error_errno(r, "Failed to create mount point %s: %m", where); - if (mount(m->source, where, NULL, mount_flags, mount_opts) < 0) return log_error_errno(errno, "mount(%s) failed: %m", where); @@ -750,7 +751,7 @@ static int mount_unified_cgroups(const char *dest) { return -EINVAL; } - if (mount("cgroup", p, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "__DEVEL__sane_behavior") < 0) + if (mount("cgroup", p, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) < 0) return log_error_errno(errno, "Failed to mount unified cgroup hierarchy to %s: %m", p); return 0; diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index fcb1efaa74..74a0ae865b 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -232,7 +232,7 @@ int setup_veth_extra( if (r < 0) return r; - idx ++; + idx++; } return 0; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 5a68fec603..eb89916b7e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -87,6 +87,7 @@ #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "selinux-util.h" #include "signal-util.h" #include "socket-util.h" #include "stat-util.h" @@ -561,7 +562,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_CAPABILITY: case ARG_DROP_CAPABILITY: { p = optarg; - for(;;) { + for (;;) { _cleanup_free_ char *t = NULL; r = extract_first_word(&p, &t, ",", 0); @@ -976,6 +977,13 @@ static int verify_arguments(void) { return -EINVAL; } +#ifndef HAVE_LIBIPTC + if (arg_expose_ports) { + log_error("--port= is not supported, compiled without libiptc support."); + return -EOPNOTSUPP; + } +#endif + if (arg_start_mode == START_BOOT && arg_kill_signal <= 0) arg_kill_signal = SIGRTMIN+3; @@ -2560,7 +2568,7 @@ static int inner_child( envp[n_env] = strv_find_prefix(environ, "TERM="); if (envp[n_env]) - n_env ++; + n_env++; if ((asprintf((char**)(envp + n_env++), "HOME=%s", home ? home: "/root") < 0) || (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ? arg_user : "root") < 0) || @@ -3284,6 +3292,12 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_selinux_apifs_context) { + r = mac_selinux_apply(console, arg_selinux_apifs_context); + if (r < 0) + goto finish; + } + if (unlockpt(master) < 0) { r = log_error_errno(errno, "Failed to unlock tty: %m"); goto finish; @@ -3618,7 +3632,7 @@ int main(int argc, char *argv[]) { /* We failed to wait for the container, or the * container exited abnormally */ goto finish; - else if (r > 0 || container_status == CONTAINER_TERMINATED){ + else if (r > 0 || container_status == CONTAINER_TERMINATED) { /* The container exited with a non-zero * status, or with zero status and no reboot * was requested. */ diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 1582d702f8..8d57b26cbc 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -66,7 +66,7 @@ static int count_addresses(sd_bus_message *m, int af, unsigned *ret) { if (af != AF_UNSPEC && family != af) continue; - c ++; + c++; } if (r < 0) return r; diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index 69c0d9bdc1..0de6bd2241 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -90,7 +90,7 @@ static int count_addresses(sd_bus_message *m, int af, const char **canonical) { if (af != AF_UNSPEC && family != af) continue; - c ++; + c++; } if (r < 0) return r; diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index db9666b970..7b79d29d7e 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "macro.h" /* DNS record types, taken from diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index a519074278..14ee01c49d 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -17,7 +17,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <gcrypt.h> #include <getopt.h> #include <net/if.h> @@ -44,12 +43,19 @@ static uint16_t arg_class = 0; static bool arg_legend = true; static uint64_t arg_flags = 0; +typedef enum ServiceFamily { + SERVICE_FAMILY_TCP, + SERVICE_FAMILY_UDP, + SERVICE_FAMILY_SCTP, + _SERVICE_FAMILY_INVALID = -1, +} ServiceFamily; +static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP; + typedef enum RawType { RAW_NONE, RAW_PAYLOAD, RAW_PACKET, } RawType; - static RawType arg_raw = RAW_NONE; static enum { @@ -57,10 +63,34 @@ static enum { MODE_RESOLVE_RECORD, MODE_RESOLVE_SERVICE, MODE_RESOLVE_OPENPGP, + MODE_RESOLVE_TLSA, MODE_STATISTICS, MODE_RESET_STATISTICS, } arg_mode = MODE_RESOLVE_HOST; +static ServiceFamily service_family_from_string(const char *s) { + if (s == NULL || streq(s, "tcp")) + return SERVICE_FAMILY_TCP; + if (streq(s, "udp")) + return SERVICE_FAMILY_UDP; + if (streq(s, "sctp")) + return SERVICE_FAMILY_SCTP; + return _SERVICE_FAMILY_INVALID; +} + +static const char* service_family_to_string(ServiceFamily service) { + switch(service) { + case SERVICE_FAMILY_TCP: + return "_tcp"; + case SERVICE_FAMILY_UDP: + return "_udp"; + case SERVICE_FAMILY_SCTP: + return "_sctp"; + default: + assert_not_reached("invalid service"); + } +} + static void print_source(uint64_t flags, usec_t rtt) { char rtt_str[FORMAT_TIMESTAMP_MAX]; @@ -832,7 +862,7 @@ static int resolve_openpgp(sd_bus *bus, const char *address) { } domain++; - r = string_hashsum(address, domain - 1 - address, GCRY_MD_SHA224, &hashed); + r = string_hashsum_sha224(address, domain - 1 - address, &hashed); if (r < 0) return log_error_errno(r, "Hashing failed: %m"); @@ -844,6 +874,38 @@ static int resolve_openpgp(sd_bus *bus, const char *address) { arg_type ?: DNS_TYPE_OPENPGPKEY); } +static int resolve_tlsa(sd_bus *bus, const char *address) { + const char *port; + uint16_t port_num = 443; + _cleanup_free_ char *full = NULL; + int r; + + assert(bus); + assert(address); + + port = strrchr(address, ':'); + if (port) { + r = safe_atou16(port + 1, &port_num); + if (r < 0 || port_num == 0) + return log_error_errno(r, "Invalid port \"%s\".", port + 1); + + address = strndupa(address, port - address); + } + + r = asprintf(&full, "_%u.%s.%s", + port_num, + service_family_to_string(arg_service_family), + address); + if (r < 0) + return log_oom(); + + log_debug("Looking up \"%s\".", full); + + return resolve_record(bus, full, + arg_class ?: DNS_CLASS_IN, + arg_type ?: DNS_TYPE_TLSA); +} + static int show_statistics(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -1031,6 +1093,7 @@ static void help(void) { " --service-address=BOOL Resolve address for services (default: yes)\n" " --service-txt=BOOL Resolve TXT records for services (default: yes)\n" " --openpgp Query OpenPGP public key\n" + " --tlsa Query TLS public key\n" " --cname=BOOL Follow CNAME redirects (default: yes)\n" " --search=BOOL Use search domains for single-label names\n" " (default: yes)\n" @@ -1050,6 +1113,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SERVICE_ADDRESS, ARG_SERVICE_TXT, ARG_OPENPGP, + ARG_TLSA, ARG_RAW, ARG_SEARCH, ARG_STATISTICS, @@ -1069,6 +1133,7 @@ static int parse_argv(int argc, char *argv[]) { { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, { "openpgp", no_argument, NULL, ARG_OPENPGP }, + { "tlsa", optional_argument, NULL, ARG_TLSA }, { "raw", optional_argument, NULL, ARG_RAW }, { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, @@ -1183,6 +1248,15 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_RESOLVE_OPENPGP; break; + case ARG_TLSA: + arg_mode = MODE_RESOLVE_TLSA; + arg_service_family = service_family_from_string(optarg); + if (arg_service_family < 0) { + log_error("Unknown service family \"%s\".", optarg); + return -EINVAL; + } + break; + case ARG_RAW: if (on_tty()) { log_error("Refusing to write binary data to tty."); @@ -1205,40 +1279,28 @@ static int parse_argv(int argc, char *argv[]) { r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --cname= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_CNAME; - else - arg_flags &= ~SD_RESOLVED_NO_CNAME; + SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0); break; case ARG_SERVICE_ADDRESS: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --service-address= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_ADDRESS; - else - arg_flags &= ~SD_RESOLVED_NO_ADDRESS; + SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0); break; case ARG_SERVICE_TXT: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --service-txt= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_TXT; - else - arg_flags &= ~SD_RESOLVED_NO_TXT; + SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0); break; case ARG_SEARCH: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --search argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_SEARCH; - else - arg_flags &= ~SD_RESOLVED_NO_SEARCH; + SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0); break; case ARG_STATISTICS: @@ -1261,7 +1323,7 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } - if (arg_type != 0 && arg_mode != MODE_RESOLVE_RECORD) { + if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) { log_error("--service and --type= may not be combined."); return -EINVAL; } @@ -1378,6 +1440,24 @@ int main(int argc, char **argv) { } break; + case MODE_RESOLVE_TLSA: + if (argc < optind + 1) { + log_error("Domain name required."); + r = -EINVAL; + goto finish; + + } + + r = 0; + while (optind < argc) { + int k; + + k = resolve_tlsa(bus, argv[optind++]); + if (k < 0) + r = k; + } + break; + case MODE_STATISTICS: if (argc > optind) { log_error("Too many arguments."); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index a138be2421..16cae8c1e5 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -188,7 +188,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { if (!canonical) canonical = dns_resource_record_ref(rr); - added ++; + added++; } if (added <= 0) { @@ -418,7 +418,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { if (r < 0) goto finish; - added ++; + added++; } if (added <= 0) { @@ -587,7 +587,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { if (r < 0) goto finish; - added ++; + added++; } if (added <= 0) { @@ -1094,9 +1094,9 @@ static void bus_method_resolve_service_complete(DnsQuery *q) { } if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { - q->block_all_complete ++; + q->block_all_complete++; r = resolve_service_hostname(q, rr, ifindex); - q->block_all_complete --; + q->block_all_complete--; if (r < 0) goto finish; @@ -1137,7 +1137,6 @@ finish: static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL; const char *name, *type, *domain; - _cleanup_free_ char *n = NULL; Manager *m = userdata; int family, ifindex; uint64_t flags; diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index bb93fbfda2..990dc03b60 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -59,7 +59,7 @@ int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, con assert(m); assert(string); - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL; r = extract_first_word(&string, &word, NULL, 0); @@ -114,7 +114,7 @@ int manager_parse_search_domains_and_warn(Manager *m, const char *string) { assert(m); assert(string); - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL; r = extract_first_word(&string, &word, NULL, EXTRACT_QUOTES); diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index c08f7a7edd..0dadf8b1dd 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -538,7 +538,7 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) { dns_resource_record_unref((*a)->items[i].rr); memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1)); - (*a)->n_rrs --; + (*a)->n_rrs--; continue; } else @@ -624,7 +624,7 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) { dns_resource_record_unref((*a)->items[i].rr); memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1)); - (*a)->n_rrs --; + (*a)->n_rrs--; continue; } else @@ -757,7 +757,7 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, unsigned n_free) { assert(a); /* Tries to extend the DnsAnswer object. And if that's not - * possibly, since we are not the sole owner, then allocate a + * possible, since we are not the sole owner, then allocate a * new, appropriately sized one. Either way, after this call * the object will only have a single reference, and has room * for at least the specified number of RRs. */ diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 4b7672fbbf..77c42d7aad 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -402,7 +402,7 @@ static int dns_cache_put_positive( k = dns_cache_remove_by_rr(c, rr); log_debug("%s: %s", k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry", - dns_resource_key_to_string(i->key, key_str, sizeof key_str)); + dns_resource_key_to_string(rr->key, key_str, sizeof key_str)); return 0; } @@ -497,7 +497,7 @@ static int dns_cache_put_negative( if (nsec_ttl <= 0 || soa->soa.minimum <= 0 || soa->ttl <= 0) { log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s", - dns_resource_key_to_string(i->key, key_str, sizeof key_str)); + dns_resource_key_to_string(key, key_str, sizeof key_str)); return 0; } @@ -640,7 +640,7 @@ int dns_cache_put( cache_keys = dns_answer_size(answer); if (key) - cache_keys ++; + cache_keys++; /* Make some space for our new entries */ dns_cache_make_space(c, cache_keys); @@ -987,7 +987,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { if (r < 0) return r; - ancount ++; + ancount++; } } diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 2e41dae656..b7907bb511 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -38,8 +38,8 @@ static void rewind_dns_packet(DnsPacketRewinder *rewinder) { dns_packet_rewind(rewinder->packet, rewinder->saved_rindex); } -#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while(0) -#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while(0) +#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while (0) +#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while (0) int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; @@ -1469,7 +1469,7 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta return r; } - bit ++; + bit++; bitmask >>= 1; } } diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index a7496aa586..706f8c14ed 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -62,6 +62,7 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) { while ((t = set_steal_first(c->transactions))) { set_remove(t->notify_query_candidates, c); + set_remove(t->notify_query_candidates_done, c); dns_transaction_gc(t); } } @@ -139,6 +140,10 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource if (r < 0) goto gc; + r = set_ensure_allocated(&t->notify_query_candidates_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->notify_query_candidates, c); if (r < 0) goto gc; @@ -927,7 +932,7 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) assert(q); - q->n_cname_redirects ++; + q->n_cname_redirects++; if (q->n_cname_redirects > CNAME_MAX) return -ELOOP; diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index d0a86ef206..6a29a93a26 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1116,40 +1116,30 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { case DNS_TYPE_TLSA: { const char *cert_usage, *selector, *matching_type; - char *ss; - int n; cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage); selector = tlsa_selector_to_string(rr->tlsa.selector); matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type); - r = asprintf(&s, "%s %u %u %u %n", - k, - rr->tlsa.cert_usage, - rr->tlsa.selector, - rr->tlsa.matching_type, - &n); - if (r < 0) - return NULL; - - r = base64_append(&s, n, - rr->tlsa.data, rr->tlsa.data_size, - 8, columns()); - if (r < 0) + t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); + if (!t) return NULL; - r = asprintf(&ss, "%s\n" + r = asprintf(&s, + "%s %u %u %u %s\n" " -- Cert. usage: %s\n" " -- Selector: %s\n" " -- Matching type: %s", - s, + k, + rr->tlsa.cert_usage, + rr->tlsa.selector, + rr->tlsa.matching_type, + t, cert_usage, selector, matching_type); if (r < 0) return NULL; - free(s); - s = ss; break; } @@ -1228,13 +1218,16 @@ ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) { case DNS_TYPE_MX: case DNS_TYPE_LOC: case DNS_TYPE_DS: - case DNS_TYPE_SSHFP: case DNS_TYPE_DNSKEY: case DNS_TYPE_RRSIG: case DNS_TYPE_NSEC: case DNS_TYPE_NSEC3: return -EINVAL; + case DNS_TYPE_SSHFP: + *out = rr->sshfp.fingerprint; + return rr->sshfp.fingerprint_size; + case DNS_TYPE_TLSA: *out = rr->tlsa.data; return rr->tlsa.data_size; diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 646e34598d..020a2abd77 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -82,7 +82,7 @@ enum { struct DnsResourceKey { unsigned n_ref; /* (unsigned -1) for const keys, see below */ uint16_t class, type; - char *_name; /* don't access directy, use dns_resource_key_name()! */ + char *_name; /* don't access directly, use dns_resource_key_name()! */ }; /* Creates a temporary resource key. This is only useful to quickly diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 27342a0e04..49d488cec5 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -120,7 +120,7 @@ DnsServer* dns_server_ref(DnsServer *s) { return NULL; assert(s->n_ref > 0); - s->n_ref ++; + s->n_ref++; return s; } @@ -130,7 +130,7 @@ DnsServer* dns_server_unref(DnsServer *s) { return NULL; assert(s->n_ref > 0); - s->n_ref --; + s->n_ref--; if (s->n_ref > 0) return NULL; @@ -290,9 +290,9 @@ void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel le if (s->possible_feature_level == level) { if (protocol == IPPROTO_UDP) - s->n_failed_udp ++; + s->n_failed_udp++; else if (protocol == IPPROTO_TCP) - s->n_failed_tcp ++; + s->n_failed_tcp++; } if (s->resend_timeout > usec) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 3443f71976..a5129c201e 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -52,6 +52,7 @@ static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) { while ((z = set_steal_first(t->dnssec_transactions))) { set_remove(z->notify_transactions, t); + set_remove(z->notify_transactions_done, t); dns_transaction_gc(z); } } @@ -100,14 +101,26 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { set_remove(c->transactions, t); set_free(t->notify_query_candidates); + while ((c = set_steal_first(t->notify_query_candidates_done))) + set_remove(c->transactions, t); + set_free(t->notify_query_candidates_done); + while ((i = set_steal_first(t->notify_zone_items))) i->probe_transaction = NULL; set_free(t->notify_zone_items); + while ((i = set_steal_first(t->notify_zone_items_done))) + i->probe_transaction = NULL; + set_free(t->notify_zone_items_done); + while ((z = set_steal_first(t->notify_transactions))) set_remove(z->dnssec_transactions, t); set_free(t->notify_transactions); + while ((z = set_steal_first(t->notify_transactions_done))) + set_remove(z->dnssec_transactions, t); + set_free(t->notify_transactions_done); + dns_transaction_flush_dnssec_transactions(t); set_free(t->dnssec_transactions); @@ -127,8 +140,11 @@ bool dns_transaction_gc(DnsTransaction *t) { return true; if (set_isempty(t->notify_query_candidates) && + set_isempty(t->notify_query_candidates_done) && set_isempty(t->notify_zone_items) && - set_isempty(t->notify_transactions)) { + set_isempty(t->notify_zone_items_done) && + set_isempty(t->notify_transactions) && + set_isempty(t->notify_transactions_done)) { dns_transaction_free(t); return false; } @@ -209,7 +225,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) LIST_PREPEND(transactions_by_scope, s->transactions, t); t->scope = s; - s->manager->n_transactions_total ++; + s->manager->n_transactions_total++; if (ret) *ret = t; @@ -266,6 +282,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { log_debug("We have the lexicographically larger IP address and thus lost in the conflict."); t->block_gc++; + while ((z = set_first(t->notify_zone_items))) { /* First, make sure the zone item drops the reference * to us */ @@ -284,7 +301,6 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { DnsQueryCandidate *c; DnsZoneItem *z; DnsTransaction *d; - Iterator i; const char *st; char key_str[DNS_RESOURCE_KEY_STRING_MAX]; @@ -333,39 +349,17 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { * transaction isn't freed while we are still looking at it */ t->block_gc++; - SET_FOREACH(c, t->notify_query_candidates, i) + SET_FOREACH_MOVE(c, t->notify_query_candidates_done, t->notify_query_candidates) dns_query_candidate_notify(c); - SET_FOREACH(z, t->notify_zone_items, i) - dns_zone_item_notify(z); + SWAP_TWO(t->notify_query_candidates, t->notify_query_candidates_done); - if (!set_isempty(t->notify_transactions)) { - DnsTransaction **nt; - unsigned j, n = 0; - - /* We need to be careful when notifying other - * transactions, as that might destroy other - * transactions in our list. Hence, in order to be - * able to safely iterate through the list of - * transactions, take a GC lock on all of them - * first. Then, in a second loop, notify them, but - * first unlock that specific transaction. */ - - nt = newa(DnsTransaction*, set_size(t->notify_transactions)); - SET_FOREACH(d, t->notify_transactions, i) { - nt[n++] = d; - d->block_gc++; - } - - assert(n == set_size(t->notify_transactions)); + SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items) + dns_zone_item_notify(z); + SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done); - for (j = 0; j < n; j++) { - if (set_contains(t->notify_transactions, nt[j])) - dns_transaction_notify(nt[j], t); - - nt[j]->block_gc--; - dns_transaction_gc(nt[j]); - } - } + SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions) + dns_transaction_notify(d, t); + SWAP_TWO(t->notify_transactions, t->notify_transactions_done); t->block_gc--; dns_transaction_gc(t); @@ -1375,7 +1369,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { other->state = DNS_TRANSACTION_PENDING; other->next_attempt_after = ts; - qdcount ++; + qdcount++; if (dns_key_is_shared(other->key)) add_known_answers = true; @@ -1626,6 +1620,10 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource if (r < 0) goto gc; + r = set_ensure_allocated(&aux->notify_transactions_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->dnssec_transactions, aux); if (r < 0) goto gc; diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 491c62d772..eaece91533 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -118,17 +118,17 @@ struct DnsTransaction { /* Query candidates this transaction is referenced by and that * shall be notified about this specific transaction * completing. */ - Set *notify_query_candidates; + Set *notify_query_candidates, *notify_query_candidates_done; /* Zone items this transaction is referenced by and that shall * be notified about completion. */ - Set *notify_zone_items; + Set *notify_zone_items, *notify_zone_items_done; /* Other transactions that this transactions is referenced by * and that shall be notified about completion. This is used * when transactions want to validate their RRsets, but need * another DNSKEY or DS RR to do so. */ - Set *notify_transactions; + Set *notify_transactions, *notify_transactions_done; /* The opposite direction: the transactions this transaction * created in order to request DNSKEY or DS RRs. */ diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 03813da6a2..850eed8cb8 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -38,6 +38,7 @@ void dns_zone_item_probe_stop(DnsZoneItem *i) { i->probe_transaction = NULL; set_remove(t->notify_zone_items, i); + set_remove(t->notify_zone_items_done, i); dns_transaction_gc(t); } @@ -186,6 +187,10 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { if (r < 0) goto gc; + r = set_ensure_allocated(&t->notify_zone_items_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->notify_zone_items, i); if (r < 0) goto gc; diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c index 6ccbdca20e..40d650949d 100644 --- a/src/resolve/resolved-etc-hosts.c +++ b/src/resolve/resolved-etc-hosts.c @@ -301,7 +301,7 @@ int manager_etc_hosts_read(Manager *m) { FOREACH_LINE(line, f, return log_error_errno(errno, "Failed to read /etc/hosts: %m")) { char *l; - nr ++; + nr++; l = strstrip(line); if (isempty(l)) diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index ef12abfbb5..8b1d71a3eb 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -286,7 +286,7 @@ static int on_llmnr_stream_packet(DnsStream *s) { scope = manager_find_scope(s->manager, s->read_packet); if (!scope) { - log_warning("Got LLMNR TCP packet on unknown scope. Ignroing."); + log_warning("Got LLMNR TCP packet on unknown scope. Ignoring."); return 0; } diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index 065427b690..ff03acc772 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -158,7 +158,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { if (*count == MAXNS) fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f); - (*count) ++; + (*count)++; fprintf(f, "nameserver %s\n", s->server_string); } @@ -184,7 +184,7 @@ static void write_resolv_conf_search( } (*length) += strlen(domain); - (*count) ++; + (*count)++; fputc(' ', f); fputs(domain, f); diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index c7e2ab14d6..161ea03412 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index 1abbd3fa2e..c232a69ce1 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -89,7 +89,6 @@ static void test_packet_from_file(const char* filename, bool canonical) { int main(int argc, char **argv) { int i, N; _cleanup_globfree_ glob_t g = {}; - _cleanup_strv_free_ char **globs = NULL; char **fnames; log_parse_environment(); diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index a093d86a91..c9b5ffa62b 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -327,10 +327,12 @@ static void test_dnssec_nsec3_hash(void) { int main(int argc, char*argv[]) { test_dnssec_canonicalize(); +#ifdef HAVE_GCRYPT test_dnssec_verify_dns_key(); test_dnssec_verify_rrset(); test_dnssec_verify_rrset2(); test_dnssec_nsec3_hash(); +#endif return 0; } diff --git a/src/run/run.c b/src/run/run.c index e7f4c21f73..f92a7f4e2e 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -83,8 +83,8 @@ static void polkit_agent_open_if_enabled(void) { static void help(void) { printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n" "Run the specified command in a transient scope or service or timer\n" - "unit. If timer option is specified and unit is exist which is\n" - "specified with --unit option then command can be omitted.\n\n" + "unit. If a timer option is specified and the unit specified with\n" + "the --unit option exists, the command can be omitted.\n\n" " -h --help Show this help\n" " --version Show package version\n" " --no-ask-password Do not prompt for password\n" @@ -878,7 +878,7 @@ static int start_transient_service( (void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); if (!arg_quiet) - log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service); + log_info("Running as unit: %s\nPress ^] three times within 1s to disconnect TTY.", service); r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward); if (r < 0) @@ -896,7 +896,7 @@ static int start_transient_service( fputc('\n', stdout); } else if (!arg_quiet) - log_info("Running as unit %s.", service); + log_info("Running as unit: %s", service); return 0; } @@ -1038,7 +1038,7 @@ static int start_transient_scope( return r; if (!arg_quiet) - log_info("Running scope as unit %s.", scope); + log_info("Running scope as unit: %s", scope); execvpe(argv[0], argv, env); @@ -1189,9 +1189,9 @@ static int start_transient_timer( if (r < 0) return r; - log_info("Running timer as unit %s.", timer); + log_info("Running timer as unit: %s", timer); if (argv[0]) - log_info("Will run service as unit %s.", service); + log_info("Will run service as unit: %s", service); return 0; } diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 3cb9e781fd..6779691c28 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -119,7 +119,7 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) { } if (ptr == 0) - return -EINVAL; + return -ENODATA; /* read Firmware Basic Boot Performance Data Record */ fd = open("/dev/mem", O_CLOEXEC|O_RDONLY); @@ -146,6 +146,10 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) { if (brec.type != ACPI_FPDT_BOOT_REC) return -EINVAL; + if (brec.exit_services_exit == 0) + /* Non-UEFI compatible boot. */ + return -ENODATA; + if (brec.startup_start == 0 || brec.exit_services_exit < brec.startup_start) return -EINVAL; if (brec.exit_services_exit > NSEC_PER_HOUR) diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index c87eaf63d8..d9dd3c6a11 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -843,7 +843,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (r < 0) return r; - while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) { + while ((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) { _cleanup_free_ char *escaped = NULL; if (first) @@ -1068,7 +1068,7 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_ } case SD_BUS_TYPE_UINT32: { - uint64_t u; + uint32_t u; uint32_t *p = userdata; r = sd_bus_message_read_basic(m, type, &u); @@ -1412,7 +1412,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return bus_log_create_error(r); field = strndupa(assignment, eq - assignment); - eq ++; + eq++; if (streq(field, "CPUQuota")) { @@ -2030,7 +2030,7 @@ static const struct { static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) { _cleanup_free_ char *service_shell_quoted = NULL; - const char *systemctl = "systemctl", *journalctl = "journalct"; + const char *systemctl = "systemctl", *journalctl = "journalctl"; assert(service); diff --git a/src/shared/condition.c b/src/shared/condition.c index f93785865e..3a45ed265c 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -295,7 +295,7 @@ static int condition_test_needs_update(Condition *c) { return false; /* Any other failure means we should allow the condition to be true, - * so that we rather invoke too many update tools then too + * so that we rather invoke too many update tools than too * few. */ if (!path_is_absolute(c->parameter)) diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index e7fe9ac21e..bd0a1f483b 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -294,7 +294,7 @@ int config_parse(const char *unit, _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; - bool section_ignored = false; + bool section_ignored = false, allow_bom = true; int r; assert(filename); @@ -314,11 +314,11 @@ int config_parse(const char *unit, fd_warn_permissions(filename, fileno(f)); - while (!feof(f)) { - char l[LINE_MAX], *p, *c = NULL, *e; + for (;;) { + char buf[LINE_MAX], *l, *p, *c = NULL, *e; bool escaped = false; - if (!fgets(l, sizeof(l), f)) { + if (!fgets(buf, sizeof buf, f)) { if (feof(f)) break; @@ -326,6 +326,11 @@ int config_parse(const char *unit, return -errno; } + l = buf; + if (allow_bom && startswith(l, UTF8_BYTE_ORDER_MARK)) + l += strlen(UTF8_BYTE_ORDER_MARK); + allow_bom = false; + truncate_nl(l); if (continuation) { diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index a91c94c322..73fb132413 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -178,7 +178,7 @@ int config_parse_personality(const char *unit, const char *filename, unsigned li assert(data); \ \ xs = new0(type, 1); \ - if(!xs) \ + if (!xs) \ return -ENOMEM; \ \ *xs = invalid; \ diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 0fc2a31f04..835557c6b2 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -180,7 +180,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha unsigned slashes = 0; for (y = terminal - 1; y >= name && *y == '\\'; y--) - slashes ++; + slashes++; if (slashes % 2 == 0) { /* The '.' was not escaped */ @@ -192,7 +192,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha } } - terminal --; + terminal--; } r = dns_label_unescape(&name, dest, sz); @@ -1172,7 +1172,7 @@ int dns_name_skip(const char *a, unsigned n_labels, const char **ret) { assert(a); assert(ret); - for (; n_labels > 0; n_labels --) { + for (; n_labels > 0; n_labels--) { r = dns_name_parent(&a); if (r < 0) return r; diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 2de3642cb3..af780f0b8b 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - - #include <errno.h> #include <stdbool.h> #include <stddef.h> diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c index b887243849..39b544b6f0 100644 --- a/src/shared/gcrypt-util.c +++ b/src/shared/gcrypt-util.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#ifdef HAVE_GCRYPT #include <gcrypt.h> -#include "hexdecoct.h" #include "gcrypt-util.h" +#include "hexdecoct.h" void initialize_libgcrypt(bool secmem) { const char *p; @@ -32,7 +33,7 @@ void initialize_libgcrypt(bool secmem) { p = gcry_check_version("1.4.5"); assert(p); - /* Turn off "secmem". Clients which whish to make use of this + /* Turn off "secmem". Clients which wish to make use of this * feature should initialize the library manually */ if (!secmem) gcry_control(GCRYCTL_DISABLE_SECMEM); @@ -67,3 +68,4 @@ int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) { *out = enc; return 0; } +#endif diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h index c7652c22d1..cf33b3c59c 100644 --- a/src/shared/gcrypt-util.h +++ b/src/shared/gcrypt-util.h @@ -19,7 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> #include <stdbool.h> +#include <stddef.h> + +#ifdef HAVE_GCRYPT +#include <gcrypt.h> void initialize_libgcrypt(bool secmem); int string_hashsum(const char *s, size_t len, int md_algorithm, char **out); +#endif + +static inline int string_hashsum_sha224(const char *s, size_t len, char **out) { +#ifdef HAVE_GCRYPT + return string_hashsum(s, len, GCRY_MD_SHA224, out); +#else + return -EOPNOTSUPP; +#endif +} diff --git a/src/shared/gpt.h b/src/shared/gpt.h index 52ab29ed5f..55b41bbcd8 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <endian.h> #include "sd-id128.h" diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h index acf519f4f7..8a570fc265 100644 --- a/src/shared/install-printf.h +++ b/src/shared/install-printf.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "install.h" int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret); diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 5eb3bd35c7..e2d2931c51 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -997,7 +997,7 @@ static int show_journal(FILE *f, continue; } - line ++; + line++; maybe_print_begin_newline(f, &flags); r = output_journal(f, j, mode, n_columns, flags, ellipsized); diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index ed8a29c575..d2f1c4a40c 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -23,6 +23,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/file.h> #include <sys/stat.h> #include <unistd.h> #include <linux/fs.h> diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index e5674e4137..23890c63a0 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -24,6 +24,7 @@ #include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <sys/file.h> #include <sys/ioctl.h> #include <sys/mount.h> #include <sys/prctl.h> @@ -138,7 +139,7 @@ static int setup_machine_raw(uint64_t size, sd_bus_error *error) { execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL); if (errno == ENOENT) - return 99; + _exit(99); _exit(EXIT_FAILURE); } @@ -238,10 +239,8 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) { } r = mkfs_exists("btrfs"); - if (r == -ENOENT) { - log_debug("mkfs.btrfs is missing, cannot create loopback file for /var/lib/machines."); - return 0; - } + if (r == 0) + return sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing"); if (r < 0) return r; diff --git a/src/shared/pager.c b/src/shared/pager.c index 05b2b15e40..c16bc027be 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -52,11 +52,14 @@ noreturn static void pager_fallback(void) { _exit(EXIT_SUCCESS); } -int pager_open(bool jump_to_end) { +int pager_open(bool no_pager, bool jump_to_end) { _cleanup_close_pair_ int fd[2] = { -1, -1 }; const char *pager; pid_t parent_pid; + if (no_pager) + return 0; + if (pager_pid > 0) return 1; diff --git a/src/shared/pager.h b/src/shared/pager.h index 9fb05796bb..893e1d2bb6 100644 --- a/src/shared/pager.h +++ b/src/shared/pager.h @@ -23,7 +23,7 @@ #include "macro.h" -int pager_open(bool jump_to_end); +int pager_open(bool no_pager, bool jump_to_end); void pager_close(void); bool pager_have(void) _pure_; diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 061d31f4de..02c03b98d8 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -461,10 +461,7 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) { if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b) return 0; - if (b) - f->flags |= PTY_FORWARD_IGNORE_VHANGUP; - else - f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP; + SET_FLAG(f->flags, PTY_FORWARD_IGNORE_VHANGUP, b); if (!ignore_vhangup(f)) { diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index a0aef66bc8..35aa60101f 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -37,7 +37,7 @@ #include "string-util.h" #include "strv.h" -#define USE(x, y) do{ (x) = (y); (y) = NULL; } while(0) +#define USE(x, y) do { (x) = (y); (y) = NULL; } while (0) int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h index 51f4621844..ad10039ff4 100644 --- a/src/shared/sleep-config.h +++ b/src/shared/sleep-config.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - int parse_sleep_config(const char *verb, char ***modes, char ***states); int can_sleep(const char *verb); diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c index eb251492c3..b6ec474390 100644 --- a/src/shared/uid-range.c +++ b/src/shared/uid-range.c @@ -54,7 +54,7 @@ static void uid_range_coalesce(UidRange **p, unsigned *n) { if (*n > j+1) memmove(y, y+1, sizeof(UidRange) * (*n - j -1)); - (*n) --; + (*n)--; j--; } } diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index 99d4b62139..1157a0c72e 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -427,7 +427,7 @@ static int resolve_remote(Connection *c) { service = strrchr(arg_remote_host, ':'); if (service) { node = strndupa(arg_remote_host, service - arg_remote_host); - service ++; + service++; } else { node = arg_remote_host; service = "80"; diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c index 91eace90e2..ce8efce3d5 100644 --- a/src/stdio-bridge/stdio-bridge.c +++ b/src/stdio-bridge/stdio-bridge.c @@ -190,7 +190,7 @@ int main(int argc, char *argv[]) { } for (;;) { - _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL; int events_a, events_b, fd; uint64_t timeout_a, timeout_b, t; struct timespec _ts, *ts; @@ -234,12 +234,14 @@ int main(int argc, char *argv[]) { fd = sd_bus_get_fd(a); if (fd < 0) { + r = fd; log_error_errno(r, "Failed to get fd: %m"); goto finish; } events_a = sd_bus_get_events(a); if (events_a < 0) { + r = events_a; log_error_errno(r, "Failed to get events mask: %m"); goto finish; } @@ -252,6 +254,7 @@ int main(int argc, char *argv[]) { events_b = sd_bus_get_events(b); if (events_b < 0) { + r = events_b; log_error_errno(r, "Failed to get events mask: %m"); goto finish; } @@ -294,8 +297,6 @@ int main(int argc, char *argv[]) { } } - r = 0; - finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c75d12c136..3407d93c80 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -152,7 +152,7 @@ static bool arg_now = false; static int daemon_reload(int argc, char *argv[], void* userdata); static int halt_now(enum action a); -static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet); +static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state); static bool original_stdout_is_tty; @@ -200,14 +200,6 @@ static void release_busses(void) { busses[w] = sd_bus_flush_close_unref(busses[w]); } -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void ask_password_agent_open_if_enabled(void) { /* Open the password agent as a child process if necessary */ @@ -348,6 +340,11 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) { if (arg_all) return true; + if (!strv_isempty(arg_states)) + return true; + + /* By default show all units except the ones in inactive + * state and with no pending job */ if (u->job_id > 0) return true; @@ -678,7 +675,7 @@ static int list_units(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -890,7 +887,7 @@ static int list_sockets(int argc, char *argv[], void *userdata) { int r = 0, n; sd_bus *bus; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -1197,7 +1194,7 @@ static int list_timers(int argc, char *argv[], void *userdata) { sd_bus *bus; int r = 0; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -1365,7 +1362,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { char *path; int r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (install_client_side()) { Hashmap *h; @@ -1436,7 +1433,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { }; if (output_show_unit_file(&units[c], strv_skip(argv, 1))) - c ++; + c++; } if (r < 0) @@ -1484,7 +1481,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); } - if (arg_full){ + if (arg_full) { printf("%s\n", name); return 0; } @@ -1638,11 +1635,27 @@ static int list_dependencies_one( if (arg_plain) printf(" "); else { - int state; + UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID; const char *on; - state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true); - on = state > 0 ? ansi_highlight_green() : ansi_highlight_red(); + (void) get_state_one_unit(bus, *c, &active_state); + switch (active_state) { + case UNIT_ACTIVE: + case UNIT_RELOADING: + case UNIT_ACTIVATING: + on = ansi_highlight_green(); + break; + + case UNIT_INACTIVE: + case UNIT_DEACTIVATING: + on = ansi_normal(); + break; + + default: + on = ansi_highlight_red(); + break; + } + printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal()); } @@ -1679,7 +1692,7 @@ static int list_dependencies(int argc, char *argv[], void *userdata) { } else u = SPECIAL_DEFAULT_TARGET; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -1883,13 +1896,13 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n) printf("%s%s%s ", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state); if (m->is_host) - printf("%-*s (host) %s%-*s%s %s%*u%s %*u\n", + printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n", (int) (namelen - (sizeof(" (host)")-1)), strna(m->name), on_state, statelen, strna(m->state), off_state, on_failed, failedlen, m->n_failed_units, off_failed, jobslen, m->n_jobs); else - printf("%-*s %s%-*s%s %s%*u%s %*u\n", + printf("%-*s %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n", namelen, strna(m->name), on_state, statelen, strna(m->state), off_state, on_failed, failedlen, m->n_failed_units, off_failed, @@ -1910,7 +1923,7 @@ static int list_machines(int argc, char *argv[], void *userdata) { return -EPERM; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -2067,7 +2080,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp return; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); id_len = strlen("JOB"); unit_len = strlen("UNIT"); @@ -2137,7 +2150,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) { int r; bool skipped = false; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -2407,18 +2420,19 @@ static int unit_find_paths( return r; } -static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) { +static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *buf = NULL; - const char *path, *state; + UnitActiveState state; + const char *path; int r; assert(name); + assert(active_state); /* We don't use unit_dbus_path_from_name() directly since we don't want to load the unit unnecessarily, if it * isn't loaded. */ - r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -2434,7 +2448,7 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states /* The unit is currently not loaded, hence say it's "inactive", since all units that aren't loaded are * considered inactive. */ - state = "inactive"; + state = UNIT_INACTIVE; } else { r = sd_bus_message_read(reply, "o", &path); @@ -2452,13 +2466,15 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states if (r < 0) return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r)); - state = buf; + state = unit_active_state_from_string(buf); + if (state == _UNIT_ACTIVE_STATE_INVALID) { + log_error("Invalid unit state '%s' for: %s", buf, name); + return -EINVAL; + } } - if (!quiet) - puts(state); - - return nulstr_contains(good_states, state); + *active_state = state; + return 0; } static int check_triggering_units( @@ -2466,9 +2482,10 @@ static int check_triggering_units( const char *name) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_free_ char *path = NULL, *n = NULL, *state = NULL; + _cleanup_free_ char *path = NULL, *n = NULL, *load_state = NULL; _cleanup_strv_free_ char **triggered_by = NULL; bool print_warning_label = true; + UnitActiveState active_state; char **i; int r; @@ -2487,11 +2504,11 @@ static int check_triggering_units( "org.freedesktop.systemd1.Unit", "LoadState", &error, - &state); + &load_state); if (r < 0) return log_error_errno(r, "Failed to get load state of %s: %s", n, bus_error_message(&error, r)); - if (streq(state, "masked")) + if (streq(load_state, "masked")) return 0; r = sd_bus_get_property_strv( @@ -2506,11 +2523,11 @@ static int check_triggering_units( return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r)); STRV_FOREACH(i, triggered_by) { - r = check_one_unit(bus, *i, "active\0reloading\0", true); + r = get_state_one_unit(bus, *i, &active_state); if (r < 0) - return log_error_errno(r, "Failed to check unit: %m"); + return r; - if (r == 0) + if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING)) continue; if (print_warning_label) { @@ -2604,7 +2621,10 @@ static int start_unit_one( if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) && !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED)) - log_error("See system logs and 'systemctl status %s' for details.", name); + log_error("See %s logs and 'systemctl%s status %s' for details.", + arg_scope == UNIT_FILE_SYSTEM ? "system" : "user", + arg_scope == UNIT_FILE_SYSTEM ? "" : " --user", + name); return r; } @@ -3171,11 +3191,12 @@ static int start_special(int argc, char *argv[], void *userdata) { return start_unit(argc, argv, userdata); } -static int check_unit_generic(int code, const char *good_states, char **args) { +static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) { _cleanup_strv_free_ char **names = NULL; + UnitActiveState active_state; sd_bus *bus; char **name; - int r; + int r, i; bool found = false; r = acquire_bus(BUS_MANAGER, &bus); @@ -3187,13 +3208,16 @@ static int check_unit_generic(int code, const char *good_states, char **args) { return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - int state; + r = get_state_one_unit(bus, *name, &active_state); + if (r < 0) + return r; - state = check_one_unit(bus, *name, good_states, arg_quiet); - if (state < 0) - return state; - if (state > 0) - found = true; + if (!arg_quiet) + puts(unit_active_state_to_string(active_state)); + + for (i = 0; i < nb_states; ++i) + if (good_states[i] == active_state) + found = true; } /* use the given return code for the case that we won't find @@ -3202,12 +3226,14 @@ static int check_unit_generic(int code, const char *good_states, char **args) { } static int check_unit_active(int argc, char *argv[], void *userdata) { + const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING }; /* According to LSB: 3, "program is not running" */ - return check_unit_generic(3, "active\0reloading\0", strv_skip(argv, 1)); + return check_unit_generic(3, states, ELEMENTSOF(states), strv_skip(argv, 1)); } static int check_unit_failed(int argc, char *argv[], void *userdata) { - return check_unit_generic(1, "failed\0", strv_skip(argv, 1)); + const UnitActiveState states[] = { UNIT_FAILED }; + return check_unit_generic(1, states, ELEMENTSOF(states), strv_skip(argv, 1)); } static int kill_unit(int argc, char *argv[], void *userdata) { @@ -4559,7 +4585,7 @@ static int show_all( if (r < 0) return r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); c = (unsigned) r; @@ -4611,8 +4637,8 @@ static int show_system_status(sd_bus *bus) { printf(" State: %s%s%s\n", on, strna(mi.state), off); - printf(" Jobs: %u queued\n", mi.n_jobs); - printf(" Failed: %u units\n", mi.n_failed_units); + printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs); + printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units); printf(" Since: %s; %s\n", format_timestamp(since2, sizeof(since2), mi.timestamp), @@ -4654,7 +4680,7 @@ static int show(int argc, char *argv[], void *userdata) { return -EINVAL; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (show_status) /* Increase max number of open files to 16K if we can, we @@ -4672,7 +4698,7 @@ static int show(int argc, char *argv[], void *userdata) { if (show_status && argc <= 1) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); show_system_status(bus); new_line = true; @@ -4813,7 +4839,7 @@ static int cat(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to expand names: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); STRV_FOREACH(name, names) { _cleanup_free_ char *fragment_path = NULL; @@ -5003,7 +5029,7 @@ static int show_environment(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -6170,15 +6196,30 @@ static int edit(int argc, char *argv[], void *userdata) { r = daemon_reload(argc, argv, userdata); end: - STRV_FOREACH_PAIR(original, tmp, paths) + STRV_FOREACH_PAIR(original, tmp, paths) { (void) unlink(*tmp); + /* Removing empty dropin dirs */ + if (!arg_full) { + _cleanup_free_ char *dir; + + dir = dirname_malloc(*original); + if (!dir) + return log_oom(); + + /* no need to check if the dir is empty, rmdir + * does nothing if it is not the case. + */ + (void) rmdir(dir); + } + } + return r; } static void systemctl_help(void) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); printf("%s [OPTIONS...] {COMMAND} ...\n\n" "Query or send control commands to the systemd manager.\n\n" @@ -6550,7 +6591,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } p = optarg; - for(;;) { + for (;;) { _cleanup_free_ char *type = NULL; r = extract_first_word(&p, &type, ",", 0); @@ -6600,7 +6641,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return log_oom(); } else { p = optarg; - for(;;) { + for (;;) { _cleanup_free_ char *prop = NULL; r = extract_first_word(&p, &prop, ",", 0); @@ -6710,11 +6751,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_FORCE: - arg_force ++; + arg_force++; break; case 'f': - arg_force ++; + arg_force++; break; case ARG_NO_RELOAD: @@ -6785,7 +6826,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } p = optarg; - for(;;) { + for (;;) { _cleanup_free_ char *s = NULL; r = extract_first_word(&p, &s, ",", 0); @@ -7180,7 +7221,7 @@ static int telinit_parse_argv(int argc, char *argv[]) { arg_action = table[i].to; - optind ++; + optind++; return 1; } @@ -7271,6 +7312,7 @@ static int parse_argv(int argc, char *argv[]) { return systemctl_parse_argv(argc, argv); } +#ifdef HAVE_SYSV_COMPAT _pure_ static int action_to_runlevel(void) { static const char table[_ACTION_MAX] = { @@ -7288,6 +7330,7 @@ _pure_ static int action_to_runlevel(void) { return table[arg_action]; } +#endif static int talk_initctl(void) { #ifdef HAVE_SYSV_COMPAT diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h index 2d4e1f26e1..3bb886be75 100644 --- a/src/systemd/_sd-common.h +++ b/src/systemd/_sd-common.h @@ -74,7 +74,7 @@ #endif #define _SD_DEFINE_POINTER_CLEANUP_FUNC(type, func) \ - static inline void func##p(type **p) { \ + static __inline__ void func##p(type **p) { \ if (*p) \ func(*p); \ } \ diff --git a/src/systemd/sd-bus-protocol.h b/src/systemd/sd-bus-protocol.h index 47b256d5b9..623cee0c50 100644 --- a/src/systemd/sd-bus-protocol.h +++ b/src/systemd/sd-bus-protocol.h @@ -59,7 +59,7 @@ enum { SD_BUS_TYPE_STRUCT_END = ')', SD_BUS_TYPE_DICT_ENTRY = 'e', /* not actually used in signatures */ SD_BUS_TYPE_DICT_ENTRY_BEGIN = '{', - SD_BUS_TYPE_DICT_ENTRY_END = '}', + SD_BUS_TYPE_DICT_ENTRY_END = '}' }; /* Well-known errors. Note that this is only a sanitized subset of the diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h index 6ad6d51979..e8f84eb545 100644 --- a/src/systemd/sd-bus-vtable.h +++ b/src/systemd/sd-bus-vtable.h @@ -34,7 +34,7 @@ enum { _SD_BUS_VTABLE_METHOD = 'M', _SD_BUS_VTABLE_SIGNAL = 'S', _SD_BUS_VTABLE_PROPERTY = 'P', - _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W', + _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W' }; enum { diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 2a2ef0eb98..295989cd69 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -89,13 +89,13 @@ enum { SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 32, SD_BUS_CREDS_DESCRIPTION = 1ULL << 33, SD_BUS_CREDS_AUGMENT = 1ULL << 63, /* special flag, if on sd-bus will augment creds struct, in a potentially race-full way. */ - _SD_BUS_CREDS_ALL = (1ULL << 34) -1, + _SD_BUS_CREDS_ALL = (1ULL << 34) -1 }; enum { SD_BUS_NAME_REPLACE_EXISTING = 1ULL << 0, SD_BUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1, - SD_BUS_NAME_QUEUE = 1ULL << 2, + SD_BUS_NAME_QUEUE = 1ULL << 2 }; /* Callbacks */ diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 5bfca6ecec..c1d07561d7 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -22,6 +22,7 @@ ***/ #include <inttypes.h> +#include <sys/sysmacros.h> #include <sys/types.h> #include "_sd-common.h" diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 2b865a80e1..374ff8774e 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -84,9 +84,9 @@ enum { typedef struct sd_dhcp_client sd_dhcp_client; -typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event, +typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, +int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb, void *userdata); int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); @@ -98,6 +98,8 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, const uint8_t *data, size_t data_len); +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, + uint16_t duid_type, uint8_t *duid, size_t duid_len); int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, const uint8_t **data, size_t *data_len); int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); @@ -113,7 +115,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); int sd_dhcp_client_new(sd_dhcp_client **ret); -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority); +int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority); int sd_dhcp_client_detach_event(sd_dhcp_client *client); sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 8658197e80..fcef083ce6 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -37,7 +37,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex); sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server); sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server); -int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int priority); +int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int64_t priority); int sd_dhcp_server_detach_event(sd_dhcp_server *client); sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 9608060830..4604cb6382 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -76,17 +76,18 @@ enum { typedef struct sd_dhcp6_client sd_dhcp6_client; -typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event, +typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, void *userdata); int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, - sd_dhcp6_client_cb_t cb, void *userdata); + sd_dhcp6_client_callback_t cb, void *userdata); int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, + uint8_t *duid, size_t duid_len); +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid); int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, @@ -97,8 +98,7 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret); int sd_dhcp6_client_stop(sd_dhcp6_client *client); int sd_dhcp6_client_start(sd_dhcp6_client *client); int sd_dhcp6_client_is_running(sd_dhcp6_client *client); -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, - int priority); +int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority); int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 1ea97e47f8..531ace1c34 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -55,7 +55,7 @@ enum { SD_EVENT_RUNNING, SD_EVENT_EXITING, SD_EVENT_FINISHED, - SD_EVENT_PREPARING, + SD_EVENT_PREPARING }; enum { @@ -69,7 +69,11 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); +#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); +#else +typedef void* sd_event_child_handler_t; +#endif int sd_event_default(sd_event **e); diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index a3bf5897b8..4dff0b9b81 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -100,11 +100,11 @@ int sd_id128_get_boot(sd_id128_t *ret); ((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \ 0 }) -_sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) { +_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) { return memcmp(&a, &b, 16) == 0; } -_sd_pure_ static inline int sd_id128_is_null(sd_id128_t a) { +_sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) { return a.qwords[0] == 0 && a.qwords[1] == 0; } diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index 3a2219c82c..9e3e14a30c 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -37,12 +37,12 @@ enum { }; typedef struct sd_ipv4acd sd_ipv4acd; -typedef void (*sd_ipv4acd_cb_t)(sd_ipv4acd *ll, int event, void *userdata); +typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *ll, int event, void *userdata); int sd_ipv4acd_detach_event(sd_ipv4acd *ll); -int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority); +int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority); int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address); -int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata); +int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata); int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index); int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address); diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 67c566fe0d..6fa38a2243 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -36,12 +36,12 @@ enum { }; typedef struct sd_ipv4ll sd_ipv4ll; -typedef void (*sd_ipv4ll_cb_t)(sd_ipv4ll *ll, int event, void *userdata); +typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata); int sd_ipv4ll_detach_event(sd_ipv4ll *ll); -int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority); +int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority); int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata); +int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index); int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index abb9eca576..d4c6f409cd 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -72,7 +72,7 @@ enum { SD_JOURNAL_SYSTEM = 4, SD_JOURNAL_CURRENT_USER = 8, - SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM, /* deprecated name */ + SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM /* deprecated name */ }; /* Wakeup event types */ diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index ea952ef187..4f2a3b50c0 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -30,57 +30,150 @@ _SD_BEGIN_DECLARATIONS; +typedef struct sd_lldp sd_lldp; +typedef struct sd_lldp_neighbor sd_lldp_neighbor; + +#define SD_LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } + +/* IEEE 802.3AB Clause 9: TLV Types */ enum { - SD_LLDP_EVENT_UPDATE_INFO = 0, + SD_LLDP_TYPE_END = 0, + SD_LLDP_TYPE_CHASSIS_ID = 1, + SD_LLDP_TYPE_PORT_ID = 2, + SD_LLDP_TYPE_TTL = 3, + SD_LLDP_TYPE_PORT_DESCRIPTION = 4, + SD_LLDP_TYPE_SYSTEM_NAME = 5, + SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6, + SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7, + SD_LLDP_TYPE_MGMT_ADDRESS = 8, + SD_LLDP_TYPE_PRIVATE = 127, }; +/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ enum { - SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE, - SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE, - SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE, + SD_LLDP_CHASSIS_SUBTYPE_RESERVED = 0, + SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, + SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2, + SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3, + SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4, + SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, + SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, + SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, }; -typedef struct sd_lldp sd_lldp; -typedef struct sd_lldp_packet sd_lldp_packet; +/* IEEE 802.3AB Clause 9.5.3: Port subtype */ +enum { + SD_LLDP_PORT_SUBTYPE_RESERVED = 0, + SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, + SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, + SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, + SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, + SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, + SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, + SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, +}; -typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata); +enum { + SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, + SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, + SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, + SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3, + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4, + SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5, + SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6, + SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, + SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, + SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, + SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, +}; -int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret); -sd_lldp* sd_lldp_unref(sd_lldp *lldp); +#define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1) -int sd_lldp_start(sd_lldp *lldp); -int sd_lldp_stop(sd_lldp *lldp); +#define SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \ + ((uint16_t) \ + (SD_LLDP_SYSTEM_CAPABILITIES_REPEATER| \ + SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE| \ + SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \ + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER| \ + SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS| \ + SD_LLDP_SYSTEM_CAPABILITIES_CVLAN| \ + SD_LLDP_SYSTEM_CAPABILITIES_SVLAN| \ + SD_LLDP_SYSTEM_CAPABILITIES_TPMR)) -int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority); -int sd_lldp_detach_event(sd_lldp *lldp); -int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata); -int sd_lldp_save(sd_lldp *lldp, const char *file); +#define SD_LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } +#define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } + +enum { + SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, + SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, + SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3, + SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, + SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, + SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, + SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, +}; + +typedef enum sd_lldp_event { + SD_LLDP_EVENT_ADDED = 'a', + SD_LLDP_EVENT_REMOVED = 'r', + SD_LLDP_EVENT_UPDATED = 'u', + SD_LLDP_EVENT_REFRESHED = 'f', +} sd_lldp_event; -int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl); -int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length); -int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length); -int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data); -int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length); +typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata); -/* IEEE 802.1 organizationally specific TLVs */ -int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id); -int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id); -int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length); -int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id); -int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id); +int sd_lldp_new(sd_lldp **ret, int ifindex); +sd_lldp* sd_lldp_unref(sd_lldp *lldp); -sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv); -sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); +int sd_lldp_start(sd_lldp *lldp); +int sd_lldp_stop(sd_lldp *lldp); -int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); +int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority); +int sd_lldp_detach_event(sd_lldp *lldp); -int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); +int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); + +/* Controls how much and what to store in the neighbors database */ +int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n); +int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask); +int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *address); + +int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***neighbors); + +int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size); +sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n); +sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n); + +/* Access to LLDP frame metadata */ +int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address); +int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address); +int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); + +/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */ +int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); +int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); +int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret); +int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret); +int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret); + +/* Low-level, iterative TLV access. This is for evertyhing else, it iteratively goes through all available TLVs + * (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */ +int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n); +int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n); +int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type); +int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type); +int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype); +int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype); +int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref); -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_packet, sd_lldp_packet_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref); _SD_END_DECLARATIONS; diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 8a72576ec8..3c44d63021 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -82,8 +82,6 @@ _SD_BEGIN_DECLARATIONS; #define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01) -#define SD_MESSAGE_BOOTCHART SD_ID128_MAKE(9f,26,aa,56,2c,f4,40,c2,b1,6c,77,3d,04,79,b5,18) - #define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d) #define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65) #define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57) diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 762947531d..29bcbe8e3e 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -52,7 +52,7 @@ int sd_ndisc_set_callback(sd_ndisc *nd, int sd_ndisc_set_index(sd_ndisc *nd, int interface_index); int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority); +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); int sd_ndisc_detach_event(sd_ndisc *nd); sd_event *sd_ndisc_get_event(sd_ndisc *nd); diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index b4798d2476..af7a797567 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -64,7 +64,7 @@ int sd_netlink_wait(sd_netlink *nl, uint64_t timeout); int sd_netlink_add_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata); int sd_netlink_remove_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata); -int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int priority); +int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority); int sd_netlink_detach_event(sd_netlink *nl); int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data); @@ -131,7 +131,7 @@ int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type); int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family); int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex); int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags); -int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type); +int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type); int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen); diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index e20d12c44d..0f13e2bae7 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -99,11 +99,11 @@ int sd_network_link_get_network_file(int ifindex, char **filename); /* Get DNS entries for a given link. These are string representations of * IP addresses */ -int sd_network_link_get_dns(int ifindex, char ***addr); +int sd_network_link_get_dns(int ifindex, char ***ret); /* Get NTP entries for a given link. These are domain names or string * representations of IP addresses */ -int sd_network_link_get_ntp(int ifindex, char ***addr); +int sd_network_link_get_ntp(int ifindex, char ***ret); /* Indicates whether or not LLMNR should be enabled for the link * Possible levels of support: yes, no, resolve @@ -133,19 +133,17 @@ int sd_network_link_get_dnssec(int ifindex, char **dnssec); */ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta); -int sd_network_link_get_lldp(int ifindex, char **lldp); - /* Get the search DNS domain names for a given link. */ int sd_network_link_get_search_domains(int ifindex, char ***domains); /* Get the route DNS domain names for a given link. */ int sd_network_link_get_route_domains(int ifindex, char ***domains); -/* Get the CARRIERS to which current link is bound to. */ -int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers); +/* Get the carrier interface indexes to which current link is bound to. */ +int sd_network_link_get_carrier_bound_to(int ifindex, int **ifindexes); /* Get the CARRIERS that are bound to current link. */ -int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers); +int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes); /* Get the timezone that was learnt on a specific link. */ int sd_network_link_get_timezone(int ifindex, char **timezone); diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index 903b917f70..1c792dab39 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -79,7 +79,7 @@ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec); int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid); -int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int priority); +int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int64_t priority); int sd_resolve_detach_event(sd_resolve *resolve); sd_event *sd_resolve_get_event(sd_resolve *resolve); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 863c628323..4377f1b910 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1820,7 +1820,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index b5925a47dc..59e1a3e921 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -864,7 +864,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic } service = hashmap_get(all_services, name); - if (!service){ + if (!service) { log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name); continue; } diff --git a/src/test/test-alloc-util.c b/src/test/test-alloc-util.c new file mode 100644 index 0000000000..cc4821eaf5 --- /dev/null +++ b/src/test/test-alloc-util.c @@ -0,0 +1,55 @@ +/*** + 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 "macro.h" +#include "util.h" + +static void test_alloca(void) { + static const uint8_t zero[997] = { }; + char *t; + + t = alloca_align(17, 512); + assert_se(!((uintptr_t)t & 0xff)); + memzero(t, 17); + + t = alloca0_align(997, 1024); + assert_se(!((uintptr_t)t & 0x1ff)); + assert_se(!memcmp(t, zero, 997)); +} + +static void test_memdup_multiply(void) { + int org[] = {1, 2, 3}; + int *dup; + + dup = (int*)memdup_multiply(org, sizeof(int), 3); + + assert_se(dup); + assert_se(dup[0] == 1); + assert_se(dup[1] == 2); + assert_se(dup[2] == 3); + free(dup); +} + +int main(int argc, char *argv[]) { + test_alloca(); + test_memdup_multiply(); + + return 0; +} diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c index d2add5880c..8e68d6510d 100644 --- a/src/test/test-boot-timestamps.c +++ b/src/test/test-boot-timestamps.c @@ -34,17 +34,18 @@ static int test_acpi_fpdt(void) { r = acpi_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - if (r != -ENOENT) - log_error_errno(r, "Failed to read ACPI FPDT: %m"); - return r; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -ENODATA; + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read ACPI FPDT: %m"); + return ok ? 0 : r; } log_info("ACPI FPDT: loader start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); - - return 0; + return 1; } static int test_efi_loader(void) { @@ -57,33 +58,34 @@ static int test_efi_loader(void) { r = efi_loader_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - if (r != -ENOENT) - log_error_errno(r, "Failed to read EFI loader data: %m"); - return r; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read EFI loader data: %m"); + return ok ? 0 : r; } log_info("EFI Loader: start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); - - return 0; + return 1; } -int main(int argc, char* argv[]) { +static int test_boot_timestamps(void) { char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)]; int r; dual_timestamp fw, l, k; - test_acpi_fpdt(); - test_efi_loader(); - dual_timestamp_from_monotonic(&k, 0); r = boot_timestamps(NULL, &fw, &l); if (r < 0) { - log_error_errno(r, "Failed to read variables: %m"); - return 1; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read variables: %m"); + return ok ? 0 : r; } log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0)); @@ -91,6 +93,21 @@ int main(int argc, char* argv[]) { log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime)); log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime)); log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime)); + return 1; +} + +int main(int argc, char* argv[]) { + int p, q, r; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + p = test_acpi_fpdt(); + assert(p >= 0); + q = test_efi_loader(); + assert(q >= 0); + r = test_boot_timestamps(); + assert(r >= 0); - return 0; + return (p > 0 || q > 0 || r >> 0) ? EXIT_SUCCESS : EXIT_TEST_SKIP; } diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 8754cb3381..5a8c6cbfb6 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -137,6 +137,7 @@ int main(int argc, char* argv[]) { test_next("2015-11-13 09:11:23.42", "EET", 12345, 1447398683420000); test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683420000, 1447398685190000); test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683419999, 1447398683420000); + test_next("Sun 16:00:00", "CET", 1456041600123456, 1456066800000000); assert_se(calendar_spec_from_string("test", &c) < 0); assert_se(calendar_spec_from_string("", &c) < 0); diff --git a/src/test/test-clock.c b/src/test/test-clock.c new file mode 100644 index 0000000000..84f775e5bc --- /dev/null +++ b/src/test/test-clock.c @@ -0,0 +1,96 @@ +/*** + This file is part of systemd. + + Copyright (C) 2016 Canonical Ltd. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <unistd.h> +#include <fcntl.h> + +#include "clock-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" +#include "macro.h" + +static void test_clock_is_localtime(void) { + char adjtime[] = "/tmp/test-adjtime.XXXXXX"; + int fd = -1; + _cleanup_fclose_ FILE* f = NULL; + + static const struct scenario { + const char* contents; + int expected_result; + } scenarios[] = { + /* adjtime configures UTC */ + {"0.0 0 0\n0\nUTC\n", 0}, + /* adjtime configures local time */ + {"0.0 0 0\n0\nLOCAL\n", 1}, + /* no final EOL */ + {"0.0 0 0\n0\nUTC", 0}, + {"0.0 0 0\n0\nLOCAL", 1}, + /* empty value -> defaults to UTC */ + {"0.0 0 0\n0\n", 0}, + /* unknown value -> defaults to UTC */ + {"0.0 0 0\n0\nFOO\n", 0}, + /* no third line */ + {"0.0 0 0", 0}, + {"0.0 0 0\n", 0}, + {"0.0 0 0\n0", 0}, + }; + + /* without an adjtime file we default to UTC */ + assert_se(clock_is_localtime("/nonexisting/adjtime") == 0); + + fd = mkostemp_safe(adjtime, O_WRONLY|O_CLOEXEC); + assert_se(fd >= 0); + log_info("adjtime test file: %s", adjtime); + f = fdopen(fd, "w"); + assert_se(f); + + for (size_t i = 0; i < ELEMENTSOF(scenarios); ++i) { + log_info("scenario #%zu:, expected result %i", i, scenarios[i].expected_result); + log_info("%s", scenarios[i].contents); + rewind(f); + ftruncate(fd, 0); + assert_se(write_string_stream(f, scenarios[i].contents, false) == 0); + assert_se(clock_is_localtime(adjtime) == scenarios[i].expected_result); + } + + unlink(adjtime); +} + +/* Test with the real /etc/adjtime */ +static void test_clock_is_localtime_system(void) { + int r; + r = clock_is_localtime(NULL); + + if (access("/etc/adjtime", F_OK) == 0) { + log_info("/etc/adjtime exists, clock_is_localtime() == %i", r); + /* if /etc/adjtime exists we expect some answer, no error or + * crash */ + assert_se(r == 0 || r == 1); + } else + /* default is UTC if there is no /etc/adjtime */ + assert_se(r == 0); +} + +int main(int argc, char *argv[]) { + test_clock_is_localtime(); + test_clock_is_localtime_system(); + + return 0; +} diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index b3a4c40339..be5d2611f8 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -215,6 +215,14 @@ static void test_config_parse_nsec(void) { test_config_parse_nsec_one("garbage", 0); } +static void test_config_parse_iec_uint64(void) { + uint64_t offset = 0; + assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); + assert_se(offset == 4 * 1024 * 1024); + + assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); +} + int main(int argc, char **argv) { log_parse_environment(); log_open(); @@ -230,6 +238,7 @@ int main(int argc, char **argv) { test_config_parse_mode(); test_config_parse_sec(); test_config_parse_nsec(); + test_config_parse_iec_uint64(); return 0; } diff --git a/src/test/test-copy.c b/src/test/test-copy.c index ad57cb0202..cb437754b4 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -24,6 +24,7 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "log.h" #include "macro.h" #include "mkdir.h" #include "path-util.h" @@ -39,6 +40,8 @@ static void test_copy_file(void) { size_t sz = 0; int fd; + log_info("%s", __func__); + fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); close(fd); @@ -66,6 +69,8 @@ static void test_copy_file_fd(void) { char text[] = "boohoo\nfoo\n\tbar\n"; char buf[64] = {0}; + log_info("%s", __func__); + in_fd = mkostemp_safe(in_fn, O_RDWR); assert_se(in_fd >= 0); out_fd = mkostemp_safe(out_fn, O_RDWR); @@ -91,6 +96,8 @@ static void test_copy_tree(void) { "link2", "dir1/file"); char **p, **link; + log_info("%s", __func__); + (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); @@ -173,11 +180,65 @@ static void test_copy_bytes(void) { assert_se(r == -EBADF); } +static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint64_t max_bytes) { + char fn2[] = "/tmp/test-copy-file-XXXXXX"; + char fn3[] = "/tmp/test-copy-file-XXXXXX"; + _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1; + int r; + struct stat buf, buf2, buf3; + + log_info("%s try_reflink=%s max_bytes=%" PRIu64, __func__, yes_no(try_reflink), max_bytes); + + fd = open(src, O_RDONLY | O_CLOEXEC | O_NOCTTY); + assert_se(fd >= 0); + + fd2 = mkostemp_safe(fn2, O_RDWR); + assert_se(fd2 >= 0); + + fd3 = mkostemp_safe(fn3, O_WRONLY); + assert_se(fd3 >= 0); + + r = copy_bytes(fd, fd2, max_bytes, try_reflink); + if (max_bytes == (uint64_t) -1) + assert_se(r == 0); + else + assert_se(IN_SET(r, 0, 1)); + + assert_se(lseek(fd2, 0, SEEK_SET) == 0); + + r = copy_bytes(fd2, fd3, max_bytes, try_reflink); + if (max_bytes == (uint64_t) -1) + assert_se(r == 0); + else + /* We cannot distinguish between the input being exactly max_bytes + * or longer than max_bytes (without trying to read one more byte, + * or calling stat, or FION_READ, etc, and we don't want to do any + * of that). So we expect "truncation" since we know that file we + * are copying is exactly max_bytes bytes. */ + assert_se(r == 1); + + assert_se(fstat(fd, &buf) == 0); + assert_se(fstat(fd2, &buf2) == 0); + assert_se(fstat(fd3, &buf3) == 0); + + assert_se((uint64_t) buf2.st_size == MIN((uint64_t) buf.st_size, max_bytes)); + assert_se(buf3.st_size == buf2.st_size); + + unlink(fn2); + unlink(fn3); +} + int main(int argc, char *argv[]) { test_copy_file(); test_copy_file_fd(); test_copy_tree(); test_copy_bytes(); + test_copy_bytes_regular_file(argv[0], false, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], true, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], false, 1000); /* smaller than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 1000); + test_copy_bytes_regular_file(argv[0], false, 32000); /* larger than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 32000); return 0; } diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c new file mode 100644 index 0000000000..8818d1ffb7 --- /dev/null +++ b/src/test/test-cpu-set-util.c @@ -0,0 +1,143 @@ +/*** + 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 "cpu-set-util.h" +#include "macro.h" + +static void test_parse_cpu_set(void) { + cpu_set_t *c = NULL; + int ncpus; + int cpu; + + /* Simple range (from CPUAffinity example) */ + ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); + c = mfree(c); + + /* A more interesting range */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Quoted strings */ + ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Use commas as separators */ + ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Commas with spaces (and trailing comma, space) */ + ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges */ + ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges with trailing comma, space */ + ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Negative range (returns empty cpu_set) */ + ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); + c = mfree(c); + + /* Overlapping ranges */ + ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); + for (cpu = 0; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Mix ranges and individual CPUs */ + ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); + assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 4; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Garbage */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Range with garbage */ + ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Empty string */ + c = NULL; + ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus == 0); /* empty string returns 0 */ + assert_se(!c); + + /* Runnaway quoted string */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); +} + +int main(int argc, char *argv[]) { + test_parse_cpu_set(); + + return 0; +} diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c index 4ce00f4b1f..a7cb426282 100644 --- a/src/test/test-daemon.c +++ b/src/test/test-daemon.c @@ -38,27 +38,27 @@ int main(int argc, char*argv[]) { sd_notify(0, "STATUS=Starting up"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Running\n" "READY=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Reloading\n" "RELOADING=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Running\n" "READY=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Quitting\n" "STOPPING=1"); - sleep(5); + sleep(1); return EXIT_SUCCESS; } diff --git a/src/test/test-env-replace.c b/src/test/test-env-util.c index 264acc6ea6..35bb62906e 100644 --- a/src/test/test-env-replace.c +++ b/src/test/test-env-util.c @@ -2,6 +2,7 @@ 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 @@ -177,10 +178,37 @@ static void test_env_name_is_valid(void) { assert_se(!env_name_is_valid(NULL)); assert_se(!env_name_is_valid("")); + assert_se(!env_name_is_valid("xxx\a")); + assert_se(!env_name_is_valid("xxx\007b")); + assert_se(!env_name_is_valid("\007\009")); assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong")); assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed")); } +static void test_env_value_is_valid(void) { + assert_se(env_value_is_valid("")); + assert_se(env_value_is_valid("gÅ‚Ä…b kapuÅ›ciany")); + assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\"")); +} + +static void test_env_assignment_is_valid(void) { + assert_se(env_assignment_is_valid("a=")); + assert_se(env_assignment_is_valid("b=gÅ‚Ä…b kapuÅ›ciany")); + assert_se(env_assignment_is_valid("c=\\007\\009\\011")); + assert_se(env_assignment_is_valid("e=printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\"")); + + assert_se(!env_assignment_is_valid("=")); + assert_se(!env_assignment_is_valid("a b=")); + assert_se(!env_assignment_is_valid("a =")); + assert_se(!env_assignment_is_valid(" b=")); + /* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */ + assert_se(!env_assignment_is_valid("a.b=")); + assert_se(!env_assignment_is_valid("a-b=")); + assert_se(!env_assignment_is_valid("\007=gÅ‚Ä…b kapuÅ›ciany")); + assert_se(!env_assignment_is_valid("c\009=\007\009\011")); + assert_se(!env_assignment_is_valid("gÅ‚Ä…b=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\"")); +} + int main(int argc, char *argv[]) { test_strv_env_delete(); test_strv_env_unset(); @@ -189,6 +217,8 @@ int main(int argc, char *argv[]) { test_replace_env_arg(); test_env_clean(); test_env_name_is_valid(); + test_env_value_is_valid(); + test_env_assignment_is_valid(); return 0; } diff --git a/src/test/test-escape.c b/src/test/test-escape.c new file mode 100644 index 0000000000..6cbb8443fe --- /dev/null +++ b/src/test/test-escape.c @@ -0,0 +1,114 @@ +/*** + 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 "escape.h" +#include "macro.h" + +static void test_cescape(void) { + _cleanup_free_ char *escaped; + + assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); + assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); +} + +static void test_cunescape(void) { + _cleanup_free_ char *unescaped; + + assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0); + assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00")); + unescaped = mfree(unescaped); + + /* incomplete sequences */ + assert_se(cunescape("\\x0", 0, &unescaped) < 0); + assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\x0")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\x", 0, &unescaped) < 0); + assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\x")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\", 0, &unescaped) < 0); + assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\11", 0, &unescaped) < 0); + assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\11")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\1", 0, &unescaped) < 0); + assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\1")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\u0000", 0, &unescaped) < 0); + assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "ßßΠA")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\073", 0, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, ";")); +} + +static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { + _cleanup_free_ char *r; + + assert_se(r = shell_escape(s, bad)); + assert_se(streq_ptr(r, expected)); +} + +static void test_shell_escape(void) { + test_shell_escape_one("", "", ""); + test_shell_escape_one("\\", "", "\\\\"); + test_shell_escape_one("foobar", "", "foobar"); + test_shell_escape_one("foobar", "o", "f\\o\\obar"); + test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz"); +} + +static void test_shell_maybe_quote_one(const char *s, const char *expected) { + _cleanup_free_ char *r; + + assert_se(r = shell_maybe_quote(s)); + assert_se(streq(r, expected)); +} + +static void test_shell_maybe_quote(void) { + + test_shell_maybe_quote_one("", ""); + test_shell_maybe_quote_one("\\", "\"\\\\\""); + test_shell_maybe_quote_one("\"", "\"\\\"\""); + test_shell_maybe_quote_one("foobar", "foobar"); + test_shell_maybe_quote_one("foo bar", "\"foo bar\""); + test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\""); + test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); +} + +int main(int argc, char *argv[]) { + test_cescape(); + test_cunescape(); + test_shell_escape(); + test_shell_maybe_quote(); + + return 0; +} diff --git a/src/test/test-execute.c b/src/test/test-execute.c index d021be4671..901cc44af6 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -91,7 +91,7 @@ static void test_exec_personality(Manager *m) { #elif defined(__s390__) test(m, "exec-personality-s390.service", 0, CLD_EXITED); -#else +#elif defined(__i386__) test(m, "exec-personality-x86.service", 0, CLD_EXITED); #endif } @@ -130,18 +130,33 @@ static void test_exec_systemcallerrornumber(Manager *m) { #endif } +static void test_exec_systemcall_system_mode_with_user(Manager *m) { +#ifdef HAVE_SECCOMP + if (getpwnam("nobody")) + test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED); + else if (getpwnam("nfsnobody")) + test(m, "exec-systemcallfilter-system-user-nfsnobody.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_systemcall_system_mode_with_user, could not find nobody/nfsnobody user: %m"); +#endif +} + static void test_exec_user(Manager *m) { if (getpwnam("nobody")) test(m, "exec-user.service", 0, CLD_EXITED); + else if (getpwnam("nfsnobody")) + test(m, "exec-user-nfsnobody.service", 0, CLD_EXITED); else - log_error_errno(errno, "Skipping test_exec_user, could not find nobody user: %m"); + log_error_errno(errno, "Skipping test_exec_user, could not find nobody/nfsnobody user: %m"); } static void test_exec_group(Manager *m) { if (getgrnam("nobody")) test(m, "exec-group.service", 0, CLD_EXITED); + else if (getgrnam("nfsnobody")) + test(m, "exec-group-nfsnobody.service", 0, CLD_EXITED); else - log_error_errno(errno, "Skipping test_exec_group, could not find nobody group: %m"); + log_error_errno(errno, "Skipping test_exec_group, could not find nobody/nfsnobody group: %m"); } static void test_exec_environment(Manager *m) { @@ -204,8 +219,10 @@ static void test_exec_runtimedirectory(Manager *m) { test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); if (getgrnam("nobody")) test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + else if (getgrnam("nfsnobody")) + test(m, "exec-runtimedirectory-owner-nfsnobody.service", 0, CLD_EXITED); else - log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody group: %m"); + log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody/nfsnobody group: %m"); } static void test_exec_capabilityboundingset(Manager *m) { @@ -234,9 +251,16 @@ static void test_exec_capabilityambientset(Manager *m) { * in the first place for the tests. */ r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); if (r >= 0 || errno != EINVAL) { - test(m, "exec-capabilityambientset.service", 0, CLD_EXITED); - test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED); - } + if (getpwnam("nobody")) { + test(m, "exec-capabilityambientset.service", 0, CLD_EXITED); + test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED); + } else if (getpwnam("nfsnobody")) { + test(m, "exec-capabilityambientset-nfsnobody.service", 0, CLD_EXITED); + test(m, "exec-capabilityambientset-merge-nfsnobody.service", 0, CLD_EXITED); + } else + log_error_errno(errno, "Skipping test_exec_capabilityambientset, could not find nobody/nfsnobody user: %m"); + } else + log_error_errno(errno, "Skipping test_exec_capabilityambientset, the kernel does not support ambient capabilities: %m"); } static void test_exec_privatenetwork(Manager *m) { @@ -267,8 +291,31 @@ static void test_exec_spec_interpolation(Manager *m) { test(m, "exec-spec-interpolation.service", 0, CLD_EXITED); } +static int run_tests(ManagerRunningAs running_as, test_function_t *tests) { + test_function_t *test = NULL; + Manager *m = NULL; + int r; + + assert_se(tests); + + r = manager_new(running_as, true, &m); + if (MANAGER_SKIP_TEST(r)) { + printf("Skipping test: manager_new: %s\n", strerror(-r)); + return EXIT_TEST_SKIP; + } + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); + + for (test = tests; test && *test; test++) + (*test)(m); + + manager_free(m); + + return 0; +} + int main(int argc, char *argv[]) { - test_function_t tests[] = { + test_function_t user_tests[] = { test_exec_workingdirectory, test_exec_personality, test_exec_ignoresigpipe, @@ -291,8 +338,10 @@ int main(int argc, char *argv[]) { test_exec_spec_interpolation, NULL, }; - test_function_t *test = NULL; - Manager *m = NULL; + test_function_t system_tests[] = { + test_exec_systemcall_system_mode_with_user, + NULL, + }; int r; log_parse_environment(); @@ -317,18 +366,9 @@ int main(int argc, char *argv[]) { assert_se(unsetenv("VAR2") == 0); assert_se(unsetenv("VAR3") == 0); - r = manager_new(MANAGER_USER, true, &m); - if (MANAGER_SKIP_TEST(r)) { - printf("Skipping test: manager_new: %s\n", strerror(-r)); - return EXIT_TEST_SKIP; - } - assert_se(r >= 0); - assert_se(manager_startup(m, NULL, NULL) >= 0); - - for (test = tests; test && *test; test++) - (*test)(m); + r = run_tests(MANAGER_USER, user_tests); + if (r != 0) + return r; - manager_free(m); - - return 0; + return run_tests(MANAGER_SYSTEM, system_tests); } diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c new file mode 100644 index 0000000000..421d3bdeb3 --- /dev/null +++ b/src/test/test-fd-util.c @@ -0,0 +1,103 @@ +/*** + 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 <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" + +static void test_close_many(void) { + int fds[3]; + char name0[] = "/tmp/test-close-many.XXXXXX"; + char name1[] = "/tmp/test-close-many.XXXXXX"; + char name2[] = "/tmp/test-close-many.XXXXXX"; + + fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC); + fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC); + fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC); + + close_many(fds, 2); + + assert_se(fcntl(fds[0], F_GETFD) == -1); + assert_se(fcntl(fds[1], F_GETFD) == -1); + assert_se(fcntl(fds[2], F_GETFD) >= 0); + + safe_close(fds[2]); + + unlink(name0); + unlink(name1); + unlink(name2); +} + +static void test_close_nointr(void) { + char name[] = "/tmp/test-test-close_nointr.XXXXXX"; + int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(close_nointr(fd) >= 0); + assert_se(close_nointr(fd) < 0); + + unlink(name); +} + +static void test_same_fd(void) { + _cleanup_close_pair_ int p[2] = { -1, -1 }; + _cleanup_close_ int a = -1, b = -1, c = -1; + + assert_se(pipe2(p, O_CLOEXEC) >= 0); + assert_se((a = dup(p[0])) >= 0); + assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0); + assert_se((c = dup(a)) >= 0); + + assert_se(same_fd(p[0], p[0]) > 0); + assert_se(same_fd(p[1], p[1]) > 0); + assert_se(same_fd(a, a) > 0); + assert_se(same_fd(b, b) > 0); + + assert_se(same_fd(a, p[0]) > 0); + assert_se(same_fd(p[0], a) > 0); + assert_se(same_fd(c, p[0]) > 0); + assert_se(same_fd(p[0], c) > 0); + assert_se(same_fd(a, c) > 0); + assert_se(same_fd(c, a) > 0); + + assert_se(same_fd(p[0], p[1]) == 0); + assert_se(same_fd(p[1], p[0]) == 0); + assert_se(same_fd(p[0], b) == 0); + assert_se(same_fd(b, p[0]) == 0); + assert_se(same_fd(p[1], a) == 0); + assert_se(same_fd(a, p[1]) == 0); + assert_se(same_fd(p[1], b) == 0); + assert_se(same_fd(b, p[1]) == 0); + + assert_se(same_fd(a, b) == 0); + assert_se(same_fd(b, a) == 0); +} + +int main(int argc, char *argv[]) { + test_close_many(); + test_close_nointr(); + test_same_fd(); + + return 0; +} diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 5586a2d6c1..ec9f173da2 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -27,6 +27,7 @@ #include "env-util.h" #include "fd-util.h" #include "fileio.h" +#include "io-util.h" #include "parse-util.h" #include "process-util.h" #include "string-util.h" @@ -425,6 +426,134 @@ static void test_load_env_file_pairs(void) { unlink(fn); } +static void test_search_and_fopen(void) { + const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL}; + char name[] = "/tmp/test-search_and_fopen.XXXXXX"; + int fd = -1; + int r; + FILE *f; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = search_and_fopen(basename(name), "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen(name, "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen(basename(name), "r", "/", dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); + assert_se(r < 0); + r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); + assert_se(r < 0); + + r = unlink(name); + assert_se(r == 0); + + r = search_and_fopen(basename(name), "r", NULL, dirs, &f); + assert_se(r < 0); +} + + +static void test_search_and_fopen_nulstr(void) { + const char dirs[] = "/tmp/foo/bar\0/tmp\0"; + char name[] = "/tmp/test-search_and_fopen.XXXXXX"; + int fd = -1; + int r; + FILE *f; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); + assert_se(r < 0); + r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); + assert_se(r < 0); + + r = unlink(name); + assert_se(r == 0); + + r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); + assert_se(r < 0); +} + +static void test_writing_tmpfile(void) { + char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX"; + _cleanup_free_ char *contents = NULL; + size_t size; + int fd, r; + struct iovec iov[3]; + + IOVEC_SET_STRING(iov[0], "abc\n"); + IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n"); + IOVEC_SET_STRING(iov[2], ""); + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + printf("tmpfile: %s", name); + + r = writev(fd, iov, 3); + assert_se(r >= 0); + + r = read_full_file(name, &contents, &size); + assert_se(r == 0); + printf("contents: %s", contents); + assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n")); + + unlink(name); +} + +static void test_tempfn(void) { + char *ret = NULL, *p; + + assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX")); + free(ret); + + assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0); + assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX")); + free(ret); + + assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/.#waldo")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/waldo/.#")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -439,6 +568,10 @@ int main(int argc, char *argv[]) { test_write_string_file_no_create(); test_write_string_file_verify(); test_load_env_file_pairs(); + test_search_and_fopen(); + test_search_and_fopen_nulstr(); + test_writing_tmpfile(); + test_tempfn(); return 0; } diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c new file mode 100644 index 0000000000..6db2c2b6f1 --- /dev/null +++ b/src/test/test-fs-util.c @@ -0,0 +1,91 @@ +/*** + 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 <unistd.h> + +#include "alloc-util.h" +#include "fileio.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "mkdir.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" + +static void test_unlink_noerrno(void) { + char name[] = "/tmp/test-close_nointr.XXXXXX"; + int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(close_nointr(fd) >= 0); + + { + PROTECT_ERRNO; + errno = -42; + assert_se(unlink_noerrno(name) >= 0); + assert_se(errno == -42); + assert_se(unlink_noerrno(name) < 0); + assert_se(errno == -42); + } +} + +static void test_readlink_and_make_absolute(void) { + char tempdir[] = "/tmp/test-readlink_and_make_absolute"; + char name[] = "/tmp/test-readlink_and_make_absolute/original"; + char name2[] = "test-readlink_and_make_absolute/original"; + char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; + char *r = NULL; + + assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); + assert_se(touch(name) >= 0); + + assert_se(symlink(name, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); + assert_se(streq(r, name)); + free(r); + assert_se(unlink(name_alias) >= 0); + + assert_se(chdir(tempdir) >= 0); + assert_se(symlink(name2, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); + assert_se(streq(r, name)); + free(r); + assert_se(unlink(name_alias) >= 0); + + assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); +} + +static void test_get_files_in_directory(void) { + _cleanup_strv_free_ char **l = NULL, **t = NULL; + + assert_se(get_files_in_directory("/tmp", &l) >= 0); + assert_se(get_files_in_directory(".", &t) >= 0); + assert_se(get_files_in_directory(".", NULL) >= 0); +} + +int main(int argc, char *argv[]) { + test_unlink_noerrno(); + test_readlink_and_make_absolute(); + test_get_files_in_directory(); + + return 0; +} diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index ea3d1a6909..63a4b8c243 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -131,8 +131,45 @@ static void test_fstab_yes_no_option(void) { assert_se(fstab_test_yes_no_option("nofail,nofail=0,fail=0", "nofail\0fail\0") == false); } +static void test_fstab_node_to_udev_node(void) { + char *n; + + n = fstab_node_to_udev_node("LABEL=applé/jack"); + puts(n); + assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); + free(n); + + n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); + free(n); + + n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PONIES=awesome"); + puts(n); + assert_se(streq(n, "PONIES=awesome")); + free(n); + + n = fstab_node_to_udev_node("/dev/xda1"); + puts(n); + assert_se(streq(n, "/dev/xda1")); + free(n); +} + int main(void) { test_fstab_filter_options(); test_fstab_find_pri(); test_fstab_yes_no_option(); + test_fstab_node_to_udev_node(); + + return 0; } diff --git a/src/bootchart/svg.h b/src/test/test-glob-util.c index 6e06b5ad97..227d4290f0 100644 --- a/src/bootchart/svg.h +++ b/src/test/test-glob-util.c @@ -1,12 +1,7 @@ -#pragma once - /*** This file is part of systemd. - Copyright (C) 2009-2013 Intel Corporation - - Authors: - Auke Kok <auke-jan.h.kok@intel.com> + 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 @@ -22,14 +17,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -int svg_do(FILE *of, - const char *build, - struct list_sample_data *head, - struct ps_struct *ps_first, - int n_samples, - int pscount, - int n_cpus, - double graph_start, - double log_start, - double interval, - int overrun); +#include <fcntl.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fileio.h" +#include "glob-util.h" +#include "macro.h" + +static void test_glob_exists(void) { + char name[] = "/tmp/test-glob_exists.XXXXXX"; + int fd = -1; + int r; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = glob_exists("/tmp/test-glob_exists*"); + assert_se(r == 1); + + r = unlink(name); + assert_se(r == 0); + r = glob_exists("/tmp/test-glob_exists*"); + assert_se(r == 0); +} + +int main(void) { + test_glob_exists(); + + return 0; +} diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index 6bf33306a9..1bd5c02f87 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -323,26 +323,29 @@ static void test_hashmap_remove_value(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; char *r; - r = hashmap_remove_value(NULL, "key 1", (void*) "val 1"); + char val1[] = "val 1"; + char val2[] = "val 2"; + + r = hashmap_remove_value(NULL, "key 1", val1); assert_se(r == NULL); m = hashmap_new(&string_hash_ops); assert_se(m); - r = hashmap_remove_value(m, "key 1", (void*) "val 1"); + r = hashmap_remove_value(m, "key 1", val1); assert_se(r == NULL); - hashmap_put(m, "key 1", (void*) "val 1"); - hashmap_put(m, "key 2", (void*) "val 2"); + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); - r = hashmap_remove_value(m, "key 1", (void*) "val 1"); + r = hashmap_remove_value(m, "key 1", val1); assert_se(streq(r, "val 1")); r = hashmap_get(m, "key 2"); assert_se(streq(r, "val 2")); assert_se(!hashmap_get(m, "key 1")); - r = hashmap_remove_value(m, "key 2", (void*) "val 1"); + r = hashmap_remove_value(m, "key 2", val1); assert_se(r == NULL); r = hashmap_get(m, "key 2"); diff --git a/src/test/test-hexdecoct.c b/src/test/test-hexdecoct.c new file mode 100644 index 0000000000..276f25d091 --- /dev/null +++ b/src/test/test-hexdecoct.c @@ -0,0 +1,387 @@ +/*** + 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 "hexdecoct.h" +#include "macro.h" +#include "string-util.h" + +static void test_hexchar(void) { + assert_se(hexchar(0xa) == 'a'); + assert_se(hexchar(0x0) == '0'); +} + +static void test_unhexchar(void) { + assert_se(unhexchar('a') == 0xA); + assert_se(unhexchar('A') == 0xA); + assert_se(unhexchar('0') == 0x0); +} + +static void test_base32hexchar(void) { + assert_se(base32hexchar(0) == '0'); + assert_se(base32hexchar(9) == '9'); + assert_se(base32hexchar(10) == 'A'); + assert_se(base32hexchar(31) == 'V'); +} + +static void test_unbase32hexchar(void) { + assert_se(unbase32hexchar('0') == 0); + assert_se(unbase32hexchar('9') == 9); + assert_se(unbase32hexchar('A') == 10); + assert_se(unbase32hexchar('V') == 31); + assert_se(unbase32hexchar('=') == -EINVAL); +} + +static void test_base64char(void) { + assert_se(base64char(0) == 'A'); + assert_se(base64char(26) == 'a'); + assert_se(base64char(63) == '/'); +} + +static void test_unbase64char(void) { + assert_se(unbase64char('A') == 0); + assert_se(unbase64char('Z') == 25); + assert_se(unbase64char('a') == 26); + assert_se(unbase64char('z') == 51); + assert_se(unbase64char('0') == 52); + assert_se(unbase64char('9') == 61); + assert_se(unbase64char('+') == 62); + assert_se(unbase64char('/') == 63); + assert_se(unbase64char('=') == -EINVAL); +} + +static void test_octchar(void) { + assert_se(octchar(00) == '0'); + assert_se(octchar(07) == '7'); +} + +static void test_unoctchar(void) { + assert_se(unoctchar('0') == 00); + assert_se(unoctchar('7') == 07); +} + +static void test_decchar(void) { + assert_se(decchar(0) == '0'); + assert_se(decchar(9) == '9'); +} + +static void test_undecchar(void) { + assert_se(undecchar('0') == 0); + assert_se(undecchar('9') == 9); +} + +static void test_unhexmem(void) { + const char *hex = "efa214921"; + const char *hex_invalid = "efa214921o"; + _cleanup_free_ char *hex2 = NULL; + _cleanup_free_ void *mem = NULL; + size_t len; + + assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); + assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); + assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); + + assert_se((hex2 = hexmem(mem, len))); + + free(mem); + + assert_se(memcmp(hex, hex2, strlen(hex)) == 0); + + free(hex2); + + assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); + assert_se((hex2 = hexmem(mem, len))); + assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base32hexmem(void) { + char *b32; + + b32 = base32hexmem("", strlen(""), true); + assert_se(b32); + assert_se(streq(b32, "")); + free(b32); + + b32 = base32hexmem("f", strlen("f"), true); + assert_se(b32); + assert_se(streq(b32, "CO======")); + free(b32); + + b32 = base32hexmem("fo", strlen("fo"), true); + assert_se(b32); + assert_se(streq(b32, "CPNG====")); + free(b32); + + b32 = base32hexmem("foo", strlen("foo"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMU===")); + free(b32); + + b32 = base32hexmem("foob", strlen("foob"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOG=")); + free(b32); + + b32 = base32hexmem("fooba", strlen("fooba"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1")); + free(b32); + + b32 = base32hexmem("foobar", strlen("foobar"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1E8======")); + free(b32); + + b32 = base32hexmem("", strlen(""), false); + assert_se(b32); + assert_se(streq(b32, "")); + free(b32); + + b32 = base32hexmem("f", strlen("f"), false); + assert_se(b32); + assert_se(streq(b32, "CO")); + free(b32); + + b32 = base32hexmem("fo", strlen("fo"), false); + assert_se(b32); + assert_se(streq(b32, "CPNG")); + free(b32); + + b32 = base32hexmem("foo", strlen("foo"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMU")); + free(b32); + + b32 = base32hexmem("foob", strlen("foob"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOG")); + free(b32); + + b32 = base32hexmem("fooba", strlen("fooba"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1")); + free(b32); + + b32 = base32hexmem("foobar", strlen("foobar"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1E8")); + free(b32); +} + +static void test_unbase32hexmem(void) { + void *mem; + size_t len; + + assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL); + + assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + + assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base64mem(void) { + char *b64; + + assert_se(base64mem("", strlen(""), &b64) == 0); + assert_se(streq(b64, "")); + free(b64); + + assert_se(base64mem("f", strlen("f"), &b64) == 4); + assert_se(streq(b64, "Zg==")); + free(b64); + + assert_se(base64mem("fo", strlen("fo"), &b64) == 4); + assert_se(streq(b64, "Zm8=")); + free(b64); + + assert_se(base64mem("foo", strlen("foo"), &b64) == 4); + assert_se(streq(b64, "Zm9v")); + free(b64); + + assert_se(base64mem("foob", strlen("foob"), &b64) == 8); + assert_se(streq(b64, "Zm9vYg==")); + free(b64); + + assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8); + assert_se(streq(b64, "Zm9vYmE=")); + free(b64); + + assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8); + assert_se(streq(b64, "Zm9vYmFy")); + free(b64); +} + +static void test_unbase64mem(void) { + void *mem; + size_t len; + + assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); + assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); +} + +static void test_hexdump(void) { + uint8_t data[146]; + unsigned i; + + hexdump(stdout, NULL, 0); + hexdump(stdout, "", 0); + hexdump(stdout, "", 1); + hexdump(stdout, "x", 1); + hexdump(stdout, "x", 2); + hexdump(stdout, "foobar", 7); + hexdump(stdout, "f\nobar", 7); + hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); + + for (i = 0; i < ELEMENTSOF(data); i++) + data[i] = i*2; + + hexdump(stdout, data, sizeof(data)); +} + +int main(int argc, char *argv[]) { + test_hexchar(); + test_unhexchar(); + test_base32hexchar(); + test_unbase32hexchar(); + test_base64char(); + test_unbase64char(); + test_octchar(); + test_unoctchar(); + test_decchar(); + test_undecchar(); + test_unhexmem(); + test_base32hexmem(); + test_unbase32hexmem(); + test_base64mem(); + test_unbase64mem(); + test_hexdump(); + + return 0; +} diff --git a/src/test/test-io-util.c b/src/test/test-io-util.c new file mode 100644 index 0000000000..10bd3833bc --- /dev/null +++ b/src/test/test-io-util.c @@ -0,0 +1,69 @@ +/*** + 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 <stdlib.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "macro.h" + +static void test_sparse_write_one(int fd, const char *buffer, size_t n) { + char check[n]; + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n); + + assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n); + assert_se(ftruncate(fd, n) >= 0); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(read(fd, check, n) == (ssize_t) n); + + assert_se(memcmp(buffer, check, n) == 0); +} + +static void test_sparse_write(void) { + const char test_a[] = "test"; + const char test_b[] = "\0\0\0\0test\0\0\0\0"; + const char test_c[] = "\0\0test\0\0\0\0"; + const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0"; + const char test_e[] = "test\0\0\0\0test"; + _cleanup_close_ int fd = -1; + char fn[] = "/tmp/sparseXXXXXX"; + + fd = mkostemp(fn, O_CLOEXEC); + assert_se(fd >= 0); + unlink(fn); + + test_sparse_write_one(fd, test_a, sizeof(test_a)); + test_sparse_write_one(fd, test_b, sizeof(test_b)); + test_sparse_write_one(fd, test_c, sizeof(test_c)); + test_sparse_write_one(fd, test_d, sizeof(test_d)); + test_sparse_write_one(fd, test_e, sizeof(test_e)); +} + +int main(void) { + test_sparse_write(); + + return 0; +} diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 2464d32458..c5bcaf47bb 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -23,9 +23,14 @@ int main(int argc, char *argv[]) { uid_t uid; - - assert_se(argc == 2); - assert_se(parse_uid(argv[1], &uid) >= 0); + int r; + const char* name = argv[1] ?: "nfsnobody"; + + r = get_user_creds(&name, &uid, NULL, NULL, NULL); + if (r < 0) { + log_error_errno(r, "Failed to resolve \"%s\": %m", name); + return EXIT_FAILURE; + } return clean_ipc(uid) < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index a7eb60e8cf..e28de9b37b 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -24,170 +24,140 @@ #include "libudev.h" +#include "fd-util.h" +#include "log.h" #include "stdio-util.h" #include "string-util.h" #include "udev-util.h" #include "util.h" -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - static void print_device(struct udev_device *device) { const char *str; dev_t devnum; int count; struct udev_list_entry *list_entry; - printf("*** device: %p ***\n", device); + log_info("*** device: %p ***", device); str = udev_device_get_action(device); if (str != NULL) - printf("action: '%s'\n", str); + log_info("action: '%s'", str); str = udev_device_get_syspath(device); - printf("syspath: '%s'\n", str); + log_info("syspath: '%s'", str); str = udev_device_get_sysname(device); - printf("sysname: '%s'\n", str); + log_info("sysname: '%s'", str); str = udev_device_get_sysnum(device); if (str != NULL) - printf("sysnum: '%s'\n", str); + log_info("sysnum: '%s'", str); str = udev_device_get_devpath(device); - printf("devpath: '%s'\n", str); + log_info("devpath: '%s'", str); str = udev_device_get_subsystem(device); if (str != NULL) - printf("subsystem: '%s'\n", str); + log_info("subsystem: '%s'", str); str = udev_device_get_devtype(device); if (str != NULL) - printf("devtype: '%s'\n", str); + log_info("devtype: '%s'", str); str = udev_device_get_driver(device); if (str != NULL) - printf("driver: '%s'\n", str); + log_info("driver: '%s'", str); str = udev_device_get_devnode(device); if (str != NULL) - printf("devname: '%s'\n", str); + log_info("devname: '%s'", str); devnum = udev_device_get_devnum(device); if (major(devnum) > 0) - printf("devnum: %u:%u\n", major(devnum), minor(devnum)); + log_info("devnum: %u:%u", major(devnum), minor(devnum)); count = 0; udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { - printf("link: '%s'\n", udev_list_entry_get_name(list_entry)); + log_info("link: '%s'", udev_list_entry_get_name(list_entry)); count++; } if (count > 0) - printf("found %i links\n", count); + log_info("found %i links", count); count = 0; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) { - printf("property: '%s=%s'\n", + log_info("property: '%s=%s'", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); count++; } if (count > 0) - printf("found %i properties\n", count); + log_info("found %i properties", count); str = udev_device_get_property_value(device, "MAJOR"); if (str != NULL) - printf("MAJOR: '%s'\n", str); + log_info("MAJOR: '%s'", str); str = udev_device_get_sysattr_value(device, "dev"); if (str != NULL) - printf("attr{dev}: '%s'\n", str); - - printf("\n"); + log_info("attr{dev}: '%s'", str); } -static int test_device(struct udev *udev, const char *syspath) { +static void test_device(struct udev *udev, const char *syspath) { _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking at device: %s\n", syspath); + log_info("looking at device: %s", syspath); device = udev_device_new_from_syspath(udev, syspath); - if (device == NULL) { - printf("no device found\n"); - return -1; - } - print_device(device); - - return 0; + if (device == NULL) + log_warning_errno(errno, "udev_device_new_from_syspath: %m"); + else + print_device(device); } -static int test_device_parents(struct udev *udev, const char *syspath) { +static void test_device_parents(struct udev *udev, const char *syspath) { _cleanup_udev_device_unref_ struct udev_device *device; struct udev_device *device_parent; - printf("looking at device: %s\n", syspath); + log_info("looking at device: %s", syspath); device = udev_device_new_from_syspath(udev, syspath); if (device == NULL) - return -1; + return; - printf("looking at parents\n"); + log_info("looking at parents"); device_parent = device; do { print_device(device_parent); device_parent = udev_device_get_parent(device_parent); } while (device_parent != NULL); - printf("looking at parents again\n"); + log_info("looking at parents again"); device_parent = device; do { print_device(device_parent); device_parent = udev_device_get_parent(device_parent); } while (device_parent != NULL); - - return 0; } -static int test_device_devnum(struct udev *udev) { +static void test_device_devnum(struct udev *udev) { dev_t devnum = makedev(1, 3); - struct udev_device *device; + _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); + log_info("looking up device: %u:%u", major(devnum), minor(devnum)); device = udev_device_new_from_devnum(udev, 'c', devnum); if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; + log_warning_errno(errno, "udev_device_new_from_devnum: %m"); + else + print_device(device); } -static int test_device_subsys_name(struct udev *udev) { - struct udev_device *device; - - printf("looking up device: 'block':'sda'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "block", "sda"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'subsystem':'pci'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'drivers':'scsi:sd'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); +static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) { + _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking up device: 'module':'printk'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "module", "printk"); + log_info("looking up device: '%s:%s'", subsys, dev); + device = udev_device_new_from_subsystem_sysname(udev, subsys, dev); if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; + log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m"); + else + print_device(device); } static int test_enumerate_print_list(struct udev_enumerate *enumerate) { @@ -200,63 +170,45 @@ static int test_enumerate_print_list(struct udev_enumerate *enumerate) { device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), udev_list_entry_get_name(list_entry)); if (device != NULL) { - printf("device: '%s' (%s)\n", - udev_device_get_syspath(device), - udev_device_get_subsystem(device)); + log_info("device: '%s' (%s)", + udev_device_get_syspath(device), + udev_device_get_subsystem(device)); udev_device_unref(device); count++; } } - printf("found %i devices\n\n", count); + log_info("found %i devices", count); return count; } -static int test_monitor(struct udev *udev) { - struct udev_monitor *udev_monitor = NULL; - int fd_ep; - int fd_udev = -1; - struct epoll_event ep_udev, ep_stdin; +static void test_monitor(struct udev *udev) { + _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor; + _cleanup_close_ int fd_ep; + int fd_udev; + struct epoll_event ep_udev = { + .events = EPOLLIN, + }, ep_stdin = { + .events = EPOLLIN, + .data.fd = STDIN_FILENO, + }; fd_ep = epoll_create1(EPOLL_CLOEXEC); - if (fd_ep < 0) { - printf("error creating epoll fd: %m\n"); - goto out; - } + assert_se(fd_ep >= 0); udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); - if (udev_monitor == NULL) { - printf("no socket\n"); - goto out; - } + assert_se(udev_monitor != NULL); + fd_udev = udev_monitor_get_fd(udev_monitor); + ep_udev.data.fd = fd_udev; - if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) { - printf("filter failed\n"); - goto out; - } + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) >= 0); + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) >= 0); + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") >= 0); - if (udev_monitor_enable_receiving(udev_monitor) < 0) { - printf("bind failed\n"); - goto out; - } + assert_se(udev_monitor_enable_receiving(udev_monitor) >= 0); - memzero(&ep_udev, sizeof(struct epoll_event)); - ep_udev.events = EPOLLIN; - ep_udev.data.fd = fd_udev; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } - - memzero(&ep_stdin, sizeof(struct epoll_event)); - ep_stdin.events = EPOLLIN; - ep_stdin.data.fd = STDIN_FILENO; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } + assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) >= 0); + assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) >= 0); for (;;) { int fdcount; @@ -265,7 +217,7 @@ static int test_monitor(struct udev *udev) { int i; printf("waiting for events from udev, press ENTER to exit\n"); - fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); printf("epoll fd count: %i\n", fdcount); for (i = 0; i < fdcount; i++) { @@ -279,36 +231,29 @@ static int test_monitor(struct udev *udev) { udev_device_unref(device); } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) { printf("exiting loop\n"); - goto out; + return; } } } -out: - if (fd_ep >= 0) - close(fd_ep); - udev_monitor_unref(udev_monitor); - return 0; } -static int test_queue(struct udev *udev) { +static void test_queue(struct udev *udev) { struct udev_queue *udev_queue; + bool empty; udev_queue = udev_queue_new(udev); - if (udev_queue == NULL) - return -1; - - if (udev_queue_get_queue_is_empty(udev_queue)) - printf("queue is empty\n"); + assert_se(udev_queue); + empty = udev_queue_get_queue_is_empty(udev_queue); + log_info("queue is %s", empty ? "empty" : "not empty"); udev_queue_unref(udev_queue); - return 0; } static int test_enumerate(struct udev *udev, const char *subsystem) { struct udev_enumerate *udev_enumerate; int r; - printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem); + log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -317,7 +262,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'net' + duplicated scan + null + zero\n"); + log_info("enumerate 'net' + duplicated scan + null + zero"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -337,7 +282,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'block'\n"); + log_info("enumerate 'block'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -351,7 +296,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'not block'\n"); + log_info("enumerate 'not block'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -360,7 +305,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'pci, mem, vc'\n"); + log_info("enumerate 'pci, mem, vc'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -371,7 +316,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'subsystem'\n"); + log_info("enumerate 'subsystem'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -379,7 +324,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'property IF_FS_*=filesystem'\n"); + log_info("enumerate 'property IF_FS_*=filesystem'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -397,32 +342,32 @@ static void test_hwdb(struct udev *udev, const char *modalias) { hwdb = udev_hwdb_new(udev); udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) - printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); - printf("\n"); + log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); hwdb = udev_hwdb_unref(hwdb); assert_se(hwdb == NULL); } int main(int argc, char *argv[]) { - struct udev *udev = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; + bool arg_monitor = false; static const struct option options[] = { - { "syspath", required_argument, NULL, 'p' }, + { "syspath", required_argument, NULL, 'p' }, { "subsystem", required_argument, NULL, 's' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "monitor", no_argument, NULL, 'm' }, {} }; const char *syspath = "/devices/virtual/mem/null"; const char *subsystem = NULL; - char path[1024]; int c; udev = udev_new(); - printf("context: %p\n", udev); + log_info("context: %p", udev); if (udev == NULL) { - printf("no context\n"); + log_info("no context"); return 1; } @@ -444,14 +389,18 @@ int main(int argc, char *argv[]) { case 'h': printf("--debug --syspath= --subsystem= --help\n"); - goto out; + return EXIT_SUCCESS; case 'V': printf("%s\n", VERSION); - goto out; + return EXIT_SUCCESS; + + case 'm': + arg_monitor = true; + break; case '?': - goto out; + return EXIT_FAILURE; default: assert_not_reached("Unhandled option code."); @@ -459,14 +408,16 @@ int main(int argc, char *argv[]) { /* add sys path if needed */ - if (!startswith(syspath, "/sys")) { - xsprintf(path, "/sys/%s", syspath); - syspath = path; - } + if (!startswith(syspath, "/sys")) + syspath = strjoina("/sys/", syspath); test_device(udev, syspath); test_device_devnum(udev); - test_device_subsys_name(udev); + test_device_subsys_name(udev, "block", "sda"); + test_device_subsys_name(udev, "subsystem", "pci"); + test_device_subsys_name(udev, "drivers", "scsi:sd"); + test_device_subsys_name(udev, "module", "printk"); + test_device_parents(udev, syspath); test_enumerate(udev, subsystem); @@ -475,8 +426,8 @@ int main(int argc, char *argv[]) { test_hwdb(udev, "usb:v0D50p0011*"); - test_monitor(udev); -out: - udev_unref(udev); - return 0; + if (arg_monitor) + test_monitor(udev); + + return EXIT_SUCCESS; } diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c index 2748395ade..7b67337331 100644 --- a/src/test/test-loopback.c +++ b/src/test/test-loopback.c @@ -31,7 +31,7 @@ int main(int argc, char* argv[]) { r = loopback_setup(); if (r < 0) - fprintf(stderr, "loopback: %s\n", strerror(-r)); + log_error("loopback: %m"); - return 0; + return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c index 79ff6ae74d..bc6dd0926c 100644 --- a/src/test/test-netlink-manual.c +++ b/src/test/test-netlink-manual.c @@ -68,10 +68,10 @@ static int test_tunnel_configure(sd_netlink *rtnl) { /* skip test if module cannot be loaded */ r = load_module("ipip"); - if(r < 0) + if (r < 0) return EXIT_TEST_SKIP; - if(getuid() != 0) + if (getuid() != 0) return EXIT_TEST_SKIP; /* IPIP tunnel */ @@ -99,7 +99,7 @@ static int test_tunnel_configure(sd_netlink *rtnl) { assert_se((m = sd_netlink_message_unref(m)) == NULL); r = load_module("sit"); - if(r < 0) + if (r < 0) return EXIT_TEST_SKIP; /* sit */ diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 53a585290a..d376dd56c5 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -433,6 +433,50 @@ static void test_path_is_mount_point(void) { assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); } +static void test_file_in_same_dir(void) { + char *t; + + t = file_in_same_dir("/", "a"); + assert_se(streq(t, "/a")); + free(t); + + t = file_in_same_dir("/", "/a"); + assert_se(streq(t, "/a")); + free(t); + + t = file_in_same_dir("", "a"); + assert_se(streq(t, "a")); + free(t); + + t = file_in_same_dir("a/", "a"); + assert_se(streq(t, "a/a")); + free(t); + + t = file_in_same_dir("bar/foo", "bar"); + assert_se(streq(t, "bar/bar")); + free(t); +} + +static void test_filename_is_valid(void) { + char foo[FILENAME_MAX+2]; + int i; + + assert_se(!filename_is_valid("")); + assert_se(!filename_is_valid("/bar/foo")); + assert_se(!filename_is_valid("/")); + assert_se(!filename_is_valid(".")); + assert_se(!filename_is_valid("..")); + + for (i=0; i<FILENAME_MAX+1; i++) + foo[i] = 'a'; + foo[FILENAME_MAX+1] = '\0'; + + assert_se(!filename_is_valid(foo)); + + assert_se(filename_is_valid("foo_bar-333")); + assert_se(filename_is_valid("o.o")); +} + int main(int argc, char **argv) { test_path(); test_find_binary(argv[0]); @@ -444,6 +488,8 @@ int main(int argc, char **argv) { test_path_startswith(); test_prefix_root(); test_path_is_mount_point(); + test_file_in_same_dir(); + test_filename_is_valid(); return 0; } diff --git a/src/test/test-path.c b/src/test/test-path.c index 7a3b145414..1e704a03dc 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -93,7 +93,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con ts = now(CLOCK_MONOTONIC); /* We process events until the service related to the path has been successfully started */ - while(service->result != SERVICE_SUCCESS || service->state != SERVICE_START) { + while (service->result != SERVICE_SUCCESS || service->state != SERVICE_START) { usec_t n; int r; diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c new file mode 100644 index 0000000000..a7a8f621a2 --- /dev/null +++ b/src/test/test-proc-cmdline.c @@ -0,0 +1,52 @@ +/*** + 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 "log.h" +#include "macro.h" +#include "proc-cmdline.h" +#include "special.h" +#include "string-util.h" + +static int parse_item(const char *key, const char *value) { + assert_se(key); + + log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); + return 0; +} + +static void test_parse_proc_cmdline(void) { + assert_se(parse_proc_cmdline(parse_item) >= 0); +} + +static void test_runlevel_to_target(void) { + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); +} + +int main(void) { + log_parse_environment(); + log_open(); + + test_parse_proc_cmdline(); + test_runlevel_to_target(); + + return 0; +} diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 48be5a3a87..4616314200 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -18,12 +18,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <sys/personality.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include "alloc-util.h" +#include "architecture.h" #include "log.h" #include "macro.h" #include "process-util.h" @@ -128,6 +130,29 @@ static void test_pid_is_alive(void) { assert_se(!pid_is_alive(-1)); } +static void test_personality(void) { + + assert_se(personality_to_string(PER_LINUX)); + assert_se(!personality_to_string(PERSONALITY_INVALID)); + + assert_se(streq(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()))); + + assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX); + assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX); + +#ifdef __x86_64__ + assert_se(streq_ptr(personality_to_string(PER_LINUX), "x86-64")); + assert_se(streq_ptr(personality_to_string(PER_LINUX32), "x86")); + + assert_se(personality_from_string("x86-64") == PER_LINUX); + assert_se(personality_from_string("x86") == PER_LINUX32); + assert_se(personality_from_string("ia64") == PERSONALITY_INVALID); + assert_se(personality_from_string(NULL) == PERSONALITY_INVALID); + + assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32); +#endif +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -135,6 +160,7 @@ int main(int argc, char *argv[]) { test_get_process_comm(); test_pid_is_unwaited(); test_pid_is_alive(); + test_personality(); return 0; } diff --git a/src/test/test-selinux.c b/src/test/test-selinux.c new file mode 100644 index 0000000000..7545ad3764 --- /dev/null +++ b/src/test/test-selinux.c @@ -0,0 +1,122 @@ +/*** + 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/>. +***/ + +#include <sys/stat.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "log.h" +#include "selinux-util.h" +#include "string-util.h" +#include "time-util.h" +#include "util.h" + +static void test_testing(void) { + bool b; + + log_info("============ %s ==========", __func__); + + b = mac_selinux_use(); + log_info("mac_selinux_use → %s", yes_no(b)); + + b = mac_selinux_have(); + log_info("mac_selinux_have → %s", yes_no(b)); + + mac_selinux_retest(); + + b = mac_selinux_use(); + log_info("mac_selinux_use → %s", yes_no(b)); + + b = mac_selinux_have(); + log_info("mac_selinux_have → %s", yes_no(b)); +} + +static void test_loading(void) { + usec_t n1, n2; + int r; + + log_info("============ %s ==========", __func__); + + n1 = now(CLOCK_MONOTONIC); + r = mac_selinux_init(); + n2 = now(CLOCK_MONOTONIC); + log_info_errno(r, "mac_selinux_init → %d (%m) %.2fs", r, (n2 - n1)/1e6); +} + +static void test_cleanup(void) { + usec_t n1, n2; + + log_info("============ %s ==========", __func__); + + n1 = now(CLOCK_MONOTONIC); + mac_selinux_finish(); + n2 = now(CLOCK_MONOTONIC); + log_info("mac_selinux_finish → %.2fs", (n2 - n1)/1e6); +} + +static void test_misc(const char* fname) { + _cleanup_(mac_selinux_freep) char *label = NULL, *label2 = NULL, *label3 = NULL; + int r; + _cleanup_close_ int fd = -1; + + log_info("============ %s ==========", __func__); + + r = mac_selinux_get_our_label(&label); + log_info_errno(r, "mac_selinux_get_our_label → %d (%m), \"%s\"", + r, strnull(label)); + + r = mac_selinux_get_create_label_from_exe(fname, &label2); + log_info_errno(r, "mac_selinux_create_label_from_exe → %d (%m), \"%s\"", + r, strnull(label2)); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + assert_se(fd >= 0); + + r = mac_selinux_get_child_mls_label(fd, fname, label2, &label3); + log_info_errno(r, "mac_selinux_get_child_mls_label → %d (%m), \"%s\"", + r, strnull(label3)); +} + +static void test_create_file_prepare(const char* fname) { + int r; + + log_info("============ %s ==========", __func__); + + r = mac_selinux_create_file_prepare(fname, S_IRWXU); + log_info_errno(r, "mac_selinux_create_file_prepare → %d (%m)", r); + + mac_selinux_create_file_clear(); +} + +int main(int argc, char **argv) { + const char *path = SYSTEMD_BINARY_PATH; + if (argc >= 2) + path = argv[1]; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + test_testing(); + test_loading(); + test_misc(path); + test_create_file_prepare(path); + test_cleanup(); + + return 0; +} diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c index 3083501ce9..671eb869cb 100644 --- a/src/test/test-signal-util.c +++ b/src/test/test-signal-util.c @@ -17,6 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <signal.h> +#include <unistd.h> + +#include "macro.h" #include "signal-util.h" static void test_block_signals(void) { @@ -44,6 +48,20 @@ static void test_block_signals(void) { assert_se(sigismember(&ss, SIGVTALRM) == 0); } +static void test_ignore_signals(void) { + assert_se(ignore_signals(SIGINT, -1) >= 0); + assert_se(kill(getpid(), SIGINT) >= 0); + assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); + assert_se(kill(getpid(), SIGUSR1) >= 0); + assert_se(kill(getpid(), SIGUSR2) >= 0); + assert_se(kill(getpid(), SIGTERM) >= 0); + assert_se(kill(getpid(), SIGPIPE) >= 0); + assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); +} + int main(int argc, char *argv[]) { test_block_signals(); + test_ignore_signals(); + + return 0; } diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c index caae911f30..b74b7ad2dd 100644 --- a/src/test/test-siphash24.c +++ b/src/test/test-siphash24.c @@ -22,9 +22,9 @@ #define ITERATIONS 10000000ULL -static int do_test(const uint8_t *in, size_t len, const uint8_t *key) { +static void do_test(const uint8_t *in, size_t len, const uint8_t *key) { struct siphash state = {}; - uint64_t out = 0; + uint64_t out; unsigned i, j; out = siphash24(in, len, key); @@ -60,7 +60,46 @@ static int do_test(const uint8_t *in, size_t len, const uint8_t *key) { assert_se(out == 0xa129ca6149be45e5); } } - return 0; +} + +static void test_short_hashes(void) { + const uint8_t one[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + const uint8_t key[16] = { 0x22, 0x24, 0x41, 0x22, 0x55, 0x77, 0x88, 0x07, + 0x23, 0x09, 0x23, 0x14, 0x0c, 0x33, 0x0e, 0x0f}; + uint8_t two[sizeof one] = {}; + + struct siphash state1 = {}, state2 = {}; + unsigned i, j; + + siphash24_init(&state1, key); + siphash24_init(&state2, key); + + /* hashing 1, 2, 3, 4, 5, ..., 16 bytes, with the byte after the buffer different */ + for (i = 1; i <= sizeof one; i++) { + siphash24_compress(one, i, &state1); + + two[i-1] = one[i-1]; + siphash24_compress(two, i, &state2); + + assert_se(memcmp(&state1, &state2, sizeof state1) == 0); + } + + /* hashing n and 1, n and 2, n and 3, ..., n-1 and 1, n-2 and 2, ... */ + for (i = sizeof one; i > 0; i--) { + zero(two); + + for (j = 1; j <= sizeof one; j++) { + siphash24_compress(one, i, &state1); + siphash24_compress(one, j, &state1); + + siphash24_compress(one, i, &state2); + two[j-1] = one[j-1]; + siphash24_compress(two, j, &state2); + + assert_se(memcmp(&state1, &state2, sizeof state1) == 0); + } + } } /* see https://131002.net/siphash/siphash.pdf, Appendix A */ @@ -80,4 +119,6 @@ int main(int argc, char *argv[]) { do_test(in_buf + 2, sizeof(in), key); memcpy(in_buf + 4, in, sizeof(in)); do_test(in_buf + 4, sizeof(in), key); + + test_short_hashes(); } diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c new file mode 100644 index 0000000000..8f99a13772 --- /dev/null +++ b/src/test/test-sizeof.c @@ -0,0 +1,53 @@ +/*** + 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/>. +***/ + +#include "log.h" +#include "time-util.h" + +/* Print information about various types. Useful when diagnosing + * gcc diagnostics on an unfamiliar architecture. */ + +#pragma GCC diagnostic ignored "-Wtype-limits" + +#define info(t) \ + log_info("%s → %zu bits%s", STRINGIFY(t), \ + sizeof(t)*CHAR_BIT, \ + strstr(STRINGIFY(t), "signed") ? "" : \ + ((t)-1 < (t)0 ? ", signed" : ", unsigned")); + +int main(void) { + info(char); + info(signed char); + info(unsigned char); + info(short unsigned); + info(unsigned); + info(long unsigned); + info(long long unsigned); + + info(float); + info(double); + info(long double); + + info(size_t); + info(ssize_t); + info(time_t); + info(usec_t); + + return 0; +} diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c new file mode 100644 index 0000000000..a10227f823 --- /dev/null +++ b/src/test/test-stat-util.c @@ -0,0 +1,68 @@ +/*** + 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 <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" +#include "stat-util.h" + +static void test_files_same(void) { + _cleanup_close_ int fd = -1; + char name[] = "/tmp/test-files_same.XXXXXX"; + char name_alias[] = "/tmp/test-files_same.alias"; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(symlink(name, name_alias) >= 0); + + assert_se(files_same(name, name)); + assert_se(files_same(name, name_alias)); + + unlink(name); + unlink(name_alias); +} + +static void test_is_symlink(void) { + char name[] = "/tmp/test-is_symlink.XXXXXX"; + char name_link[] = "/tmp/test-is_symlink.link"; + _cleanup_close_ int fd = -1; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(symlink(name, name_link) >= 0); + + assert_se(is_symlink(name) == 0); + assert_se(is_symlink(name_link) == 1); + assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); + + + unlink(name); + unlink(name_link); +} + +int main(int argc, char *argv[]) { + test_files_same(); + test_is_symlink(); + + return 0; +} diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 9b48e95998..d0f84d70bc 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -17,7 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "macro.h" #include "string-util.h" +#include "strv.h" static void test_string_erase(void) { char *x; @@ -97,9 +100,271 @@ static void test_ascii_strcasecmp_nn(void) { assert_se(ascii_strcasecmp_nn("BBbb", 4, "aaaa", 4) > 0); } +static void test_streq_ptr(void) { + assert_se(streq_ptr(NULL, NULL)); + assert_se(!streq_ptr("abc", "cdef")); +} + +static void test_strstrip(void) { + char *r; + char input[] = " hello, waldo. "; + + r = strstrip(input); + assert_se(streq(r, "hello, waldo.")); +} + +static void test_strextend(void) { + _cleanup_free_ char *str = strdup("0123"); + strextend(&str, "456", "78", "9", NULL); + assert_se(streq(str, "0123456789")); +} + +static void test_strrep(void) { + _cleanup_free_ char *one, *three, *zero; + one = strrep("waldo", 1); + three = strrep("waldo", 3); + zero = strrep("waldo", 0); + + assert_se(streq(one, "waldo")); + assert_se(streq(three, "waldowaldowaldo")); + assert_se(streq(zero, "")); +} + + +static void test_strappend(void) { + _cleanup_free_ char *t1, *t2, *t3, *t4; + + t1 = strappend(NULL, NULL); + assert_se(streq(t1, "")); + + t2 = strappend(NULL, "suf"); + assert_se(streq(t2, "suf")); + + t3 = strappend("pre", NULL); + assert_se(streq(t3, "pre")); + + t4 = strappend("pre", "suf"); + assert_se(streq(t4, "presuf")); +} + +static void test_string_has_cc(void) { + assert_se(string_has_cc("abc\1", NULL)); + assert_se(string_has_cc("abc\x7f", NULL)); + assert_se(string_has_cc("abc\x7f", NULL)); + assert_se(string_has_cc("abc\t\x7f", "\t")); + assert_se(string_has_cc("abc\t\x7f", "\t")); + assert_se(string_has_cc("\x7f", "\t")); + assert_se(string_has_cc("\x7f", "\t\a")); + + assert_se(!string_has_cc("abc\t\t", "\t")); + assert_se(!string_has_cc("abc\t\t\a", "\t\a")); + assert_se(!string_has_cc("a\ab\tc", "\t\a")); +} + +static void test_ascii_strlower(void) { + char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK"; + assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk")); +} + +static void test_strshorten(void) { + char s[] = "foobar"; + + assert_se(strlen(strshorten(s, 6)) == 6); + assert_se(strlen(strshorten(s, 12)) == 6); + assert_se(strlen(strshorten(s, 2)) == 2); + assert_se(strlen(strshorten(s, 0)) == 0); +} + +static void test_strjoina(void) { + char *actual; + + actual = strjoina("", "foo", "bar"); + assert_se(streq(actual, "foobar")); + + actual = strjoina("foo", "bar", "baz"); + assert_se(streq(actual, "foobarbaz")); + + actual = strjoina("foo", "", "bar", "baz"); + assert_se(streq(actual, "foobarbaz")); + + actual = strjoina("foo"); + assert_se(streq(actual, "foo")); + + actual = strjoina(NULL); + assert_se(streq(actual, "")); + + actual = strjoina(NULL, "foo"); + assert_se(streq(actual, "")); + + actual = strjoina("foo", NULL, "bar"); + assert_se(streq(actual, "foo")); +} + +static void test_strcmp_ptr(void) { + assert_se(strcmp_ptr(NULL, NULL) == 0); + assert_se(strcmp_ptr("", NULL) > 0); + assert_se(strcmp_ptr("foo", NULL) > 0); + assert_se(strcmp_ptr(NULL, "") < 0); + assert_se(strcmp_ptr(NULL, "bar") < 0); + assert_se(strcmp_ptr("foo", "bar") > 0); + assert_se(strcmp_ptr("bar", "baz") < 0); + assert_se(strcmp_ptr("foo", "foo") == 0); + assert_se(strcmp_ptr("", "") == 0); +} + +static void test_foreach_word(void) { + const char *word, *state; + size_t l; + int i = 0; + const char test[] = "test abc d\te f "; + const char * const expected[] = { + "test", + "abc", + "d", + "e", + "f", + "", + NULL + }; + + FOREACH_WORD(word, l, test, state) + assert_se(strneq(expected[i++], word, l)); +} + +static void check(const char *test, char** expected, bool trailing) { + const char *word, *state; + size_t l; + int i = 0; + + printf("<<<%s>>>\n", test); + FOREACH_WORD_QUOTED(word, l, test, state) { + _cleanup_free_ char *t = NULL; + + assert_se(t = strndup(word, l)); + assert_se(strneq(expected[i++], word, l)); + printf("<%s>\n", t); + } + printf("<<<%s>>>\n", state); + assert_se(expected[i] == NULL); + assert_se(isempty(state) == !trailing); +} + +static void test_foreach_word_quoted(void) { + check("test a b c 'd' e '' '' hhh '' '' \"a b c\"", + STRV_MAKE("test", + "a", + "b", + "c", + "d", + "e", + "", + "", + "hhh", + "", + "", + "a b c"), + false); + + check("test \"xxx", + STRV_MAKE("test"), + true); + + check("test\\", + STRV_MAKE_EMPTY, + true); +} + +static void test_endswith(void) { + assert_se(endswith("foobar", "bar")); + assert_se(endswith("foobar", "")); + assert_se(endswith("foobar", "foobar")); + assert_se(endswith("", "")); + + assert_se(!endswith("foobar", "foo")); + assert_se(!endswith("foobar", "foobarfoofoo")); +} + +static void test_endswith_no_case(void) { + assert_se(endswith_no_case("fooBAR", "bar")); + assert_se(endswith_no_case("foobar", "")); + assert_se(endswith_no_case("foobar", "FOOBAR")); + assert_se(endswith_no_case("", "")); + + assert_se(!endswith_no_case("foobar", "FOO")); + assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO")); +} + +static void test_delete_chars(void) { + char *r; + char input[] = " hello, waldo. abc"; + + r = delete_chars(input, WHITESPACE); + assert_se(streq(r, "hello,waldo.abc")); +} + +static void test_in_charset(void) { + assert_se(in_charset("dddaaabbbcccc", "abcd")); + assert_se(!in_charset("dddaaabbbcccc", "abc f")); +} + +static void test_split_pair(void) { + _cleanup_free_ char *a = NULL, *b = NULL; + + assert_se(split_pair("", "", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); + assert_se(split_pair("", "=", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); + assert_se(streq(a, "foo")); + assert_se(streq(b, "bar")); + free(a); + free(b); + assert_se(split_pair("==", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "")); + free(a); + free(b); + + assert_se(split_pair("===", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "=")); +} + +static void test_first_word(void) { + assert_se(first_word("Hello", "")); + assert_se(first_word("Hello", "Hello")); + assert_se(first_word("Hello world", "Hello")); + assert_se(first_word("Hello\tworld", "Hello")); + assert_se(first_word("Hello\nworld", "Hello")); + assert_se(first_word("Hello\rworld", "Hello")); + assert_se(first_word("Hello ", "Hello")); + + assert_se(!first_word("Hello", "Hellooo")); + assert_se(!first_word("Hello", "xxxxx")); + assert_se(!first_word("Hellooo", "Hello")); +} + int main(int argc, char *argv[]) { test_string_erase(); test_ascii_strcasecmp_n(); test_ascii_strcasecmp_nn(); + test_streq_ptr(); + test_strstrip(); + test_strextend(); + test_strrep(); + test_strappend(); + test_string_has_cc(); + test_ascii_strlower(); + test_strshorten(); + test_strjoina(); + test_strcmp_ptr(); + test_foreach_word(); + test_foreach_word_quoted(); + test_endswith(); + test_endswith_no_case(); + test_delete_chars(); + test_in_charset(); + test_split_pair(); + test_first_word(); + return 0; } diff --git a/src/test/test-strv.c b/src/test/test-strv.c index ef451c6abf..fea1f848cd 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -660,6 +660,25 @@ static void test_strv_make_nulstr(void) { test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux")); } +static void test_foreach_string(void) { + const char * const t[] = { + "foo", + "bar", + "waldo", + NULL + }; + const char *x; + unsigned i = 0; + + FOREACH_STRING(x, "foo", "bar", "waldo") + assert_se(streq_ptr(t[i++], x)); + + assert_se(i == 3); + + FOREACH_STRING(x, "zzz") + assert_se(streq(x, "zzz")); +} + int main(int argc, char *argv[]) { test_specifier_printf(); test_strv_foreach(); @@ -724,5 +743,7 @@ int main(int argc, char *argv[]) { test_strv_extend_n(); test_strv_make_nulstr(); + test_foreach_string(); + return 0; } diff --git a/src/test/test-time.c b/src/test/test-time.c index 9062c3f3c1..ee7d55c5ab 100644 --- a/src/test/test-time.c +++ b/src/test/test-time.c @@ -220,7 +220,7 @@ int main(int argc, char *argv[]) { /* Ensure TIME_T_MAX works correctly */ x = (uintmax_t) TIME_T_MAX; - x ++; + x++; assert((time_t) x < 0); return 0; diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 9cc64f7c68..d01789fe08 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; log_debug("version %s", VERSION); - mac_selinux_init("/dev"); + mac_selinux_init(); action = argv[1]; if (action == NULL) { diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index b0c343590d..cc6c61ba63 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -606,7 +606,7 @@ static void test_install_printf(void) { } else assert_se(t == NULL); \ strcpy(i.name, d1); \ strcpy(i.path, d2); \ - } while(false) + } while (false) expect(i, "%n", "name.service"); expect(i, "%N", "name"); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index 42c6a8d5e2..8d1ec19f17 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -37,6 +37,30 @@ static void test_gid_to_name_one(gid_t gid, const char *name) { assert_se(streq_ptr(t, name)); } +static void test_parse_uid(void) { + int r; + uid_t uid; + + r = parse_uid("100", &uid); + assert_se(r == 0); + assert_se(uid == 100); + + r = parse_uid("65535", &uid); + assert_se(r == -ENXIO); + + r = parse_uid("asdsdas", &uid); + assert_se(r == -EINVAL); +} + +static void test_uid_ptr(void) { + + assert_se(UID_TO_PTR(0) != NULL); + assert_se(UID_TO_PTR(1000) != NULL); + + assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0); + assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); +} + int main(int argc, char*argv[]) { test_uid_to_name_one(0, "root"); @@ -48,5 +72,8 @@ int main(int argc, char*argv[]) { test_gid_to_name_one(0xFFFF, "65535"); test_gid_to_name_one(0xFFFFFFFF, "4294967295"); + test_parse_uid(); + test_uid_ptr(); + return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 9a8a265790..05cb1eae76 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -19,47 +19,16 @@ ***/ #include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <string.h> -#include <sys/types.h> #include <sys/wait.h> -#include <sys/xattr.h> #include <unistd.h> -#include "alloc-util.h" -#include "conf-parser.h" -#include "cpu-set-util.h" #include "def.h" -#include "escape.h" -#include "fd-util.h" #include "fileio.h" #include "fs-util.h" -#include "fstab-util.h" -#include "glob-util.h" -#include "hexdecoct.h" -#include "io-util.h" -#include "mkdir.h" -#include "parse-util.h" -#include "path-util.h" -#include "proc-cmdline.h" -#include "process-util.h" #include "rm-rf.h" -#include "signal-util.h" -#include "special.h" -#include "stat-util.h" #include "string-util.h" -#include "strv.h" -#include "user-util.h" #include "util.h" -#include "virt.h" -#include "web-util.h" -#include "xattr-util.h" - -static void test_streq_ptr(void) { - assert_se(streq_ptr(NULL, NULL)); - assert_se(!streq_ptr("abc", "cdef")); -} static void test_align_power2(void) { unsigned long i, p2; @@ -151,19 +120,6 @@ static void test_container_of(void) { v1) == &myval); } -static void test_alloca(void) { - static const uint8_t zero[997] = { }; - char *t; - - t = alloca_align(17, 512); - assert_se(!((uintptr_t)t & 0xff)); - memzero(t, 17); - - t = alloca0_align(997, 1024); - assert_se(!((uintptr_t)t & 0x1ff)); - assert_se(!memcmp(t, zero, 997)); -} - static void test_div_round_up(void) { int div; @@ -197,544 +153,6 @@ static void test_div_round_up(void) { assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U); } -static void test_first_word(void) { - assert_se(first_word("Hello", "")); - assert_se(first_word("Hello", "Hello")); - assert_se(first_word("Hello world", "Hello")); - assert_se(first_word("Hello\tworld", "Hello")); - assert_se(first_word("Hello\nworld", "Hello")); - assert_se(first_word("Hello\rworld", "Hello")); - assert_se(first_word("Hello ", "Hello")); - - assert_se(!first_word("Hello", "Hellooo")); - assert_se(!first_word("Hello", "xxxxx")); - assert_se(!first_word("Hellooo", "Hello")); -} - -static void test_close_many(void) { - int fds[3]; - char name0[] = "/tmp/test-close-many.XXXXXX"; - char name1[] = "/tmp/test-close-many.XXXXXX"; - char name2[] = "/tmp/test-close-many.XXXXXX"; - - fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC); - fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC); - fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC); - - close_many(fds, 2); - - assert_se(fcntl(fds[0], F_GETFD) == -1); - assert_se(fcntl(fds[1], F_GETFD) == -1); - assert_se(fcntl(fds[2], F_GETFD) >= 0); - - safe_close(fds[2]); - - unlink(name0); - unlink(name1); - unlink(name2); -} - -static void test_parse_uid(void) { - int r; - uid_t uid; - - r = parse_uid("100", &uid); - assert_se(r == 0); - assert_se(uid == 100); - - r = parse_uid("65535", &uid); - assert_se(r == -ENXIO); - - r = parse_uid("asdsdas", &uid); - assert_se(r == -EINVAL); -} - -static void test_strappend(void) { - _cleanup_free_ char *t1, *t2, *t3, *t4; - - t1 = strappend(NULL, NULL); - assert_se(streq(t1, "")); - - t2 = strappend(NULL, "suf"); - assert_se(streq(t2, "suf")); - - t3 = strappend("pre", NULL); - assert_se(streq(t3, "pre")); - - t4 = strappend("pre", "suf"); - assert_se(streq(t4, "presuf")); -} - -static void test_strstrip(void) { - char *r; - char input[] = " hello, waldo. "; - - r = strstrip(input); - assert_se(streq(r, "hello, waldo.")); -} - -static void test_delete_chars(void) { - char *r; - char input[] = " hello, waldo. abc"; - - r = delete_chars(input, WHITESPACE); - assert_se(streq(r, "hello,waldo.abc")); -} - -static void test_in_charset(void) { - assert_se(in_charset("dddaaabbbcccc", "abcd")); - assert_se(!in_charset("dddaaabbbcccc", "abc f")); -} - -static void test_hexchar(void) { - assert_se(hexchar(0xa) == 'a'); - assert_se(hexchar(0x0) == '0'); -} - -static void test_unhexchar(void) { - assert_se(unhexchar('a') == 0xA); - assert_se(unhexchar('A') == 0xA); - assert_se(unhexchar('0') == 0x0); -} - -static void test_base32hexchar(void) { - assert_se(base32hexchar(0) == '0'); - assert_se(base32hexchar(9) == '9'); - assert_se(base32hexchar(10) == 'A'); - assert_se(base32hexchar(31) == 'V'); -} - -static void test_unbase32hexchar(void) { - assert_se(unbase32hexchar('0') == 0); - assert_se(unbase32hexchar('9') == 9); - assert_se(unbase32hexchar('A') == 10); - assert_se(unbase32hexchar('V') == 31); - assert_se(unbase32hexchar('=') == -EINVAL); -} - -static void test_base64char(void) { - assert_se(base64char(0) == 'A'); - assert_se(base64char(26) == 'a'); - assert_se(base64char(63) == '/'); -} - -static void test_unbase64char(void) { - assert_se(unbase64char('A') == 0); - assert_se(unbase64char('Z') == 25); - assert_se(unbase64char('a') == 26); - assert_se(unbase64char('z') == 51); - assert_se(unbase64char('0') == 52); - assert_se(unbase64char('9') == 61); - assert_se(unbase64char('+') == 62); - assert_se(unbase64char('/') == 63); - assert_se(unbase64char('=') == -EINVAL); -} - -static void test_octchar(void) { - assert_se(octchar(00) == '0'); - assert_se(octchar(07) == '7'); -} - -static void test_unoctchar(void) { - assert_se(unoctchar('0') == 00); - assert_se(unoctchar('7') == 07); -} - -static void test_decchar(void) { - assert_se(decchar(0) == '0'); - assert_se(decchar(9) == '9'); -} - -static void test_undecchar(void) { - assert_se(undecchar('0') == 0); - assert_se(undecchar('9') == 9); -} - -static void test_unhexmem(void) { - const char *hex = "efa214921"; - const char *hex_invalid = "efa214921o"; - _cleanup_free_ char *hex2 = NULL; - _cleanup_free_ void *mem = NULL; - size_t len; - - assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); - assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); - assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); - - assert_se((hex2 = hexmem(mem, len))); - - free(mem); - - assert_se(memcmp(hex, hex2, strlen(hex)) == 0); - - free(hex2); - - assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); - assert_se((hex2 = hexmem(mem, len))); - assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); -} - -/* https://tools.ietf.org/html/rfc4648#section-10 */ -static void test_base32hexmem(void) { - char *b32; - - b32 = base32hexmem("", strlen(""), true); - assert_se(b32); - assert_se(streq(b32, "")); - free(b32); - - b32 = base32hexmem("f", strlen("f"), true); - assert_se(b32); - assert_se(streq(b32, "CO======")); - free(b32); - - b32 = base32hexmem("fo", strlen("fo"), true); - assert_se(b32); - assert_se(streq(b32, "CPNG====")); - free(b32); - - b32 = base32hexmem("foo", strlen("foo"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMU===")); - free(b32); - - b32 = base32hexmem("foob", strlen("foob"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOG=")); - free(b32); - - b32 = base32hexmem("fooba", strlen("fooba"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1")); - free(b32); - - b32 = base32hexmem("foobar", strlen("foobar"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1E8======")); - free(b32); - - b32 = base32hexmem("", strlen(""), false); - assert_se(b32); - assert_se(streq(b32, "")); - free(b32); - - b32 = base32hexmem("f", strlen("f"), false); - assert_se(b32); - assert_se(streq(b32, "CO")); - free(b32); - - b32 = base32hexmem("fo", strlen("fo"), false); - assert_se(b32); - assert_se(streq(b32, "CPNG")); - free(b32); - - b32 = base32hexmem("foo", strlen("foo"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMU")); - free(b32); - - b32 = base32hexmem("foob", strlen("foob"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOG")); - free(b32); - - b32 = base32hexmem("fooba", strlen("fooba"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1")); - free(b32); - - b32 = base32hexmem("foobar", strlen("foobar"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1E8")); - free(b32); -} - -static void test_unbase32hexmem(void) { - void *mem; - size_t len; - - assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL); - - assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - - assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL); -} - -/* https://tools.ietf.org/html/rfc4648#section-10 */ -static void test_base64mem(void) { - char *b64; - - assert_se(base64mem("", strlen(""), &b64) == 0); - assert_se(streq(b64, "")); - free(b64); - - assert_se(base64mem("f", strlen("f"), &b64) == 4); - assert_se(streq(b64, "Zg==")); - free(b64); - - assert_se(base64mem("fo", strlen("fo"), &b64) == 4); - assert_se(streq(b64, "Zm8=")); - free(b64); - - assert_se(base64mem("foo", strlen("foo"), &b64) == 4); - assert_se(streq(b64, "Zm9v")); - free(b64); - - assert_se(base64mem("foob", strlen("foob"), &b64) == 8); - assert_se(streq(b64, "Zm9vYg==")); - free(b64); - - assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8); - assert_se(streq(b64, "Zm9vYmE=")); - free(b64); - - assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8); - assert_se(streq(b64, "Zm9vYmFy")); - free(b64); -} - -static void test_unbase64mem(void) { - void *mem; - size_t len; - - assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); - assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); - assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); - assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); -} - -static void test_cescape(void) { - _cleanup_free_ char *escaped; - - assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); - assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); -} - -static void test_cunescape(void) { - _cleanup_free_ char *unescaped; - - assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0); - assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00")); - unescaped = mfree(unescaped); - - /* incomplete sequences */ - assert_se(cunescape("\\x0", 0, &unescaped) < 0); - assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\x0")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\x", 0, &unescaped) < 0); - assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\x")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\", 0, &unescaped) < 0); - assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\11", 0, &unescaped) < 0); - assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\11")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\1", 0, &unescaped) < 0); - assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\1")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\u0000", 0, &unescaped) < 0); - assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "ßßΠA")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\073", 0, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, ";")); -} - -static void test_foreach_word(void) { - const char *word, *state; - size_t l; - int i = 0; - const char test[] = "test abc d\te f "; - const char * const expected[] = { - "test", - "abc", - "d", - "e", - "f", - "", - NULL - }; - - FOREACH_WORD(word, l, test, state) - assert_se(strneq(expected[i++], word, l)); -} - -static void check(const char *test, char** expected, bool trailing) { - const char *word, *state; - size_t l; - int i = 0; - - printf("<<<%s>>>\n", test); - FOREACH_WORD_QUOTED(word, l, test, state) { - _cleanup_free_ char *t = NULL; - - assert_se(t = strndup(word, l)); - assert_se(strneq(expected[i++], word, l)); - printf("<%s>\n", t); - } - printf("<<<%s>>>\n", state); - assert_se(expected[i] == NULL); - assert_se(isempty(state) == !trailing); -} - -static void test_foreach_word_quoted(void) { - check("test a b c 'd' e '' '' hhh '' '' \"a b c\"", - STRV_MAKE("test", - "a", - "b", - "c", - "d", - "e", - "", - "", - "hhh", - "", - "", - "a b c"), - false); - - check("test \"xxx", - STRV_MAKE("test"), - true); - - check("test\\", - STRV_MAKE_EMPTY, - true); -} - -static void test_memdup_multiply(void) { - int org[] = {1, 2, 3}; - int *dup; - - dup = (int*)memdup_multiply(org, sizeof(int), 3); - - assert_se(dup); - assert_se(dup[0] == 1); - assert_se(dup[1] == 2); - assert_se(dup[2] == 3); - free(dup); -} - static void test_u64log2(void) { assert_se(u64log2(0) == 0); assert_se(u64log2(8) == 3); @@ -754,210 +172,6 @@ static void test_protect_errno(void) { assert_se(errno == 12); } -static void test_parse_cpu_set(void) { - cpu_set_t *c = NULL; - int ncpus; - int cpu; - - /* Simple range (from CPUAffinity example) */ - ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); - c = mfree(c); - - /* A more interesting range */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Quoted strings */ - ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Use commas as separators */ - ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Commas with spaces (and trailing comma, space) */ - ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 8; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Ranges */ - ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Ranges with trailing comma, space */ - ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Negative range (returns empty cpu_set) */ - ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); - c = mfree(c); - - /* Overlapping ranges */ - ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); - for (cpu = 0; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Mix ranges and individual CPUs */ - ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); - assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 4; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Garbage */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); - - /* Range with garbage */ - ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); - - /* Empty string */ - c = NULL; - ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus == 0); /* empty string returns 0 */ - assert_se(!c); - - /* Runnaway quoted string */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); -} - -static void test_config_parse_iec_uint64(void) { - uint64_t offset = 0; - assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); - assert_se(offset == 4 * 1024 * 1024); - - assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); -} - -static void test_strextend(void) { - _cleanup_free_ char *str = strdup("0123"); - strextend(&str, "456", "78", "9", NULL); - assert_se(streq(str, "0123456789")); -} - -static void test_strrep(void) { - _cleanup_free_ char *one, *three, *zero; - one = strrep("waldo", 1); - three = strrep("waldo", 3); - zero = strrep("waldo", 0); - - assert_se(streq(one, "waldo")); - assert_se(streq(three, "waldowaldowaldo")); - assert_se(streq(zero, "")); -} - -static void test_split_pair(void) { - _cleanup_free_ char *a = NULL, *b = NULL; - - assert_se(split_pair("", "", &a, &b) == -EINVAL); - assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); - assert_se(split_pair("", "=", &a, &b) == -EINVAL); - assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); - assert_se(streq(a, "foo")); - assert_se(streq(b, "bar")); - free(a); - free(b); - assert_se(split_pair("==", "==", &a, &b) >= 0); - assert_se(streq(a, "")); - assert_se(streq(b, "")); - free(a); - free(b); - - assert_se(split_pair("===", "==", &a, &b) >= 0); - assert_se(streq(a, "")); - assert_se(streq(b, "=")); -} - -static void test_fstab_node_to_udev_node(void) { - char *n; - - n = fstab_node_to_udev_node("LABEL=applé/jack"); - puts(n); - assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); - free(n); - - n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); - puts(n); - assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); - free(n); - - n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); - puts(n); - assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); - free(n); - - n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); - puts(n); - assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); - free(n); - - n = fstab_node_to_udev_node("PONIES=awesome"); - puts(n); - assert_se(streq(n, "PONIES=awesome")); - free(n); - - n = fstab_node_to_udev_node("/dev/xda1"); - puts(n); - assert_se(streq(n, "/dev/xda1")); - free(n); -} - -static void test_get_files_in_directory(void) { - _cleanup_strv_free_ char **l = NULL, **t = NULL; - - assert_se(get_files_in_directory("/tmp", &l) >= 0); - assert_se(get_files_in_directory(".", &t) >= 0); - assert_se(get_files_in_directory(".", NULL) >= 0); -} - static void test_in_set(void) { assert_se(IN_SET(1, 1)); assert_se(IN_SET(1, 1, 2, 3, 4)); @@ -968,50 +182,6 @@ static void test_in_set(void) { assert_se(!IN_SET(0, 1, 2, 3, 4)); } -static void test_writing_tmpfile(void) { - char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX"; - _cleanup_free_ char *contents = NULL; - size_t size; - int fd, r; - struct iovec iov[3]; - - IOVEC_SET_STRING(iov[0], "abc\n"); - IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n"); - IOVEC_SET_STRING(iov[2], ""); - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - printf("tmpfile: %s", name); - - r = writev(fd, iov, 3); - assert_se(r >= 0); - - r = read_full_file(name, &contents, &size); - assert_se(r == 0); - printf("contents: %s", contents); - assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n")); - - unlink(name); -} - -static void test_hexdump(void) { - uint8_t data[146]; - unsigned i; - - hexdump(stdout, NULL, 0); - hexdump(stdout, "", 0); - hexdump(stdout, "", 1); - hexdump(stdout, "x", 1); - hexdump(stdout, "x", 2); - hexdump(stdout, "foobar", 7); - hexdump(stdout, "f\nobar", 7); - hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); - - for (i = 0; i < ELEMENTSOF(data); i++) - data[i] = i*2; - - hexdump(stdout, data, sizeof(data)); -} - static void test_log2i(void) { assert_se(log2i(1) == 0); assert_se(log2i(2) == 1); @@ -1023,341 +193,6 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } -static void test_foreach_string(void) { - const char * const t[] = { - "foo", - "bar", - "waldo", - NULL - }; - const char *x; - unsigned i = 0; - - FOREACH_STRING(x, "foo", "bar", "waldo") - assert_se(streq_ptr(t[i++], x)); - - assert_se(i == 3); - - FOREACH_STRING(x, "zzz") - assert_se(streq(x, "zzz")); -} - -static void test_filename_is_valid(void) { - char foo[FILENAME_MAX+2]; - int i; - - assert_se(!filename_is_valid("")); - assert_se(!filename_is_valid("/bar/foo")); - assert_se(!filename_is_valid("/")); - assert_se(!filename_is_valid(".")); - assert_se(!filename_is_valid("..")); - - for (i=0; i<FILENAME_MAX+1; i++) - foo[i] = 'a'; - foo[FILENAME_MAX+1] = '\0'; - - assert_se(!filename_is_valid(foo)); - - assert_se(filename_is_valid("foo_bar-333")); - assert_se(filename_is_valid("o.o")); -} - -static void test_string_has_cc(void) { - assert_se(string_has_cc("abc\1", NULL)); - assert_se(string_has_cc("abc\x7f", NULL)); - assert_se(string_has_cc("abc\x7f", NULL)); - assert_se(string_has_cc("abc\t\x7f", "\t")); - assert_se(string_has_cc("abc\t\x7f", "\t")); - assert_se(string_has_cc("\x7f", "\t")); - assert_se(string_has_cc("\x7f", "\t\a")); - - assert_se(!string_has_cc("abc\t\t", "\t")); - assert_se(!string_has_cc("abc\t\t\a", "\t\a")); - assert_se(!string_has_cc("a\ab\tc", "\t\a")); -} - -static void test_ascii_strlower(void) { - char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK"; - assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk")); -} - -static void test_files_same(void) { - _cleanup_close_ int fd = -1; - char name[] = "/tmp/test-files_same.XXXXXX"; - char name_alias[] = "/tmp/test-files_same.alias"; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(symlink(name, name_alias) >= 0); - - assert_se(files_same(name, name)); - assert_se(files_same(name, name_alias)); - - unlink(name); - unlink(name_alias); -} - -static void test_is_valid_documentation_url(void) { - assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd")); - assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt")); - assert_se(documentation_url_is_valid("file:/foo/foo")); - assert_se(documentation_url_is_valid("man:systemd.special(7)")); - assert_se(documentation_url_is_valid("info:bar")); - - assert_se(!documentation_url_is_valid("foo:")); - assert_se(!documentation_url_is_valid("info:")); - assert_se(!documentation_url_is_valid("")); -} - -static void test_file_in_same_dir(void) { - char *t; - - t = file_in_same_dir("/", "a"); - assert_se(streq(t, "/a")); - free(t); - - t = file_in_same_dir("/", "/a"); - assert_se(streq(t, "/a")); - free(t); - - t = file_in_same_dir("", "a"); - assert_se(streq(t, "a")); - free(t); - - t = file_in_same_dir("a/", "a"); - assert_se(streq(t, "a/a")); - free(t); - - t = file_in_same_dir("bar/foo", "bar"); - assert_se(streq(t, "bar/bar")); - free(t); -} - -static void test_endswith(void) { - assert_se(endswith("foobar", "bar")); - assert_se(endswith("foobar", "")); - assert_se(endswith("foobar", "foobar")); - assert_se(endswith("", "")); - - assert_se(!endswith("foobar", "foo")); - assert_se(!endswith("foobar", "foobarfoofoo")); -} - -static void test_endswith_no_case(void) { - assert_se(endswith_no_case("fooBAR", "bar")); - assert_se(endswith_no_case("foobar", "")); - assert_se(endswith_no_case("foobar", "FOOBAR")); - assert_se(endswith_no_case("", "")); - - assert_se(!endswith_no_case("foobar", "FOO")); - assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO")); -} - -static void test_close_nointr(void) { - char name[] = "/tmp/test-test-close_nointr.XXXXXX"; - int fd; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(close_nointr(fd) >= 0); - assert_se(close_nointr(fd) < 0); - - unlink(name); -} - - -static void test_unlink_noerrno(void) { - char name[] = "/tmp/test-close_nointr.XXXXXX"; - int fd; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(close_nointr(fd) >= 0); - - { - PROTECT_ERRNO; - errno = -42; - assert_se(unlink_noerrno(name) >= 0); - assert_se(errno == -42); - assert_se(unlink_noerrno(name) < 0); - assert_se(errno == -42); - } -} - -static void test_readlink_and_make_absolute(void) { - char tempdir[] = "/tmp/test-readlink_and_make_absolute"; - char name[] = "/tmp/test-readlink_and_make_absolute/original"; - char name2[] = "test-readlink_and_make_absolute/original"; - char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; - char *r = NULL; - - assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); - assert_se(touch(name) >= 0); - - assert_se(symlink(name, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); - - assert_se(chdir(tempdir) >= 0); - assert_se(symlink(name2, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); - - assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); -} - -static void test_ignore_signals(void) { - assert_se(ignore_signals(SIGINT, -1) >= 0); - assert_se(kill(getpid(), SIGINT) >= 0); - assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); - assert_se(kill(getpid(), SIGUSR1) >= 0); - assert_se(kill(getpid(), SIGUSR2) >= 0); - assert_se(kill(getpid(), SIGTERM) >= 0); - assert_se(kill(getpid(), SIGPIPE) >= 0); - assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); -} - -static void test_strshorten(void) { - char s[] = "foobar"; - - assert_se(strlen(strshorten(s, 6)) == 6); - assert_se(strlen(strshorten(s, 12)) == 6); - assert_se(strlen(strshorten(s, 2)) == 2); - assert_se(strlen(strshorten(s, 0)) == 0); -} - -static void test_strjoina(void) { - char *actual; - - actual = strjoina("", "foo", "bar"); - assert_se(streq(actual, "foobar")); - - actual = strjoina("foo", "bar", "baz"); - assert_se(streq(actual, "foobarbaz")); - - actual = strjoina("foo", "", "bar", "baz"); - assert_se(streq(actual, "foobarbaz")); - - actual = strjoina("foo"); - assert_se(streq(actual, "foo")); - - actual = strjoina(NULL); - assert_se(streq(actual, "")); - - actual = strjoina(NULL, "foo"); - assert_se(streq(actual, "")); - - actual = strjoina("foo", NULL, "bar"); - assert_se(streq(actual, "foo")); -} - -static void test_is_symlink(void) { - char name[] = "/tmp/test-is_symlink.XXXXXX"; - char name_link[] = "/tmp/test-is_symlink.link"; - _cleanup_close_ int fd = -1; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(symlink(name, name_link) >= 0); - - assert_se(is_symlink(name) == 0); - assert_se(is_symlink(name_link) == 1); - assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); - - - unlink(name); - unlink(name_link); -} - -static void test_search_and_fopen(void) { - const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL}; - char name[] = "/tmp/test-search_and_fopen.XXXXXX"; - int fd = -1; - int r; - FILE *f; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = search_and_fopen(basename(name), "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen(name, "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen(basename(name), "r", "/", dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); - assert_se(r < 0); - r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); - assert_se(r < 0); - - r = unlink(name); - assert_se(r == 0); - - r = search_and_fopen(basename(name), "r", NULL, dirs, &f); - assert_se(r < 0); -} - - -static void test_search_and_fopen_nulstr(void) { - const char dirs[] = "/tmp/foo/bar\0/tmp\0"; - char name[] = "/tmp/test-search_and_fopen.XXXXXX"; - int fd = -1; - int r; - FILE *f; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); - assert_se(r < 0); - r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); - assert_se(r < 0); - - r = unlink(name); - assert_se(r == 0); - - r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); - assert_se(r < 0); -} - -static void test_glob_exists(void) { - char name[] = "/tmp/test-glob_exists.XXXXXX"; - int fd = -1; - int r; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = glob_exists("/tmp/test-glob_exists*"); - assert_se(r == 1); - - r = unlink(name); - assert_se(r == 0); - r = glob_exists("/tmp/test-glob_exists*"); - assert_se(r == 0); -} - static void test_execute_directory(void) { char template_lo[] = "/tmp/test-readlink_and_make_absolute-lo.XXXXXXX"; char template_hi[] = "/tmp/test-readlink_and_make_absolute-hi.XXXXXXX"; @@ -1402,17 +237,6 @@ static void test_execute_directory(void) { (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL); } -static int parse_item(const char *key, const char *value) { - assert_se(key); - - log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); - return 0; -} - -static void test_parse_proc_cmdline(void) { - assert_se(parse_proc_cmdline(parse_item) >= 0); -} - static void test_raw_clone(void) { pid_t parent, pid, pid2; @@ -1438,285 +262,20 @@ static void test_raw_clone(void) { } } -static void test_same_fd(void) { - _cleanup_close_pair_ int p[2] = { -1, -1 }; - _cleanup_close_ int a = -1, b = -1, c = -1; - - assert_se(pipe2(p, O_CLOEXEC) >= 0); - assert_se((a = dup(p[0])) >= 0); - assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0); - assert_se((c = dup(a)) >= 0); - - assert_se(same_fd(p[0], p[0]) > 0); - assert_se(same_fd(p[1], p[1]) > 0); - assert_se(same_fd(a, a) > 0); - assert_se(same_fd(b, b) > 0); - - assert_se(same_fd(a, p[0]) > 0); - assert_se(same_fd(p[0], a) > 0); - assert_se(same_fd(c, p[0]) > 0); - assert_se(same_fd(p[0], c) > 0); - assert_se(same_fd(a, c) > 0); - assert_se(same_fd(c, a) > 0); - - assert_se(same_fd(p[0], p[1]) == 0); - assert_se(same_fd(p[1], p[0]) == 0); - assert_se(same_fd(p[0], b) == 0); - assert_se(same_fd(b, p[0]) == 0); - assert_se(same_fd(p[1], a) == 0); - assert_se(same_fd(a, p[1]) == 0); - assert_se(same_fd(p[1], b) == 0); - assert_se(same_fd(b, p[1]) == 0); - - assert_se(same_fd(a, b) == 0); - assert_se(same_fd(b, a) == 0); -} - -static void test_uid_ptr(void) { - - assert_se(UID_TO_PTR(0) != NULL); - assert_se(UID_TO_PTR(1000) != NULL); - - assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0); - assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); -} - -static void test_sparse_write_one(int fd, const char *buffer, size_t n) { - char check[n]; - - assert_se(lseek(fd, 0, SEEK_SET) == 0); - assert_se(ftruncate(fd, 0) >= 0); - assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n); - - assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n); - assert_se(ftruncate(fd, n) >= 0); - - assert_se(lseek(fd, 0, SEEK_SET) == 0); - assert_se(read(fd, check, n) == (ssize_t) n); - - assert_se(memcmp(buffer, check, n) == 0); -} - -static void test_sparse_write(void) { - const char test_a[] = "test"; - const char test_b[] = "\0\0\0\0test\0\0\0\0"; - const char test_c[] = "\0\0test\0\0\0\0"; - const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0"; - const char test_e[] = "test\0\0\0\0test"; - _cleanup_close_ int fd = -1; - char fn[] = "/tmp/sparseXXXXXX"; - - fd = mkostemp(fn, O_CLOEXEC); - assert_se(fd >= 0); - unlink(fn); - - test_sparse_write_one(fd, test_a, sizeof(test_a)); - test_sparse_write_one(fd, test_b, sizeof(test_b)); - test_sparse_write_one(fd, test_c, sizeof(test_c)); - test_sparse_write_one(fd, test_d, sizeof(test_d)); - test_sparse_write_one(fd, test_e, sizeof(test_e)); -} - -static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { - _cleanup_free_ char *r; - - assert_se(r = shell_escape(s, bad)); - assert_se(streq_ptr(r, expected)); -} - -static void test_shell_escape(void) { - test_shell_escape_one("", "", ""); - test_shell_escape_one("\\", "", "\\\\"); - test_shell_escape_one("foobar", "", "foobar"); - test_shell_escape_one("foobar", "o", "f\\o\\obar"); - test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz"); -} - -static void test_shell_maybe_quote_one(const char *s, const char *expected) { - _cleanup_free_ char *r; - - assert_se(r = shell_maybe_quote(s)); - assert_se(streq(r, expected)); -} - -static void test_shell_maybe_quote(void) { - - test_shell_maybe_quote_one("", ""); - test_shell_maybe_quote_one("\\", "\"\\\\\""); - test_shell_maybe_quote_one("\"", "\"\\\"\""); - test_shell_maybe_quote_one("foobar", "foobar"); - test_shell_maybe_quote_one("foo bar", "\"foo bar\""); - test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\""); - test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); -} - -static void test_tempfn(void) { - char *ret = NULL, *p; - - assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX")); - free(ret); - - assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0); - assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX")); - free(ret); - - assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/.#waldo")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/waldo/.#")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); -} - -static void test_strcmp_ptr(void) { - assert_se(strcmp_ptr(NULL, NULL) == 0); - assert_se(strcmp_ptr("", NULL) > 0); - assert_se(strcmp_ptr("foo", NULL) > 0); - assert_se(strcmp_ptr(NULL, "") < 0); - assert_se(strcmp_ptr(NULL, "bar") < 0); - assert_se(strcmp_ptr("foo", "bar") > 0); - assert_se(strcmp_ptr("bar", "baz") < 0); - assert_se(strcmp_ptr("foo", "foo") == 0); - assert_se(strcmp_ptr("", "") == 0); -} - -static void test_fgetxattrat_fake(void) { - char t[] = "/var/tmp/xattrtestXXXXXX"; - _cleanup_close_ int fd = -1; - const char *x; - char v[3] = {}; - int r; - - assert_se(mkdtemp(t)); - x = strjoina(t, "/test"); - assert_se(touch(x) >= 0); - - r = setxattr(x, "user.foo", "bar", 3, 0); - if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */ - goto cleanup; - assert_se(r >= 0); - - fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); - assert_se(fd >= 0); - - assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0); - assert_se(memcmp(v, "bar", 3) == 0); - - safe_close(fd); - fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); - assert_se(fd >= 0); - assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA); - -cleanup: - assert_se(unlink(x) >= 0); - assert_se(rmdir(t) >= 0); -} - -static void test_runlevel_to_target(void) { - assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); - assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); - assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); -} - int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_streq_ptr(); test_align_power2(); test_max(); test_container_of(); - test_alloca(); test_div_round_up(); - test_first_word(); - test_close_many(); - test_parse_uid(); - test_strappend(); - test_strstrip(); - test_delete_chars(); - test_in_charset(); - test_hexchar(); - test_unhexchar(); - test_base32hexchar(); - test_unbase32hexchar(); - test_base64char(); - test_unbase64char(); - test_octchar(); - test_unoctchar(); - test_decchar(); - test_undecchar(); - test_unhexmem(); - test_base32hexmem(); - test_unbase32hexmem(); - test_base64mem(); - test_unbase64mem(); - test_cescape(); - test_cunescape(); - test_foreach_word(); - test_foreach_word_quoted(); - test_memdup_multiply(); test_u64log2(); test_protect_errno(); - test_parse_cpu_set(); - test_config_parse_iec_uint64(); - test_strextend(); - test_strrep(); - test_split_pair(); - test_fstab_node_to_udev_node(); - test_get_files_in_directory(); test_in_set(); - test_writing_tmpfile(); - test_hexdump(); test_log2i(); - test_foreach_string(); - test_filename_is_valid(); - test_string_has_cc(); - test_ascii_strlower(); - test_files_same(); - test_is_valid_documentation_url(); - test_file_in_same_dir(); - test_endswith(); - test_endswith_no_case(); - test_close_nointr(); - test_unlink_noerrno(); - test_readlink_and_make_absolute(); - test_ignore_signals(); - test_strshorten(); - test_strjoina(); - test_is_symlink(); - test_search_and_fopen(); - test_search_and_fopen_nulstr(); - test_glob_exists(); test_execute_directory(); - test_parse_proc_cmdline(); test_raw_clone(); - test_same_fd(); - test_uid_ptr(); - test_sparse_write(); - test_shell_escape(); - test_shell_maybe_quote(); - test_tempfn(); - test_strcmp_ptr(); - test_fgetxattrat_fake(); - test_runlevel_to_target(); return 0; } diff --git a/src/test/test-web-util.c b/src/test/test-web-util.c new file mode 100644 index 0000000000..79a3a13af6 --- /dev/null +++ b/src/test/test-web-util.c @@ -0,0 +1,39 @@ +/*** + 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" +#include "web-util.h" + +static void test_is_valid_documentation_url(void) { + assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd")); + assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt")); + assert_se(documentation_url_is_valid("file:/foo/foo")); + assert_se(documentation_url_is_valid("man:systemd.special(7)")); + assert_se(documentation_url_is_valid("info:bar")); + + assert_se(!documentation_url_is_valid("foo:")); + assert_se(!documentation_url_is_valid("info:")); + assert_se(!documentation_url_is_valid("")); +} + +int main(int argc, char *argv[]) { + test_is_valid_documentation_url(); + + return 0; +} diff --git a/src/test/test-xattr-util.c b/src/test/test-xattr-util.c new file mode 100644 index 0000000000..267f29426c --- /dev/null +++ b/src/test/test-xattr-util.c @@ -0,0 +1,69 @@ +/*** + 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 <sys/types.h> +#include <sys/xattr.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "string-util.h" +#include "xattr-util.h" + +static void test_fgetxattrat_fake(void) { + char t[] = "/var/tmp/xattrtestXXXXXX"; + _cleanup_close_ int fd = -1; + const char *x; + char v[3] = {}; + int r; + + assert_se(mkdtemp(t)); + x = strjoina(t, "/test"); + assert_se(touch(x) >= 0); + + r = setxattr(x, "user.foo", "bar", 3, 0); + if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */ + goto cleanup; + assert_se(r >= 0); + + fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + + assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0); + assert_se(memcmp(v, "bar", 3) == 0); + + safe_close(fd); + fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA); + +cleanup: + assert_se(unlink(x) >= 0); + assert_se(rmdir(t) >= 0); +} + +int main(void) { + test_fgetxattrat_fake(); + + return 0; +} diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 097963b41b..a2270aff46 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -40,14 +40,6 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; static char *arg_host = NULL; static bool arg_adjust_system_clock = false; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void polkit_agent_open_if_enabled(void) { /* Open the polkit agent as a child process if necessary */ @@ -313,7 +305,7 @@ static int list_timezones(sd_bus *bus, char **args, unsigned n) { if (r < 0) return log_error_errno(r, "Failed to read list of time zones: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); strv_print(zones); return 0; diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 2a10135fba..ffec609c69 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -78,7 +78,7 @@ static int context_read_data(Context *c) { c->zone = t; t = NULL; - c->local_rtc = clock_is_localtime() > 0; + c->local_rtc = clock_is_localtime(NULL) > 0; return 0; } @@ -125,30 +125,44 @@ static int context_write_data_local_rtc(Context *c) { if (!w) return -ENOMEM; } else { - char *p, *e; + char *p; + const char *e = "\n"; /* default if there is less than 3 lines */ + const char *prepend = ""; size_t a, b; - p = strchr(s, '\n'); - if (!p) - return -EIO; - - p = strchr(p+1, '\n'); - if (!p) - return -EIO; - - p++; - e = strchr(p, '\n'); - if (!e) - return -EIO; + p = strchrnul(s, '\n'); + if (*p == '\0') + /* only one line, no \n terminator */ + prepend = "\n0\n"; + else if (p[1] == '\0') { + /* only one line, with \n terminator */ + ++p; + prepend = "0\n"; + } else { + p = strchr(p+1, '\n'); + if (!p) { + /* only two lines, no \n terminator */ + prepend = "\n"; + p = s + strlen(s); + } else { + char *end; + /* third line might have a \n terminator or not */ + p++; + end = strchr(p, '\n'); + /* if we actually have a fourth line, use that as suffix "e", otherwise the default \n */ + if (end) + e = end; + } + } a = p - s; b = strlen(e); - w = new(char, a + (c->local_rtc ? 5 : 3) + b + 1); + w = new(char, a + (c->local_rtc ? 5 : 3) + strlen(prepend) + b + 1); if (!w) return -ENOMEM; - *(char*) mempcpy(stpcpy(mempcpy(w, s, a), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0; + *(char*) mempcpy(stpcpy(stpcpy(mempcpy(w, s, a), prepend), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0; if (streq(w, NULL_ADJTIME_UTC)) { if (unlink("/etc/adjtime") < 0) @@ -159,7 +173,7 @@ static int context_write_data_local_rtc(Context *c) { } } - mac_selinux_init("/etc"); + mac_selinux_init(); return write_string_file_atomic_label("/etc/adjtime", w); } diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 23e19159e0..b67d672a6a 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -122,7 +122,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (clock_is_localtime() > 0) { + if (clock_is_localtime(NULL) > 0) { log_info("The system is configured to read the RTC time in the local time zone. " "This mode can not be fully supported. All system time to RTC updates are disabled."); m->rtc_local_time = true; diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 7b105a6bd4..efd264b34d 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -613,7 +613,7 @@ static int path_set_perms(Item *i, const char *path) { * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via * O_PATH. */ - fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); if (fd < 0) return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path); @@ -804,7 +804,7 @@ static int path_set_acls(Item *item, const char *path) { assert(item); assert(path); - fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); if (fd < 0) return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path); @@ -917,10 +917,7 @@ static int parse_attribute_from_arg(Item *item) { v = attributes[i].value; - if (mode == MODE_ADD || mode == MODE_SET) - value |= v; - else - value &= ~v; + SET_FLAG(value, v, (mode == MODE_ADD || mode == MODE_SET)); mask |= v; } @@ -2288,7 +2285,7 @@ int main(int argc, char *argv[]) { umask(0022); - mac_selinux_init(NULL); + mac_selinux_init(); items = ordered_hashmap_new(&string_hash_ops); globs = ordered_hashmap_new(&string_hash_ops); diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h index caea5c2693..68e4954537 100644 --- a/src/udev/mtd_probe/mtd_probe.h +++ b/src/udev/mtd_probe/mtd_probe.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2010 - Maxim Levitsky * @@ -17,8 +19,6 @@ * Boston, MA 02110-1301 USA */ -#pragma once - #include <mtd/mtd-user.h> #include "macro.h" diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c index 6a6c5522a7..2a7ba17637 100644 --- a/src/udev/mtd_probe/probe_smartmedia.c +++ b/src/udev/mtd_probe/probe_smartmedia.c @@ -73,7 +73,7 @@ void probe_smart_media(int mtd_fd, mtd_info_t* info) for (offset = 0 ; offset < block_size * spare_count ; offset += sector_size) { lseek(mtd_fd, SEEK_SET, offset); - if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE){ + if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE) { cis_found = 1; break; } diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h index 2e6e1d7150..7716516e76 100644 --- a/src/udev/net/ethtool-util.h +++ b/src/udev/net/ethtool-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <macro.h> /* we can't use DUPLEX_ prefix, as it diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 15145fc5eb..c66504102f 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -18,7 +18,6 @@ ***/ #include <netinet/ether.h> -#include <linux/netdevice.h> #include "sd-netlink.h" diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index f525fe2116..9df5529d05 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include "libudev.h" #include "condition.h" diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h index 3bf1a94200..a27a84a40a 100644 --- a/src/udev/scsi_id/scsi.h +++ b/src/udev/scsi_id/scsi.h @@ -1,3 +1,5 @@ +#pragma once + /* * scsi.h * @@ -10,8 +12,6 @@ * Free Software Foundation version 2 of the License. */ -#pragma once - #include <scsi/scsi.h> struct scsi_ioctl_command { diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h index 141b116a88..5c2e1c28ee 100644 --- a/src/udev/scsi_id/scsi_id.h +++ b/src/udev/scsi_id/scsi_id.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) IBM Corp. 2003 * @@ -15,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#pragma once - #define MAX_PATH_LEN 512 /* diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index 3a3d8a1770..51a55cdbc4 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -177,7 +177,7 @@ static bool test_pointers(struct udev_device *dev, has_mt_coordinates = test_bit(ABS_MT_POSITION_X, bitmask_abs) && test_bit(ABS_MT_POSITION_Y, bitmask_abs); /* unset has_mt_coordinates if devices claims to have all abs axis */ - if(has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs)) + if (has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs)) has_mt_coordinates = false; is_direct = test_bit(INPUT_PROP_DIRECT, bitmask_props); has_touch = test_bit(BTN_TOUCH, bitmask_key); diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index b6ed45d8ba..6e9adc6e96 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -712,7 +712,7 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool * devices do not expose their buses and do not provide a unique * and predictable name that way. */ - if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport) + if (streq_ptr(udev_device_get_subsystem(dev), "block") && !supported_transport) path = mfree(path); if (path != NULL) { diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index c06ace09cf..475856db6f 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -33,9 +33,11 @@ #include "conf-files.h" #include "escape.h" #include "fd-util.h" +#include "fs-util.h" #include "glob-util.h" #include "path-util.h" #include "stat-util.h" +#include "stdio-util.h" #include "strbuf.h" #include "string-util.h" #include "strv.h" @@ -686,41 +688,31 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi return 0; } -static int attr_subst_subdir(char *attr, size_t len) { - bool found = false; +static void attr_subst_subdir(char *attr, size_t len) { + const char *pos, *tail, *path; + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *dent; - if (strstr(attr, "/*/")) { - char *pos; - char dirname[UTIL_PATH_SIZE]; - const char *tail; - DIR *dir; + pos = strstr(attr, "/*/"); + if (!pos) + return; - strscpy(dirname, sizeof(dirname), attr); - pos = strstr(dirname, "/*/"); - if (pos == NULL) - return -1; - pos[0] = '\0'; - tail = &pos[2]; - dir = opendir(dirname); - if (dir != NULL) { - struct dirent *dent; + tail = pos + 2; + path = strndupa(attr, pos - attr + 1); /* include slash at end */ + dir = opendir(path); + if (dir == NULL) + return; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - struct stat stats; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) + if (dent->d_name[0] != '.') { + char n[strlen(dent->d_name) + strlen(tail) + 1]; - if (dent->d_name[0] == '.') - continue; - strscpyl(attr, len, dirname, "/", dent->d_name, tail, NULL); - if (stat(attr, &stats) == 0) { - found = true; - break; - } + strscpyl(n, sizeof n, dent->d_name, tail, NULL); + if (faccessat(dirfd(dir), n, F_OK, 0) == 0) { + strscpyl(attr, len, path, n, NULL); + break; } - closedir(dir); } - } - - return found; } static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value) { @@ -831,12 +823,13 @@ static const char *get_key_attribute(struct udev *udev, char *str) { return NULL; } -static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, - enum operation_type op, - const char *value, const void *data) { - struct token *token = &rule_tmp->token[rule_tmp->token_cur]; +static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, + enum operation_type op, + const char *value, const void *data) { + struct token *token = rule_tmp->token + rule_tmp->token_cur; const char *attr = NULL; + assert(rule_tmp->token_cur < ELEMENTSOF(rule_tmp->token)); memzero(token, sizeof(struct token)); switch (type) { @@ -919,8 +912,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, case TK_M_MAX: case TK_END: case TK_UNSET: - log_error("wrong type %u", type); - return -1; + assert_not_reached("wrong type"); } if (value != NULL && type < TK_M_MAX) { @@ -969,11 +961,6 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, token->key.type = type; token->key.op = op; rule_tmp->token_cur++; - if (rule_tmp->token_cur >= ELEMENTSOF(rule_tmp->token)) { - log_error("temporary rule array too small"); - return -1; - } - return 0; } static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) { @@ -1010,8 +997,13 @@ static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) { return 0; } -static int add_rule(struct udev_rules *rules, char *line, - const char *filename, unsigned int filename_off, unsigned int lineno) { +#define LOG_RULE_ERROR(fmt, ...) log_error("Invalid rule %s:%u: " fmt, filename, lineno, ##__VA_ARGS__) +#define LOG_RULE_WARNING(fmt, ...) log_warning("%s:%u: " fmt, filename, lineno, ##__VA_ARGS__) +#define LOG_RULE_DEBUG(fmt, ...) log_debug("%s:%u: " fmt, filename, lineno, ##__VA_ARGS__) +#define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; } + +static void add_rule(struct udev_rules *rules, char *line, + const char *filename, unsigned int filename_off, unsigned int lineno) { char *linepos; const char *attr; struct rule_tmp rule_tmp = { @@ -1052,427 +1044,322 @@ static int add_rule(struct udev_rules *rules, char *line, break; } + if (rule_tmp.token_cur >= ELEMENTSOF(rule_tmp.token)) + LOG_AND_RETURN("temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur); + if (streq(key, "ACTION")) { - if (op > OP_MATCH_MAX) { - log_error("invalid ACTION operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL); - continue; - } - if (streq(key, "DEVPATH")) { - if (op > OP_MATCH_MAX) { - log_error("invalid DEVPATH operation"); - goto invalid; - } + } else if (streq(key, "DEVPATH")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL); - continue; - } - if (streq(key, "KERNEL")) { - if (op > OP_MATCH_MAX) { - log_error("invalid KERNEL operation"); - goto invalid; - } + } else if (streq(key, "KERNEL")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL); - continue; - } - if (streq(key, "SUBSYSTEM")) { - if (op > OP_MATCH_MAX) { - log_error("invalid SUBSYSTEM operation"); - goto invalid; - } + } else if (streq(key, "SUBSYSTEM")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + /* bus, class, subsystem events should all be the same */ - if (streq(value, "subsystem") || - streq(value, "bus") || - streq(value, "class")) { - if (streq(value, "bus") || streq(value, "class")) - log_error("'%s' must be specified as 'subsystem' " - "please fix it in %s:%u", value, filename, lineno); + if (STR_IN_SET(value, "subsystem", "bus", "class")) { + if (!streq(value, "subsystem")) + LOG_RULE_WARNING("'%s' must be specified as 'subsystem'; please fix", value); + rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL); } else rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL); - continue; - } - if (streq(key, "DRIVER")) { - if (op > OP_MATCH_MAX) { - log_error("invalid DRIVER operation"); - goto invalid; - } + } else if (streq(key, "DRIVER")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL); - continue; - } - if (startswith(key, "ATTR{")) { + } else if (startswith(key, "ATTR{")) { attr = get_key_attribute(rules->udev, key + strlen("ATTR")); - if (attr == NULL) { - log_error("error parsing ATTR attribute"); - goto invalid; - } - if (op == OP_REMOVE) { - log_error("invalid ATTR operation"); - goto invalid; - } + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "ATTR"); + + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "ATTR"); + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); else rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); - continue; - } - if (startswith(key, "SYSCTL{")) { + } else if (startswith(key, "SYSCTL{")) { attr = get_key_attribute(rules->udev, key + strlen("SYSCTL")); - if (attr == NULL) { - log_error("error parsing SYSCTL attribute"); - goto invalid; - } - if (op == OP_REMOVE) { - log_error("invalid SYSCTL operation"); - goto invalid; - } + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "ATTR"); + + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "ATTR"); + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); else rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr); - continue; - } - if (startswith(key, "SECLABEL{")) { + } else if (startswith(key, "SECLABEL{")) { attr = get_key_attribute(rules->udev, key + strlen("SECLABEL")); - if (!attr) { - log_error("error parsing SECLABEL attribute"); - goto invalid; - } - if (op == OP_REMOVE) { - log_error("invalid SECLABEL operation"); - goto invalid; - } + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "SECLABEL"); + + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "SECLABEL"); rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr); - continue; - } - if (streq(key, "KERNELS")) { - if (op > OP_MATCH_MAX) { - log_error("invalid KERNELS operation"); - goto invalid; - } + } else if (streq(key, "KERNELS")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL); - continue; - } - if (streq(key, "SUBSYSTEMS")) { - if (op > OP_MATCH_MAX) { - log_error("invalid SUBSYSTEMS operation"); - goto invalid; - } + } else if (streq(key, "SUBSYSTEMS")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL); - continue; - } - if (streq(key, "DRIVERS")) { - if (op > OP_MATCH_MAX) { - log_error("invalid DRIVERS operation"); - goto invalid; - } + } else if (streq(key, "DRIVERS")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL); - continue; - } - if (startswith(key, "ATTRS{")) { - if (op > OP_MATCH_MAX) { - log_error("invalid ATTRS operation"); - goto invalid; - } + } else if (startswith(key, "ATTRS{")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", "ATTRS"); + attr = get_key_attribute(rules->udev, key + strlen("ATTRS")); - if (attr == NULL) { - log_error("error parsing ATTRS attribute"); - goto invalid; - } + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "ATTRS"); + if (startswith(attr, "device/")) - log_error("the 'device' link may not be available in a future kernel, " - "please fix it in %s:%u", filename, lineno); - else if (strstr(attr, "../") != NULL) - log_error("do not reference parent sysfs directories directly, " - "it may break with a future kernel, please fix it in %s:%u", filename, lineno); + LOG_RULE_WARNING("'device' link may not be available in future kernels; please fix"); + if (strstr(attr, "../") != NULL) + LOG_RULE_WARNING("direct reference to parent sysfs directory, may break in future kernels; please fix"); rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr); - continue; - } - if (streq(key, "TAGS")) { - if (op > OP_MATCH_MAX) { - log_error("invalid TAGS operation"); - goto invalid; - } + } else if (streq(key, "TAGS")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL); - continue; - } - if (startswith(key, "ENV{")) { + } else if (startswith(key, "ENV{")) { attr = get_key_attribute(rules->udev, key + strlen("ENV")); - if (attr == NULL) { - log_error("error parsing ENV attribute"); - goto invalid; - } - if (op == OP_REMOVE) { - log_error("invalid ENV operation"); - goto invalid; - } - if (op < OP_MATCH_MAX) { - if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0) - goto invalid; - } else { - static const char *blacklist[] = { - "ACTION", - "SUBSYSTEM", - "DEVTYPE", - "MAJOR", - "MINOR", - "DRIVER", - "IFINDEX", - "DEVNAME", - "DEVLINKS", - "DEVPATH", - "TAGS", - }; - unsigned int i; - - for (i = 0; i < ELEMENTSOF(blacklist); i++) { - if (!streq(attr, blacklist[i])) - continue; - log_error("invalid ENV attribute, '%s' can not be set %s:%u", attr, filename, lineno); - goto invalid; - } - if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0) - goto invalid; - } - continue; - } + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "ENV"); + + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "ENV"); - if (streq(key, "TAG")) { + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr); + else { + if (STR_IN_SET(attr, + "ACTION", + "SUBSYSTEM", + "DEVTYPE", + "MAJOR", + "MINOR", + "DRIVER", + "IFINDEX", + "DEVNAME", + "DEVLINKS", + "DEVPATH", + "TAGS")) + LOG_AND_RETURN("invalid ENV attribute, '%s' cannot be set", attr); + + rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr); + } + + } else if (streq(key, "TAG")) { if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); else rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); - continue; - } - if (streq(key, "PROGRAM")) { - if (op == OP_REMOVE) { - log_error("invalid PROGRAM operation"); - goto invalid; - } + } else if (streq(key, "PROGRAM")) { + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); - continue; - } - if (streq(key, "RESULT")) { - if (op > OP_MATCH_MAX) { - log_error("invalid RESULT operation"); - goto invalid; - } + } else if (streq(key, "RESULT")) { + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL); - continue; - } - if (startswith(key, "IMPORT")) { + } else if (startswith(key, "IMPORT")) { attr = get_key_attribute(rules->udev, key + strlen("IMPORT")); if (attr == NULL) { - log_error("IMPORT{} type missing, ignoring IMPORT %s:%u", filename, lineno); + LOG_RULE_WARNING("ignoring IMPORT{} with missing type"); continue; } - if (op == OP_REMOVE) { - log_error("invalid IMPORT operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "IMPORT"); + if (streq(attr, "program")) { /* find known built-in command */ if (value[0] != '/') { - enum udev_builtin_cmd cmd; + const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); - cmd = udev_builtin_lookup(value); if (cmd < UDEV_BUILTIN_MAX) { - log_debug("IMPORT found builtin '%s', replacing %s:%u", - value, filename, lineno); + LOG_RULE_DEBUG("IMPORT found builtin '%s', replacing", value); rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); continue; } } rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL); } else if (streq(attr, "builtin")) { - enum udev_builtin_cmd cmd = udev_builtin_lookup(value); + const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); - if (cmd < UDEV_BUILTIN_MAX) - rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + if (cmd >= UDEV_BUILTIN_MAX) + LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown", value); else - log_error("IMPORT{builtin}: '%s' unknown %s:%u", value, filename, lineno); - } else if (streq(attr, "file")) { + rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + } else if (streq(attr, "file")) rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL); - } else if (streq(attr, "db")) { + else if (streq(attr, "db")) rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL); - } else if (streq(attr, "cmdline")) { + else if (streq(attr, "cmdline")) rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL); - } else if (streq(attr, "parent")) { + else if (streq(attr, "parent")) rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL); - } else - log_error("IMPORT{} unknown type, ignoring IMPORT %s:%u", filename, lineno); - continue; - } + else + LOG_RULE_ERROR("ignoring unknown %s{} type '%s'", "IMPORT", attr); - if (startswith(key, "TEST")) { + } else if (startswith(key, "TEST")) { mode_t mode = 0; - if (op > OP_MATCH_MAX) { - log_error("invalid TEST operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", "TEST"); + attr = get_key_attribute(rules->udev, key + strlen("TEST")); if (attr != NULL) { mode = strtol(attr, NULL, 8); rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode); - } else { + } else rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL); - } - continue; - } - if (startswith(key, "RUN")) { + } else if (startswith(key, "RUN")) { attr = get_key_attribute(rules->udev, key + strlen("RUN")); if (attr == NULL) attr = "program"; - if (op == OP_REMOVE) { - log_error("invalid RUN operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "RUN"); if (streq(attr, "builtin")) { - enum udev_builtin_cmd cmd = udev_builtin_lookup(value); + const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); if (cmd < UDEV_BUILTIN_MAX) rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd); else - log_error("RUN{builtin}: '%s' unknown %s:%u", value, filename, lineno); + LOG_RULE_ERROR("RUN{builtin}: '%s' unknown", value); } else if (streq(attr, "program")) { - enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX; + const enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX; rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd); - } else { - log_error("RUN{} unknown type, ignoring RUN %s:%u", filename, lineno); - } + } else + LOG_RULE_ERROR("ignoring unknown %s{} type '%s'", "RUN", attr); - continue; - } + } else if (streq(key, "LABEL")) { + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); - if (streq(key, "LABEL")) { - if (op == OP_REMOVE) { - log_error("invalid LABEL operation"); - goto invalid; - } rule_tmp.rule.rule.label_off = rules_add_string(rules, value); - continue; - } - if (streq(key, "GOTO")) { - if (op == OP_REMOVE) { - log_error("invalid GOTO operation"); - goto invalid; - } + } else if (streq(key, "GOTO")) { + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); - continue; - } - if (startswith(key, "NAME")) { - if (op == OP_REMOVE) { - log_error("invalid NAME operation"); - goto invalid; - } - if (op < OP_MATCH_MAX) { + } else if (startswith(key, "NAME")) { + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); - } else { + else { if (streq(value, "%k")) { - log_error("NAME=\"%%k\" is ignored, because it breaks kernel supplied names, " - "please remove it from %s:%u\n", filename, lineno); + LOG_RULE_WARNING("NAME=\"%%k\" is ignored, because it breaks kernel supplied names; please remove"); continue; } - if (value[0] == '\0') { - log_debug("NAME=\"\" is ignored, because udev will not delete any device nodes, " - "please remove it from %s:%u\n", filename, lineno); + if (isempty(value)) { + LOG_RULE_DEBUG("NAME=\"\" is ignored, because udev will not delete any device nodes; please remove"); continue; } rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); } rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "SYMLINK")) { - if (op == OP_REMOVE) { - log_error("invalid SYMLINK operation"); - goto invalid; - } + } else if (streq(key, "SYMLINK")) { + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); else rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL); rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "OWNER")) { + } else if (streq(key, "OWNER")) { uid_t uid; char *endptr; - if (op == OP_REMOVE) { - log_error("invalid OWNER operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); uid = strtoul(value, &endptr, 10); - if (endptr[0] == '\0') { + if (endptr[0] == '\0') rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); - } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { + else if (rules->resolve_names > 0 && strchr("$%", value[0]) == NULL) { uid = add_uid(rules, value); rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); } else if (rules->resolve_names >= 0) rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "GROUP")) { + } else if (streq(key, "GROUP")) { gid_t gid; char *endptr; - if (op == OP_REMOVE) { - log_error("invalid GROUP operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); gid = strtoul(value, &endptr, 10); - if (endptr[0] == '\0') { + if (endptr[0] == '\0') rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); - } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { + else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { gid = add_gid(rules, value); rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); } else if (rules->resolve_names >= 0) rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "MODE")) { + } else if (streq(key, "MODE")) { mode_t mode; char *endptr; - if (op == OP_REMOVE) { - log_error("invalid MODE operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); mode = strtol(value, &endptr, 8); if (endptr[0] == '\0') @@ -1480,27 +1367,23 @@ static int add_rule(struct udev_rules *rules, char *line, else rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "OPTIONS")) { + } else if (streq(key, "OPTIONS")) { const char *pos; - if (op == OP_REMOVE) { - log_error("invalid OPTIONS operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); pos = strstr(value, "link_priority="); if (pos != NULL) { - int prio = atoi(&pos[strlen("link_priority=")]); + int prio = atoi(pos + strlen("link_priority=")); rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio); } pos = strstr(value, "string_escape="); if (pos != NULL) { - pos = &pos[strlen("string_escape=")]; + pos += strlen("string_escape="); if (startswith(pos, "none")) rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL); else if (startswith(pos, "replace")) @@ -1527,30 +1410,19 @@ static int add_rule(struct udev_rules *rules, char *line, pos = strstr(value, "static_node="); if (pos != NULL) { - rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL); + pos += strlen("static_node="); + rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL); rule_tmp.rule.rule.has_static_node = true; } - continue; - } - - log_error("unknown key '%s' in %s:%u", key, filename, lineno); - goto invalid; + } else + LOG_AND_RETURN("unknown key '%s'", key); } - /* add rule token */ + /* add rule token and sort tokens */ rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur; - if (add_token(rules, &rule_tmp.rule) != 0) - goto invalid; - - /* add tokens to list, sorted by type */ - if (sort_token(rules, &rule_tmp) != 0) - goto invalid; - - return 0; -invalid: - log_error("invalid rule '%s:%u'", filename, lineno); - return -1; + if (add_token(rules, &rule_tmp.rule) != 0 || sort_token(rules, &rule_tmp) != 0) + LOG_RULE_ERROR("failed to add rule token"); } static int parse_file(struct udev_rules *rules, const char *filename) { @@ -1849,18 +1721,18 @@ enum escape_type { ESCAPE_REPLACE, }; -int udev_rules_apply_to_event(struct udev_rules *rules, - struct udev_event *event, - usec_t timeout_usec, - usec_t timeout_warn_usec, - struct udev_list *properties_list) { +void udev_rules_apply_to_event(struct udev_rules *rules, + struct udev_event *event, + usec_t timeout_usec, + usec_t timeout_warn_usec, + struct udev_list *properties_list) { struct token *cur; struct token *rule; enum escape_type esc = ESCAPE_UNSET; bool can_set_name; if (rules->tokens == NULL) - return -1; + return; can_set_name = ((!streq(udev_device_get_action(event->dev), "remove")) && (major(udev_device_get_devnum(event->dev)) > 0 || @@ -2168,7 +2040,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, break; } case TK_M_IMPORT_CMDLINE: { - FILE *f; + _cleanup_fclose_ FILE *f = NULL; bool imported = false; f = fopen("/proc/cmdline", "re"); @@ -2181,12 +2053,12 @@ int udev_rules_apply_to_event(struct udev_rules *rules, pos = strstr(cmdline, key); if (pos != NULL) { + imported = true; pos += strlen(key); - if (pos[0] == '\0' || isspace(pos[0])) { + if (pos[0] == '\0' || isspace(pos[0])) /* we import simple flags as 'FLAG=1' */ udev_device_add_property(event->dev, key, "1"); - imported = true; - } else if (pos[0] == '=') { + else if (pos[0] == '=') { const char *value; pos++; @@ -2195,11 +2067,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, pos++; pos[0] = '\0'; udev_device_add_property(event->dev, key, value); - imported = true; } } } - fclose(f); } if (!imported && cur->key.op != OP_NOMATCH) goto nomatch; @@ -2428,13 +2298,17 @@ int udev_rules_apply_to_event(struct udev_rules *rules, log_debug("%i character(s) replaced", count); } if (major(udev_device_get_devnum(event->dev)) && - (!streq(name_str, udev_device_get_devnode(event->dev) + strlen("/dev/")))) { - log_error("NAME=\"%s\" ignored, kernel device nodes " - "can not be renamed; please fix it in %s:%u\n", name, - rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + !streq(name_str, udev_device_get_devnode(event->dev) + strlen("/dev/"))) { + log_error("NAME=\"%s\" ignored, kernel device nodes cannot be renamed; please fix it in %s:%u\n", + name, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); break; } - free_and_strdup(&event->name, name_str); + if (free_and_strdup(&event->name, name_str) < 0) { + log_oom(); + return; + } log_debug("NAME '%s' %s:%u", event->name, rules_str(rules, rule->rule.filename_off), @@ -2491,7 +2365,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, const char *key_name = rules_str(rules, cur->key.attr_off); char attr[UTIL_PATH_SIZE]; char value[UTIL_NAME_SIZE]; - FILE *f; + _cleanup_fclose_ FILE *f = NULL; if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0) strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL); @@ -2502,13 +2376,10 @@ int udev_rules_apply_to_event(struct udev_rules *rules, rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); f = fopen(attr, "we"); - if (f != NULL) { - if (fprintf(f, "%s", value) <= 0) - log_error_errno(errno, "error writing ATTR{%s}: %m", attr); - fclose(f); - } else { + if (f == NULL) log_error_errno(errno, "error opening ATTR{%s} for writing: %m", attr); - } + else if (fprintf(f, "%s", value) <= 0) + log_error_errno(errno, "error writing ATTR{%s}: %m", attr); break; } case TK_A_SYSCTL: { @@ -2546,7 +2417,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, cur = &rules->tokens[cur->key.rule_goto]; continue; case TK_END: - return 0; + return; case TK_M_PARENTS_MIN: case TK_M_PARENTS_MAX: @@ -2574,7 +2445,7 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) { char **t; FILE *f = NULL; _cleanup_free_ char *path = NULL; - int r = 0; + int r; if (rules->tokens == NULL) return 0; @@ -2645,8 +2516,6 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) { if (r < 0 && errno != EEXIST) return log_error_errno(errno, "failed to create symlink %s -> %s: %m", tag_symlink, device_node); - else - r = 0; } } @@ -2698,12 +2567,11 @@ finish: fflush(f); fchmod(fileno(f), 0644); if (ferror(f) || rename(path, "/run/udev/static_node-tags") < 0) { - r = -errno; - unlink("/run/udev/static_node-tags"); - unlink(path); + unlink_noerrno("/run/udev/static_node-tags"); + unlink_noerrno(path); + return -errno; } - fclose(f); } - return r; + return 0; } diff --git a/src/udev/udev.h b/src/udev/udev.h index 1f9c8120c0..8433e8d9f2 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> * Copyright (C) 2003-2010 Kay Sievers <kay@vrfy.org> @@ -16,9 +18,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#pragma once - #include <sys/param.h> +#include <sys/sysmacros.h> #include <sys/types.h> #include "libudev.h" @@ -71,9 +72,9 @@ struct udev_rules; struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names); struct udev_rules *udev_rules_unref(struct udev_rules *rules); bool udev_rules_check_timestamp(struct udev_rules *rules); -int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, - usec_t timeout_usec, usec_t timeout_warn_usec, - struct udev_list *properties_list); +void udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, + usec_t timeout_usec, usec_t timeout_warn_usec, + struct udev_list *properties_list); int udev_rules_apply_static_dev_perms(struct udev_rules *rules); /* udev-event.c */ diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index f9cb5e63a2..b5f7f0d512 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -100,7 +100,7 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) { udev_list_init(udev, &subsystem_match_list, true); udev_list_init(udev, &tag_match_list, true); - while((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0) switch (c) { case 'p': case 'e': diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index ff427cf292..702dbe5282 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -61,7 +61,7 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) { log_debug("version %s", VERSION); - while((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0) switch (c) { case 'a': action = optarg; diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h index 37e4fe8369..dc712b0d93 100644 --- a/src/udev/udevadm-util.h +++ b/src/udev/udevadm-util.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2014 Zbigniew JÄ™drzejewski-Szmek <zbyszek@in.waw.pl> * @@ -15,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#pragma once - #include "udev.h" struct udev_device *find_device(struct udev *udev, diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 7bd2c1ea42..a6a873e5de 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - mac_selinux_init("/dev"); + mac_selinux_init(); while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0) switch (c) { diff --git a/src/udev/udevd.c b/src/udev/udevd.c index bb92f16352..243df7386f 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1695,7 +1695,7 @@ int main(int argc, char *argv[]) { umask(022); - r = mac_selinux_init("/dev"); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "could not initialize labelling: %m"); goto exit; diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index 931e583785..da306a4444 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index 8bf44e2100..9b29b5ba1d 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -40,7 +40,7 @@ int main(int argc, char*argv[]) { umask(0022); - mac_selinux_init(NULL); + mac_selinux_init(); if (streq(argv[1], "start")) { int r = 0; |