different from what the documentation said, and not particularly
useful, as repeated systemd-tmpfiles invocations would not be
idempotent and grow such files without bounds. With this release
- behaviour has been altered slightly, to match what the documentation
- says: lines of this type only have an effect if the indicated files
- don't exist yet, and only then the argument string is written to the
- file.
+ behaviour has been altered to match what the documentation says:
+ lines of this type only have an effect if the indicated files don't
+ exist yet, and only then the argument string is written to the file.
* FUTURE INCOMPATIBILITY: In systemd v238 we intend to slightly change
systemd-tmpfiles behaviour: previously, read-only files owned by root
Please see the [HACKING file](../master/docs/HACKING) for information how to hack on systemd and test your modifications.
-Please see our [Contribution Guidelines](../master/.github/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.
+Please see our [Contribution Guidelines](../master/docs/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.
When preparing patches for systemd, please follow our [Coding Style Guidelines](../master/docs/CODING_STYLE).
Features:
+* chown() tty a service is attached to after the service goes down
+
* optionally, if a per-partition GPT flag is set for the root/home/… partitions
format the partition on next boot and unset the flag, in order to implement
factory reset. also, add a second flag that simply indicates whether such a
zero and is not open anymore, while the latter happens when a file is
unlinked from any dir.
-* port systemctl, systemd-inhibit, busctl, … over to format-table.[ch]'s table formatters
+* port systemctl, busctl, … over to format-table.[ch]'s table formatters
* pid1: lock image configured with RootDirectory=/RootImage= using the usual nspawn semantics while the unit is up
for all units. It should be both a way to pin units into memory as well as a
wait to retrieve their exit data.
-* maybe set a new set of env vars for services, based on RuntimeDirectory=,
- StateDirectory=, LogsDirectory=, CacheDirectory= and ConfigurationDirectory=
- automatically. For example, there could be $RUNTIME_DIRECTORY,
- $STATE_DIRECTORY, $LOGS_DIRECTORY=, $CACHE_DIRECTORY and
- $CONFIGURATION_DIRECTORY or so. This could be useful to write services that
- can adapt to varying directories for these purposes. Special care has to be
- taken if multiple dirs are configured. Maybe avoid setting the env vars in
- that case?
-
* expose IO accounting data on the bus, show it in systemd-run --wait and log
about it in the resource log message
* hostnamectl: show root image uuid
-* sysfs set api in libudev is not const
-
* Find a solution for SMACK capabilities stuff:
http://lists.freedesktop.org/archives/systemd-devel/2014-December/026188.html
3. **Hybrid** — this is a hybrid between the unified and legacy mode. It's set
up mostly like legacy, except that there's also an additional hierarchy
-`/sys/fs/cgroup/unified/` that contains the cgroupsv2 hierarchy. In this mode
-compatibility with cgroupsv1 is retained while some cgroupsv2 features are
-available too. This mode is a stopgap. Don't bother with this too much unless
-you have too much free time.
+`/sys/fs/cgroup/unified/` that contains the cgroupsv2 hierarchy. (Note that in
+this mode the unified hierarchy won't have controllers attached, the
+controllers are all mounted as separate hierarchies as in legacy mode,
+i.e. `/sys/fs/cgroup/unified/` is purely and exclusively about core cgroupsv2
+functionality and not about resource management.) In this mode compatibility
+with cgroupsv1 is retained while some cgroupsv2 features are available
+too. This mode is a stopgap. Don't bother with this too much unless you have
+too much free time.
To say this clearly, legacy and hybrid modes have no future. If you develop
software today and don't focus on the unified mode, then you are writing
python infra/helper.py run_fuzzer systemd fuzz-foo
If you find a bug that impacts the security of systemd, please follow the
-guidance in .github/CONTRIBUTING.md on how to report a security vulnerability.
+guidance in CONTRIBUTING.md on how to report a security vulnerability.
For more details on building fuzzers and integrating with OSS-Fuzz, visit:
sensor:modalias:acpi:KIOX000A*:dmi:*:svnTECLAST:pnX98PlusII:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
+# Teclast X98 Plus I (A5C6), generic DMI strings, match entire dmi modalias inc. bios-date
+sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/2015:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnCherryTrailCR:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:
+ ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
+
#########################################
# Trekstor
#########################################
mouse:usb:v04b3p3107:name:*
MOUSE_DPI=800@125
+##########################################
+# Kensington
+##########################################
+
+# Kensington Expert Mouse trackball
+mouse:usb:v047dp1020:*Kensington Expert Mouse*
+ ID_INPUT_TRACKBALL=1
+
##########################################
# Lenovo
##########################################
############################################################
parse_hwdb_py = find_program('parse_hwdb.py')
-test('parse-hwdb',
- parse_hwdb_py,
- timeout : 90)
+if want_tests != 'false'
+ test('parse-hwdb',
+ parse_hwdb_py,
+ timeout : 90)
+endif
############################################################
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-pager" />
+ <xi:include href="standard-options.xml" xpointer="no-legend" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
<listitem><para>These options take a whitespace-separated list of directory names. The specified directory
names must be relative, and may not include <literal>..</literal>. If set, one or more
directories by the specified names will be created (including their parents) below the locations
- defined in the following table, when the unit is started.</para>
+ defined in the following table, when the unit is started. Also, the corresponding environment variable
+ is defined with the full path of directories. If multiple directories are set, then int the environment variable
+ the paths are concatenated with colon (<literal>:</literal>).</para>
<table>
- <title>Automatic directory creation</title>
- <tgroup cols='3'>
+ <title>Automatic directory creation and environment variables</title>
+ <tgroup cols='4'>
<thead>
<row>
<entry>Locations</entry>
<entry>for system</entry>
<entry>for users</entry>
+ <entry>Environment variable</entry>
</row>
</thead>
<tbody>
<entry><varname>RuntimeDirectory=</varname></entry>
<entry><filename>/run</filename></entry>
<entry><varname>$XDG_RUNTIME_DIR</varname></entry>
+ <entry><varname>$RUNTIME_DIRECTORY</varname></entry>
</row>
<row>
<entry><varname>StateDirectory=</varname></entry>
<entry><filename>/var/lib</filename></entry>
<entry><varname>$XDG_CONFIG_HOME</varname></entry>
+ <entry><varname>$STATE_DIRECTORY</varname></entry>
</row>
<row>
<entry><varname>CacheDirectory=</varname></entry>
<entry><filename>/var/cache</filename></entry>
<entry><varname>$XDG_CACHE_HOME</varname></entry>
+ <entry><varname>$CACHE_DIRECTORY</varname></entry>
</row>
<row>
<entry><varname>LogsDirectory=</varname></entry>
<entry><filename>/var/log</filename></entry>
<entry><varname>$XDG_CONFIG_HOME</varname><filename>/log</filename></entry>
+ <entry><varname>$LOGS_DIRECTORY</varname></entry>
</row>
<row>
<entry><varname>ConfigurationDirectory=</varname></entry>
<entry><filename>/etc</filename></entry>
<entry><varname>$XDG_CONFIG_HOME</varname></entry>
+ <entry><varname>$CONFIGURATION_DIRECTORY</varname></entry>
</row>
</tbody>
</tgroup>
<filename>/run/foo/bar</filename>, and <filename>/run/baz</filename>. The directories
<filename>/run/foo/bar</filename> and <filename>/run/baz</filename> except <filename>/run/foo</filename> are
owned by the user and group specified in <varname>User=</varname> and <varname>Group=</varname>, and removed
- when the service is stopped.</para></listitem>
+ when the service is stopped.</para>
+
+ <para>Example: if a system service unit has the following,
+ <programlisting>RuntimeDirectory=foo/bar
+StateDirectory=aaa/bbb ccc</programlisting>
+ then the environment variable <literal>RUNTIME_DIRECTORY</literal> is set with <literal>/run/foo/bar</literal>, and
+ <literal>STATE_DIRECTORY</literal> is set with <literal>/var/lib/aaa/bbb:/var/lib/ccc</literal>.</para></listitem>
</varlistentry>
<varlistentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ForceDHCPv6PDOtherInformation=</varname></term>
+ <listitem>
+ <para>A boolean that enforces DHCPv6 stateful mode when the 'Other information' bit is set in
+ Router Advertisement messages. By default setting only the 'O' bit in Router Advertisements
+ makes DHCPv6 request network information in a stateless manner using a two-message Information
+ Request and Information Reply message exchange.
+ <ulink url="https://tools.ietf.org/html/rfc7084">RFC 7084</ulink>, requirement WPD-4, updates
+ this behavior for a Customer Edge router so that stateful DHCPv6 Prefix Delegation is also
+ requested when only the 'O' bit is set in Router Advertisements. This option enables such a CE
+ behavior as it is impossible to automatically distinguish the intention of the 'O' bit otherwise.
+ By default this option is set to 'false', enable it if no prefixes are delegated when the device
+ should be acting as a CE router.</para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
check_compilation_sh = find_program('tools/meson-check-compilation.sh')
meson_build_sh = find_program('tools/meson-build.sh')
-if get_option('tests') != 'false'
- cxx = find_program('c++', required : false)
- if cxx.found()
- # Used only for tests
- add_languages('cpp')
- endif
+want_tests = get_option('tests')
+slow_tests = want_tests != 'false' and get_option('slow-tests')
+install_tests = get_option('install-tests')
+
+cxx = find_program('c++', required : false)
+if cxx.found()
+ # Used only for tests
+ add_languages('cpp')
endif
want_ossfuzz = get_option('oss-fuzz')
if want_importd != 'false'
have = (conf.get('HAVE_LIBCURL') == 1 and
conf.get('HAVE_ZLIB') == 1 and
- conf.get('HAVE_BZIP2') == 1 and
conf.get('HAVE_XZ') == 1 and
conf.get('HAVE_GCRYPT') == 1)
if want_importd == 'true' and not have
conf.set10('ENABLE_TIMEDATECTL', get_option('timedated') or get_option('timesyncd'))
-want_tests = get_option('tests')
-install_tests = get_option('install-tests')
-slow_tests = get_option('slow-tests')
tests = []
fuzzers = []
test_dlopen_c,
include_directories : includes,
link_with : [libbasic],
- dependencies : [libdl])
+ dependencies : [libdl],
+ build_by_default : want_tests != 'false')
foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
['systemd', 'ENABLE_NSS_SYSTEMD'],
'rm $DESTDIR@0@/libnss_@1@.so'
.format(rootlibdir, module))
- test('dlopen-nss_' + module,
- test_dlopen,
- args : [nss.full_path()]) # path to dlopen must include a slash
+ if want_tests != 'false'
+ test('dlopen-nss_' + module,
+ test_dlopen,
+ # path to dlopen must include a slash
+ args : nss.full_path())
+ endif
endif
endforeach
install : true,
install_dir : pamlibdir)
- test('dlopen-pam_systemd',
- test_dlopen,
- args : [pam_systemd.full_path()]) # path to dlopen must include a slash
+ if want_tests != 'false'
+ test('dlopen-pam_systemd',
+ test_dlopen,
+ # path to dlopen must include a slash
+ args : pam_systemd.full_path())
+ endif
endif
endif
install_dir : rootbindir)
public_programs += exe
- test('test-systemd-tmpfiles',
- test_systemd_tmpfiles_py,
- args : exe.full_path())
- # https://github.com/mesonbuild/meson/issues/2681
+ if want_tests != 'false'
+ test('test-systemd-tmpfiles',
+ test_systemd_tmpfiles_py,
+ # https://github.com/mesonbuild/meson/issues/2681
+ args : exe.full_path())
+ endif
endif
if conf.get('ENABLE_HWDB') == 1
exe = executable('systemd-udevd',
systemd_udevd_sources,
include_directories : includes,
- c_args : ['-DLOG_REALM=LOG_REALM_UDEV'],
+ c_args : '-DLOG_REALM=LOG_REALM_UDEV',
link_with : [libudev_core,
libsystemd_network,
libudev_static],
exe = executable('udevadm',
udevadm_sources,
- c_args : ['-DLOG_REALM=LOG_REALM_UDEV'],
+ c_args : '-DLOG_REALM=LOG_REALM_UDEV',
include_directories : includes,
link_with : [libudev_core,
libsystemd_network,
timeout = type.split('=')[1].to_int()
type = ''
endif
- if want_tests == 'false'
- message('Not compiling @0@ because tests is set to false'.format(name))
- elif condition == '' or conf.get(condition) == 1
+
+ if condition == '' or conf.get(condition) == 1
exe = executable(
name,
sources,
link_with : link_with,
dependencies : dependencies,
c_args : defs,
+ build_by_default : want_tests != 'false',
install_rpath : rootlibexecdir,
install : install_tests,
install_dir : join_paths(testsdir, type))
message('@0@ is a manual test'.format(name))
elif type == 'unsafe' and want_tests != 'unsafe'
message('@0@ is an unsafe test'.format(name))
- else
+ elif want_tests != 'false'
test(name, exe,
env : test_env,
timeout : timeout)
test_libsystemd_sym_c,
include_directories : includes,
link_with : [libsystemd],
+ build_by_default : want_tests != 'false',
install : install_tests,
install_dir : testsdir)
-test('test-libsystemd-sym', exe)
+if want_tests != 'false'
+ test('test-libsystemd-sym', exe)
+endif
exe = executable(
'test-libsystemd-static-sym',
link_with : [install_libsystemd_static],
dependencies : [threads], # threads is already included in dependencies on the library,
# but does not seem to get propagated. Add here as a work-around.
- build_by_default : static_libsystemd_pic,
+ build_by_default : want_tests != 'false' and static_libsystemd_pic,
install : install_tests and static_libsystemd_pic,
install_dir : testsdir)
-if static_libsystemd_pic
+if want_tests != 'false' and static_libsystemd_pic
test('test-libsystemd-static-sym', exe)
endif
'test-libudev-sym',
test_libudev_sym_c,
include_directories : includes,
- c_args : ['-Wno-deprecated-declarations'],
+ c_args : '-Wno-deprecated-declarations',
link_with : [libudev],
+ build_by_default : want_tests != 'false',
install : install_tests,
install_dir : testsdir)
-test('test-libudev-sym', exe)
+if want_tests != 'false'
+ test('test-libudev-sym', exe)
+endif
exe = executable(
'test-libudev-static-sym',
test_libudev_sym_c,
include_directories : includes,
- c_args : ['-Wno-deprecated-declarations'],
+ c_args : '-Wno-deprecated-declarations',
link_with : [install_libudev_static],
- build_by_default : static_libudev_pic,
+ build_by_default : want_tests != 'false' and static_libudev_pic,
install : install_tests and static_libudev_pic,
install_dir : testsdir)
-if static_libudev_pic
+if want_tests != 'false' and static_libudev_pic
test('test-libudev-static-sym', exe)
endif
foreach exec : public_programs
name = exec.full_path().split('/')[-1]
- test('check-help-' + name,
- meson_check_help,
- args : [exec.full_path()])
+ if want_tests != 'false'
+ test('check-help-' + name,
+ meson_check_help,
+ args : exec.full_path())
+ endif
endforeach
############################################################
#define SCALE_X (0.1 / 1000.0) /* pixels per us */
#define SCALE_Y (20.0)
-#define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0))
-
#define svg(...) printf(__VA_ARGS__)
#define svg_bar(class, x1, x2, y) \
return 0;
}
-static int compare_unit_time(const void *a, const void *b) {
- return compare(((struct unit_times *)b)->time,
- ((struct unit_times *)a)->time);
+static int compare_unit_time(const struct unit_times *a, const struct unit_times *b) {
+ return CMP(b->time, a->time);
}
-static int compare_unit_start(const void *a, const void *b) {
- return compare(((struct unit_times *)a)->activating,
- ((struct unit_times *)b)->activating);
+static int compare_unit_start(const struct unit_times *a, const struct unit_times *b) {
+ return CMP(a->activating, b->activating);
}
static void unit_times_free(struct unit_times *t) {
if (n <= 0)
return n;
- qsort(times, n, sizeof(struct unit_times), compare_unit_start);
+ typesafe_qsort(times, n, compare_unit_start);
width = SCALE_X * (boot->firmware_time + boot->finish_time);
if (width < 800.0)
static Hashmap *unit_times_hashmap;
-static int list_dependencies_compare(const void *_a, const void *_b) {
- const char **a = (const char**) _a, **b = (const char**) _b;
+static int list_dependencies_compare(char * const *a, char * const *b) {
usec_t usa = 0, usb = 0;
struct unit_times *times;
if (times)
usb = times->activated;
- return usb - usa;
+ return CMP(usb, usa);
}
static bool times_in_range(const struct unit_times *times, const struct boot_times *boot) {
if (r < 0)
return r;
- qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
+ typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
r = acquire_boot_times(bus, &boot);
if (r < 0)
if (n <= 0)
return n;
- qsort(times, n, sizeof(struct unit_times), compare_unit_time);
+ typesafe_qsort(times, n, compare_unit_time);
(void) pager_open(arg_no_pager, false);
#include "alloc-util.h"
#include "def.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
#include "escape.h"
#include "fileio.h"
#include "mkdir.h"
if (r < 0)
return r;
- if (!streq_ptr(a_val, b_val))
+ if (!streq(a_val, b_val))
return false;
r = sd_device_get_sysname(a, &a_val);
if (r < 0)
return r;
- return streq_ptr(a_val, b_val);
+ return streq(a_val, b_val);
}
static int validate_device(sd_device *device) {
if (r < 0)
return r;
- r = device_enumerator_scan_devices(enumerate);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(enumerate, other) {
+ FOREACH_DEVICE(enumerate, other) {
const char *other_subsystem;
sd_device *other_parent;
int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
struct btrfs_ioctl_vol_args args = {};
- char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")];
+ char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")], q[DEV_NUM_PATH_MAX];
_cleanup_free_ char *backing = NULL;
_cleanup_close_ int loop_fd = -1, backing_fd = -1;
struct stat st;
if (grow_only && new_size < (uint64_t) st.st_size)
return -EINVAL;
- xsprintf_sys_block_path(p, NULL, dev);
- loop_fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY);
+ xsprintf_dev_num_path(q, "block", dev);
+ loop_fd = open(q, O_RDWR|O_CLOEXEC|O_NOCTTY);
if (loop_fd < 0)
return -errno;
return mfree(c);
}
-static int component_compare(const void *_a, const void *_b) {
- CalendarComponent * const *a = _a, * const *b = _b;
-
- if ((*a)->start < (*b)->start)
- return -1;
- if ((*a)->start > (*b)->start)
- return 1;
+static int component_compare(CalendarComponent * const *a, CalendarComponent * const *b) {
+ int r;
- if ((*a)->stop < (*b)->stop)
- return -1;
- if ((*a)->stop > (*b)->stop)
- return 1;
+ r = CMP((*a)->start, (*b)->start);
+ if (r != 0)
+ return r;
- if ((*a)->repeat < (*b)->repeat)
- return -1;
- if ((*a)->repeat > (*b)->repeat)
- return 1;
+ r = CMP((*a)->stop, (*b)->stop);
+ if (r != 0)
+ return r;
- return 0;
+ return CMP((*a)->repeat, (*b)->repeat);
}
static void normalize_chain(CalendarComponent **c) {
for (i = *c; i; i = i->next)
*(j++) = i;
- qsort(b, n, sizeof(CalendarComponent*), component_compare);
+ typesafe_qsort(b, n, component_compare);
b[n-1]->next = NULL;
next = b[n-1];
return 0;
}
-static int base_cmp(const void *a, const void *b) {
- const char *s1, *s2;
-
- s1 = *(char * const *)a;
- s2 = *(char * const *)b;
- return strcmp(basename(s1), basename(s2));
+static int base_cmp(char * const *a, char * const *b) {
+ return strcmp(basename(*a), basename(*b));
}
static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, unsigned flags, char **dirs) {
if (!files)
return -ENOMEM;
- qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp);
+ typesafe_qsort(files, hashmap_size(fh), base_cmp);
*strv = files;
return 0;
for (i = 0; i < strv_length(*strv); i++) {
int c;
- c = base_cmp(*strv + i, &path);
+ c = base_cmp((char* const*) *strv + i, (char* const*) &path);
if (c == 0) {
char **dir;
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
void* const callback_args[_STDOUT_CONSUME_MAX],
int output_fd,
- char *argv[]) {
+ char *argv[],
+ char *envp[]) {
_cleanup_hashmap_free_free_ Hashmap *pids = NULL;
_cleanup_strv_free_ char **paths = NULL;
- char **path;
+ char **path, **e;
int r;
/* We fork this all off from a child process so that we can somewhat cleanly make
if (timeout != USEC_INFINITY)
alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC));
+ STRV_FOREACH(e, envp)
+ putenv(*e);
+
STRV_FOREACH(path, paths) {
_cleanup_free_ char *t = NULL;
_cleanup_close_ int fd = -1;
usec_t timeout,
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
void* const callback_args[_STDOUT_CONSUME_MAX],
- char *argv[]) {
+ char *argv[],
+ char *envp[]) {
char **dirs = (char**) directories;
_cleanup_close_ int fd = -1;
if (r < 0)
return r;
if (r == 0) {
- r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv);
+ r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv, envp);
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
usec_t timeout,
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
void* const callback_args[_STDOUT_CONSUME_MAX],
- char *argv[]);
+ char *argv[],
+ char *envp[]);
extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
return 0;
}
-static int table_data_compare(const void *x, const void *y, void *userdata) {
- const size_t *a = x, *b = y;
- Table *t = userdata;
+static int table_data_compare(const size_t *a, const size_t *b, Table *t) {
size_t i;
int r;
}
/* Order identical lines by the order there were originally added in */
- if (*a < *b)
- return -1;
- if (*a > *b)
- return 1;
-
- return 0;
+ return CMP(*a, *b);
}
static const char *table_data_format(TableData *d) {
for (i = 0; i < n_rows; i++)
sorted[i] = i * t->n_columns;
- qsort_r_safe(sorted, n_rows, sizeof(size_t), table_data_compare, t);
+ typesafe_qsort_r(sorted, n_rows, table_data_compare, t);
}
if (t->display_map)
return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
}
-int symlink_idempotent(const char *from, const char *to) {
+int symlink_idempotent(const char *from, const char *to, bool make_relative) {
+ _cleanup_free_ char *relpath = NULL;
int r;
assert(from);
assert(to);
+ if (make_relative) {
+ _cleanup_free_ char *parent = NULL;
+
+ parent = dirname_malloc(to);
+ if (!parent)
+ return -ENOMEM;
+
+ r = path_make_relative(parent, from, &relpath);
+ if (r < 0)
+ return r;
+
+ from = relpath;
+ }
+
if (symlink(from, to) < 0) {
_cleanup_free_ char *p = NULL;
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
-int symlink_idempotent(const char *from, const char *to);
+int symlink_idempotent(const char *from, const char *to, bool make_relative);
int symlink_atomic(const char *from, const char *to);
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
return 0;
}
+
+int dev_is_devtmpfs(void) {
+ _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+ char line[LINE_MAX], *e;
+ int mount_id, r;
+
+ r = path_get_mnt_id("/dev", &mount_id);
+ if (r < 0)
+ return r;
+
+ proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+ if (!proc_self_mountinfo)
+ return -errno;
+
+ (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
+
+ FOREACH_LINE(line, proc_self_mountinfo, return -errno) {
+ int mid;
+
+ if (sscanf(line, "%i", &mid) != 1)
+ continue;
+
+ if (mid != mount_id)
+ continue;
+
+ e = strstr(line, " - ");
+ if (!e)
+ continue;
+
+ /* accept any name that starts with the currently expected type */
+ if (startswith(e + 3, "devtmpfs"))
+ return true;
+ }
+
+ return false;
+}
unsigned long mount_flags,
unsigned long *ret_mount_flags,
char **ret_remaining_options);
+
+int dev_is_devtmpfs(void);
#endif
}
-int pid_compare_func(const void *a, const void *b) {
- const pid_t *p = a, *q = b;
-
+int pid_compare_func(const pid_t *a, const pid_t *b) {
/* Suitable for usage in qsort() */
- return CMP(*p, *q);
+ return CMP(*a, *b);
}
int ioprio_parse_priority(const char *s, int *ret) {
void valgrind_summary_hack(void);
-int pid_compare_func(const void *a, const void *b);
+int pid_compare_func(const pid_t *a, const pid_t *b);
static inline bool nice_is_valid(int n) {
return n >= PRIO_MIN && n < PRIO_MAX;
/* lookup child node */
search.c = c;
- child = bsearch_safe(&search, node->children, node->children_count,
- sizeof(struct strbuf_child_entry),
- (__compar_fn_t) strbuf_children_cmp);
+ child = typesafe_bsearch(&search, node->children, node->children_count, strbuf_children_cmp);
if (!child)
break;
node = child->child;
return (int) n;
}
-char *strv_join(char **l, const char *separator) {
+char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
char *r, *e;
char **s;
- size_t n, k;
+ size_t n, k, m;
if (!separator)
separator = " ";
k = strlen(separator);
+ m = strlen_ptr(prefix);
n = 0;
STRV_FOREACH(s, l) {
if (s != l)
n += k;
- n += strlen(*s);
+ n += m + strlen(*s);
}
r = new(char, n+1);
if (s != l)
e = stpcpy(e, separator);
+ if (prefix)
+ e = stpcpy(e, prefix);
+
e = stpcpy(e, *s);
}
return false;
}
-static int str_compare(const void *_a, const void *_b) {
- const char **a = (const char**) _a, **b = (const char**) _b;
-
+static int str_compare(char * const *a, char * const *b) {
return strcmp(*a, *b);
}
char **strv_sort(char **l) {
- qsort_safe(l, strv_length(l), sizeof(char*), str_compare);
+ typesafe_qsort(l, strv_length(l), str_compare);
return l;
}
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
-char *strv_join(char **l, const char *separator);
+char *strv_join_prefix(char **l, const char *separator, const char *prefix);
+static inline char *strv_join(char **l, const char *separator) {
+ return strv_join_prefix(l, separator, NULL);
+}
char **strv_parse_nulstr(const char *s, size_t l);
char **strv_split_nulstr(const char *s);
/* hey glibc, APIs with callbacks without a user pointer are so useless */
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
- int (*compar) (const void *, const void *, void *), void *arg) {
+ __compar_d_fn_t compar, void *arg) {
size_t l, u, idx;
const void *p;
int comparison;
void in_initrd_force(bool value);
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
- int (*compar) (const void *, const void *, void *),
- void *arg);
+ __compar_d_fn_t compar, void *arg);
+
+#define typesafe_bsearch_r(k, b, n, func, userdata) \
+ ({ \
+ const typeof(b[0]) *_k = k; \
+ int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
+ xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
+ })
/**
* Normal bsearch requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
static inline void* bsearch_safe(const void *key, const void *base,
- size_t nmemb, size_t size, comparison_fn_t compar) {
+ size_t nmemb, size_t size, __compar_fn_t compar) {
if (nmemb <= 0)
return NULL;
return bsearch(key, base, nmemb, size, compar);
}
+#define typesafe_bsearch(k, b, n, func) \
+ ({ \
+ const typeof(b[0]) *_k = k; \
+ int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
+ bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
+ })
+
/**
* Normal qsort requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
-static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
+static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
if (nmemb <= 1)
return;
qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
})
-static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void *userdata) {
+static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
if (nmemb <= 1)
return;
qsort_r(base, nmemb, size, compar, userdata);
}
+#define typesafe_qsort_r(p, n, func, userdata) \
+ ({ \
+ int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
+ qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
+ })
+
/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
static inline void memcpy_safe(void *dst, const void *src, size_t n) {
if (n == 0)
assert(argc >= optind);
left = argc - optind;
- name = argv[optind];
+ argv += optind;
+ optind = 0;
+ name = argv[0];
for (i = 0;; i++) {
bool found;
}
if (name)
- return verb->dispatch(left, argv + optind, userdata);
+ return verb->dispatch(left, argv, userdata);
else {
char* fake[2] = {
(char*) verb->verb,
#include "alloc-util.h"
#include "dirent-util.h"
+#include "def.h"
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
}
static int detect_vm_uml(void) {
- _cleanup_free_ char *cpuinfo_contents = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
int r;
/* Detect User-Mode Linux by reading /proc/cpuinfo */
- r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
- if (r == -ENOENT) {
- log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
- return VIRTUALIZATION_NONE;
+ f = fopen("/proc/cpuinfo", "re");
+ if (!f) {
+ if (errno == ENOENT) {
+ log_debug("/proc/cpuinfo not found, assuming no UML virtualization.");
+ return VIRTUALIZATION_NONE;
+ }
+ return -errno;
}
- if (r < 0)
- return r;
- if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
- log_debug("UML virtualization found in /proc/cpuinfo");
- return VIRTUALIZATION_UML;
+ for (;;) {
+ _cleanup_free_ char *line = NULL;
+ const char *t;
+
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ t = startswith(line, "vendor_id\t: ");
+ if (t) {
+ if (startswith(t, "User Mode Linux")) {
+ log_debug("UML virtualization found in /proc/cpuinfo");
+ return VIRTUALIZATION_UML;
+ }
+
+ break;
+ }
}
log_debug("UML virtualization not found in /proc/cpuinfo.");
efi_ldflags + tuple[2] +
['-lefi', '-lgnuefi', libgcc_file_name])
- test('no-undefined-symbols-' + tuple[0],
- no_undefined_symbols,
- args : [so])
+ if want_tests != 'false'
+ test('no-undefined-symbols-' + tuple[0],
+ no_undefined_symbols,
+ args : [so])
+ endif
stub = custom_target(
tuple[1],
string_hash_func(m->interface, state);
}
-static int member_compare_func(const void *a, const void *b) {
- const Member *x = a, *y = b;
+static int member_compare_func(const Member *x, const Member *y) {
int d;
assert(x);
return strcmp_ptr(x->name, y->name);
}
-static int member_compare_funcp(const void *a, const void *b) {
- const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
-
- return member_compare_func(*x, *y);
+static int member_compare_funcp(Member * const *a, Member * const *b) {
+ return member_compare_func(*a, *b);
}
static void member_free(Member *m) {
static int introspect(int argc, char **argv, void *userdata) {
static const struct hash_ops member_hash_ops = {
.hash = member_hash_func,
- .compare = member_compare_func,
+ .compare = (__compar_fn_t) member_compare_func,
};
static const XMLIntrospectOps ops = {
if (result_width > 40)
result_width = 40;
- qsort(sorted, k, sizeof(Member*), member_compare_funcp);
+ typesafe_qsort(sorted, k, member_compare_funcp);
if (arg_legend) {
printf("%-*s %-*s %-*s %-*s %s\n",
return 0;
}
-static int group_compare(const void*a, const void *b) {
- const Group *x = *(Group**)a, *y = *(Group**)b;
+static int group_compare(Group * const *a, Group * const *b) {
+ const Group *x = *a, *y = *b;
+ int r;
if (arg_order != ORDER_TASKS || arg_recursive) {
/* Let's make sure that the parent is always before
case ORDER_CPU:
if (arg_cpu_type == CPU_PERCENT) {
if (x->cpu_valid && y->cpu_valid) {
- if (x->cpu_fraction > y->cpu_fraction)
- return -1;
- else if (x->cpu_fraction < y->cpu_fraction)
- return 1;
+ r = CMP(y->cpu_fraction, x->cpu_fraction);
+ if (r != 0)
+ return r;
} else if (x->cpu_valid)
return -1;
else if (y->cpu_valid)
return 1;
} else {
- if (x->cpu_usage > y->cpu_usage)
- return -1;
- else if (x->cpu_usage < y->cpu_usage)
- return 1;
+ r = CMP(y->cpu_usage, x->cpu_usage);
+ if (r != 0)
+ return r;
}
break;
case ORDER_TASKS:
if (x->n_tasks_valid && y->n_tasks_valid) {
- if (x->n_tasks > y->n_tasks)
- return -1;
- else if (x->n_tasks < y->n_tasks)
- return 1;
+ r = CMP(y->n_tasks, x->n_tasks);
+ if (r != 0)
+ return r;
} else if (x->n_tasks_valid)
return -1;
else if (y->n_tasks_valid)
case ORDER_MEMORY:
if (x->memory_valid && y->memory_valid) {
- if (x->memory > y->memory)
- return -1;
- else if (x->memory < y->memory)
- return 1;
+ r = CMP(y->memory, x->memory);
+ if (r != 0)
+ return r;
} else if (x->memory_valid)
return -1;
else if (y->memory_valid)
case ORDER_IO:
if (x->io_valid && y->io_valid) {
- if (x->io_input_bps + x->io_output_bps > y->io_input_bps + y->io_output_bps)
- return -1;
- else if (x->io_input_bps + x->io_output_bps < y->io_input_bps + y->io_output_bps)
- return 1;
+ r = CMP(y->io_input_bps + y->io_output_bps, x->io_input_bps + x->io_output_bps);
+ if (r != 0)
+ return r;
} else if (x->io_valid)
return -1;
else if (y->io_valid)
if (g->n_tasks_valid || g->cpu_valid || g->memory_valid || g->io_valid)
array[n++] = g;
- qsort_safe(array, n, sizeof(Group*), group_compare);
+ typesafe_qsort(array, n, group_compare);
/* Find the longest names in one run */
for (j = 0; j < n; j++) {
* b) whether the unified hierarchy is being used
* c) the BPF implementation in the kernel supports BPF LPM TRIE maps, which we require
* d) the BPF implementation in the kernel supports BPF_PROG_TYPE_CGROUP_SKB programs, which we require
- * e) the BPF implementation in the kernel supports the BPF_PROG_ATTACH call, which we require
+ * e) the BPF implementation in the kernel supports the BPF_PROG_DETACH call, which we require
*/
if (supported >= 0)
* is turned off at kernel compilation time. This sucks of course: why does it allow us to create a cgroup BPF
* program if we can't do a thing with it later?
*
- * We detect this case by issuing the BPF_PROG_ATTACH bpf() call with invalid file descriptors: if
+ * We detect this case by issuing the BPF_PROG_DETACH bpf() call with invalid file descriptors: if
* CONFIG_CGROUP_BPF is turned off, then the call will fail early with EINVAL. If it is turned on the
* parameters are validated however, and that'll fail with EBADF then. */
.attach_bpf_fd = -1,
};
- if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) {
+ if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0) {
if (errno != EBADF) {
- log_debug_errno(errno, "Didn't get EBADF from BPF_PROG_ATTACH, BPF firewalling is not supported: %m");
+ log_debug_errno(errno, "Didn't get EBADF from BPF_PROG_DETACH, BPF firewalling is not supported: %m");
return supported = BPF_FIREWALL_UNSUPPORTED;
}
/* YAY! */
} else {
- log_debug("Wut? Kernel accepted our invalid BPF_PROG_ATTACH call? Something is weird, assuming BPF firewalling is broken and hence not supported.");
+ log_debug("Wut? Kernel accepted our invalid BPF_PROG_DETACH call? Something is weird, assuming BPF firewalling is broken and hence not supported.");
return supported = BPF_FIREWALL_UNSUPPORTED;
}
/* So now we know that the BPF program is generally available, let's see if BPF_F_ALLOW_MULTI is also supported
- * (which was added in kernel 4.15). We use a similar logic as before, but this time we use
- * BPF_F_ALLOW_MULTI. Since the flags are checked early in the system call we'll get EINVAL if it's not
- * supported, and EBADF as before if it is available. */
+ * (which was added in kernel 4.15). We use a similar logic as before, but this time we use the BPF_PROG_ATTACH
+ * bpf() call and the BPF_F_ALLOW_MULTI flags value. Since the flags are checked early in the system call we'll
+ * get EINVAL if it's not supported, and EBADF as before if it is available. */
attr = (union bpf_attr) {
.attach_type = BPF_CGROUP_INET_EGRESS,
#include "bus-error.h"
#include "dbus-device.h"
#include "device-private.h"
-#include "device-enumerator-private.h"
#include "device-util.h"
#include "device.h"
#include "libudev-private.h"
goto fail;
}
- r = device_enumerator_scan_devices(e);
- if (r < 0) {
- log_error_errno(r, "Failed to enumerate devices: %m");
- goto fail;
- }
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, dev) {
+ FOREACH_DEVICE(e, dev) {
const char *sysfs;
if (!device_is_ready(dev))
idle_pipe[3] = safe_close(idle_pipe[3]);
}
+static const char *exec_directory_env_name_to_string(ExecDirectoryType t);
+
static int build_environment(
const Unit *u,
const ExecContext *c,
char ***ret) {
_cleanup_strv_free_ char **our_env = NULL;
+ ExecDirectoryType t;
size_t n_env = 0;
char *x;
assert(u);
assert(c);
+ assert(p);
assert(ret);
- our_env = new0(char*, 14);
+ our_env = new0(char*, 14 + _EXEC_DIRECTORY_TYPE_MAX);
if (!our_env)
return -ENOMEM;
our_env[n_env++] = x;
}
+ for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
+ _cleanup_free_ char *pre = NULL, *joined = NULL;
+ const char *n;
+
+ if (!p->prefix[t])
+ continue;
+
+ if (strv_isempty(c->directories[t].paths))
+ continue;
+
+ n = exec_directory_env_name_to_string(t);
+ if (!n)
+ continue;
+
+ pre = strjoin(p->prefix[t], "/");
+ if (!pre)
+ return -ENOMEM;
+
+ joined = strv_join_prefix(c->directories[t].paths, ":", pre);
+ if (!joined)
+ return -ENOMEM;
+
+ x = strjoin(n, "=", joined);
+ if (!x)
+ return -ENOMEM;
+
+ our_env[n_env++] = x;
+ }
+
our_env[n_env++] = NULL;
- assert(n_env <= 12);
+ assert(n_env <= 14 + _EXEC_DIRECTORY_TYPE_MAX);
*ret = TAKE_PTR(our_env);
if (context->dynamic_user &&
!IN_SET(type, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION)) {
- _cleanup_free_ char *private_root = NULL, *relative = NULL, *parent = NULL;
+ _cleanup_free_ char *private_root = NULL;
/* So, here's one extra complication when dealing with DynamicUser=1 units. In that case we
* want to avoid leaving a directory around fully accessible that is owned by a dynamic user
goto fail;
}
- parent = dirname_malloc(p);
- if (!parent) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = path_make_relative(parent, pp, &relative);
- if (r < 0)
- goto fail;
-
/* And link it up from the original place */
- r = symlink_idempotent(relative, p);
+ r = symlink_idempotent(pp, p, true);
if (r < 0)
goto fail;
* that with a special, recognizable error ENOANO. In this case, silently proceeed, but only if exclusively
* sandboxing options were used, i.e. nothing such as RootDirectory= or BindMount= that would result in a
* completely different execution environment. */
- if (r == -ENOANO &&
- n_bind_mounts == 0 && context->n_temporary_filesystems == 0 &&
- !root_dir && !root_image &&
- !context->dynamic_user) {
- log_unit_debug(u, "Failed to set up namespace, assuming containerized execution and ignoring.");
- return 0;
+ if (r == -ENOANO) {
+ if (n_bind_mounts == 0 &&
+ context->n_temporary_filesystems == 0 &&
+ !root_dir && !root_image &&
+ !context->dynamic_user) {
+ log_unit_debug(u, "Failed to set up namespace, assuming containerized execution and ignoring.");
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
}
return r;
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
+static const char* const exec_directory_env_name_table[_EXEC_DIRECTORY_TYPE_MAX] = {
+ [EXEC_DIRECTORY_RUNTIME] = "RUNTIME_DIRECTORY",
+ [EXEC_DIRECTORY_STATE] = "STATE_DIRECTORY",
+ [EXEC_DIRECTORY_CACHE] = "CACHE_DIRECTORY",
+ [EXEC_DIRECTORY_LOGS] = "LOGS_DIRECTORY",
+ [EXEC_DIRECTORY_CONFIGURATION] = "CONFIGURATION_DIRECTORY",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(exec_directory_env_name, ExecDirectoryType);
+
static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
[EXEC_KEYRING_INHERIT] = "inherit",
[EXEC_KEYRING_PRIVATE] = "private",
j->in_gc_queue = true;
}
-static int job_compare(const void *a, const void *b) {
- Job *x = *(Job**) a, *y = *(Job**) b;
-
- if (x->id < y->id)
- return -1;
- if (x->id > y->id)
- return 1;
-
- return 0;
+static int job_compare(Job * const *a, Job * const *b) {
+ return CMP((*a)->id, (*b)->id);
}
static size_t sort_job_list(Job **list, size_t n) {
size_t a, b;
/* Order by numeric IDs */
- qsort_safe(list, n, sizeof(Job*), job_compare);
+ typesafe_qsort(list, n, job_compare);
/* Filter out duplicates */
for (a = 0, b = 0; a < n; a++) {
if (!generator_path_any(paths))
return 0;
- return execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL);
+ return execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, m->environment);
}
static int manager_run_generators(Manager *m) {
RUN_WITH_UMASK(0022)
execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC,
- NULL, NULL, (char**) argv);
+ NULL, NULL, (char**) argv, m->environment);
finish:
lookup_paths_trim_generator(&m->lookup_paths);
}
}
-static int mount_path_compare(const void *a, const void *b) {
- const MountEntry *p = a, *q = b;
+static int mount_path_compare(const MountEntry *a, const MountEntry *b) {
int d;
/* If the paths are not equal, then order prefixes first */
- d = path_compare(mount_entry_path(p), mount_entry_path(q));
+ d = path_compare(mount_entry_path(a), mount_entry_path(b));
if (d != 0)
return d;
/* If the paths are equal, check the mode */
- if (p->mode < q->mode)
- return -1;
- if (p->mode > q->mode)
- return 1;
-
- return 0;
+ return CMP((int) a->mode, (int) b->mode);
}
static int prefix_where_needed(MountEntry *m, size_t n, const char *root_directory) {
t = strjoina("../", bn);
if (symlink(t, sl) < 0)
- log_debug_errno(errno, "Failed to symlink '%s' to '%s': %m", t, sl);
+ log_debug_errno(errno, "Failed to symlink '%s' to '%s', ignoring: %m", t, sl);
return 0;
}
u = umask(0000);
if (!mkdtemp(temporary_mount))
- return -errno;
+ return log_debug_errno(errno, "Failed to create temporary directory '%s': %m", temporary_mount);
dev = strjoina(temporary_mount, "/dev");
(void) mkdir(dev, 0755);
if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
- r = -errno;
+ r = log_debug_errno(errno, "Failed to mount tmpfs on '%s': %m", dev);
goto fail;
}
devpts = strjoina(temporary_mount, "/dev/pts");
(void) mkdir(devpts, 0755);
if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
- r = -errno;
+ r = log_debug_errno(errno, "Failed to bind mount /dev/pts on '%s': %m", devpts);
goto fail;
}
- /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx
- * when /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible
- * thus, in that case make a clone
- *
- * in nspawn and other containers it will be a symlink, in that case make it a symlink
- */
+ /* /dev/ptmx can either be a device node or a symlink to /dev/pts/ptmx.
+ * When /dev/ptmx a device node, /dev/pts/ptmx has 000 permissions making it inaccessible.
+ * Thus, in that case make a clone.
+ * In nspawn and other containers it will be a symlink, in that case make it a symlink. */
r = is_symlink("/dev/ptmx");
- if (r < 0)
+ if (r < 0) {
+ log_debug_errno(r, "Failed to detect whether /dev/ptmx is a symlink or not: %m");
goto fail;
- if (r > 0) {
+ } else if (r > 0) {
devptmx = strjoina(temporary_mount, "/dev/ptmx");
if (symlink("pts/ptmx", devptmx) < 0) {
- r = -errno;
+ r = log_debug_errno(errno, "Failed to create a symlink '%s' to pts/ptmx: %m", devptmx);
goto fail;
}
} else {
(void) mkdir(devshm, 0755);
r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
if (r < 0) {
- r = -errno;
+ r = log_debug_errno(errno, "Failed to bind mount /dev/shm on '%s': %m", devshm);
goto fail;
}
devmqueue = strjoina(temporary_mount, "/dev/mqueue");
(void) mkdir(devmqueue, 0755);
- (void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
+ if (mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL) < 0)
+ log_debug_errno(errno, "Failed to bind mount /dev/mqueue on '%s', ignoring: %m", devmqueue);
devhugepages = strjoina(temporary_mount, "/dev/hugepages");
(void) mkdir(devhugepages, 0755);
- (void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
+ if (mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL) < 0)
+ log_debug_errno(errno, "Failed to bind mount /dev/hugepages on '%s', ignoring: %m", devhugepages);
devlog = strjoina(temporary_mount, "/dev/log");
- (void) symlink("/run/systemd/journal/dev-log", devlog);
+ if (symlink("/run/systemd/journal/dev-log", devlog) < 0)
+ log_debug_errno(errno, "Failed to create a symlink '%s' to /run/systemd/journal/dev-log, ignoring: %m", devlog);
NULSTR_FOREACH(d, devnodes) {
r = clone_device_node(d, temporary_mount, &can_mknod);
goto fail;
}
- dev_setup(temporary_mount, UID_INVALID, GID_INVALID);
+ r = dev_setup(temporary_mount, UID_INVALID, GID_INVALID);
+ if (r < 0)
+ log_debug_errno(r, "Failed to setup basic device tree at '%s', ignoring: %m", temporary_mount);
/* Create the /dev directory if missing. It is more likely to be
* missing when the service is started with RootDirectory. This is
(void) mkdir_p_label(mount_entry_path(m), 0755);
/* Unmount everything in old /dev */
- umount_recursive(mount_entry_path(m), 0);
+ r = umount_recursive(mount_entry_path(m), 0);
+ if (r < 0)
+ log_debug_errno(r, "Failed to unmount directories below '%s', ignoring: %m", mount_entry_path(m));
+
if (mount(dev, mount_entry_path(m), NULL, MS_MOVE, NULL) < 0) {
- r = -errno;
+ r = log_debug_errno(errno, "Failed to move mount point '%s' to '%s': %m", dev, mount_entry_path(m));
goto fail;
}
assert(n_mounts);
assert(mounts || *n_mounts == 0);
- qsort_safe(mounts, *n_mounts, sizeof(MountEntry), mount_path_compare);
+ typesafe_qsort(mounts, *n_mounts, mount_path_compare);
drop_duplicates(mounts, n_mounts);
drop_outside_root(root_directory, mounts, n_mounts);
arguments[0] = NULL;
arguments[1] = arg_verb;
arguments[2] = NULL;
- execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
+ execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
if (can_initrd) {
r = switch_root_initramfs();
STRV_FOREACH(i, s->symlinks) {
(void) mkdir_parents_label(*i, s->directory_mode);
- r = symlink_idempotent(p, *i);
+ r = symlink_idempotent(p, *i, false);
if (r == -EEXIST && s->remove_on_stop) {
/* If there's already something where we want to create the symlink, and the destructive
* again. */
if (unlink(*i) >= 0)
- r = symlink_idempotent(p, *i);
+ r = symlink_idempotent(p, *i, false);
}
if (r < 0)
#include "alloc-util.h"
#include "blockdev-util.h"
#include "def.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fstab-util.h"
if (r < 0)
return r;
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
- _cleanup_free_ MountPoint *lb = NULL;
+ FOREACH_DEVICE(e, d) {
+ _cleanup_free_ char *p = NULL;
const char *dn;
+ MountPoint *lb;
if (sd_device_get_devname(d, &dn) < 0)
continue;
- lb = new0(MountPoint, 1);
+ p = strdup(dn);
+ if (!p)
+ return -ENOMEM;
+
+ lb = new(MountPoint, 1);
if (!lb)
return -ENOMEM;
- r = free_and_strdup(&lb->path, dn);
- if (r < 0)
- return r;
+ *lb = (MountPoint) {
+ .path = TAKE_PTR(p),
+ };
LIST_PREPEND(mount_point, *head, lb);
- lb = NULL;
}
return 0;
if (r < 0)
return r;
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
- _cleanup_free_ MountPoint *m = NULL;
+ FOREACH_DEVICE(e, d) {
+ _cleanup_free_ char *p = NULL;
const char *dn;
+ MountPoint *m;
dev_t devnum;
- if (sd_device_get_devnum(d, &devnum) < 0)
+ if (sd_device_get_devnum(d, &devnum) < 0 ||
+ sd_device_get_devname(d, &dn) < 0)
continue;
- if (sd_device_get_devname(d, &dn) < 0)
- continue;
+ p = strdup(dn);
+ if (!p)
+ return -ENOMEM;
- m = new0(MountPoint, 1);
+ m = new(MountPoint, 1);
if (!m)
return -ENOMEM;
- m->devnum = devnum;
- r = free_and_strdup(&m->path, dn);
- if (r < 0)
- return r;
+ *m = (MountPoint) {
+ .path = TAKE_PTR(p),
+ .devnum = devnum,
+ };
LIST_PREPEND(mount_point, *head, m);
- m = NULL;
}
return 0;
}
static char* disk_description(const char *path) {
-
static const char name_fields[] =
"ID_PART_ENTRY_NAME\0"
"DM_NAME\0"
"ID_MODEL\0";
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
+ const char *i, *name;
struct stat st;
- const char *i;
- int r;
assert(path);
if (!S_ISBLK(st.st_mode))
return NULL;
- r = sd_device_new_from_devnum(&device, 'b', st.st_rdev);
- if (r < 0)
+ if (sd_device_new_from_devnum(&device, 'b', st.st_rdev) < 0)
return NULL;
- NULSTR_FOREACH(i, name_fields) {
- const char *name;
-
- r = sd_device_get_property_value(device, i, &name);
- if (r >= 0 && !isempty(name))
+ NULSTR_FOREACH(i, name_fields)
+ if (sd_device_get_property_value(device, i, &name) >= 0 &&
+ !isempty(name))
return strdup(name);
- }
return NULL;
}
root_directory = true;
}
- r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type);
- if (r >= 0) {
+ if (sd_device_get_property_value(dev, "ID_FS_TYPE", &type) >= 0) {
r = fsck_exists(type);
if (r < 0)
log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s, proceeding: %m", type, device);
#include "log.h"
#include "fileio.h"
#include "fuzz.h"
+#include "tests.h"
/* This is a test driver for the systemd fuzzers that provides main function
* for regression testing outside of oss-fuzz (https://github.com/google/oss-fuzz)
size_t size;
char *name;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
for (i = 1; i < argc; i++) {
_cleanup_free_ char *buf = NULL;
r = sd_device_get_syspath(d, &name);
if (r < 0) {
log_debug_errno(r, "Device %u:%u does not have a name, ignoring: %m", major(devnum), minor(devnum));
- goto not_found;
+ return 0;
}
}
r = sd_device_get_parent(d, &parent);
if (r < 0) {
log_debug_errno(r, "%s: not a partitioned device, ignoring: %m", name);
- goto not_found;
+ return 0;
}
/* Does it have a devtype? */
r = sd_device_get_devtype(parent, &devtype);
if (r < 0) {
log_debug_errno(r, "%s: parent doesn't have a device type, ignoring: %m", name);
- goto not_found;
+ return 0;
}
/* Is this a disk or a partition? We only care for disks... */
if (!streq(devtype, "disk")) {
log_debug("%s: parent isn't a raw disk, ignoring.", name);
- goto not_found;
+ return 0;
}
/* Does it have a device node? */
r = sd_device_get_devname(parent, &node);
if (r < 0) {
log_debug_errno(r, "%s: parent device does not have device node, ignoring: %m", name);
- goto not_found;
+ return 0;
}
log_debug("%s: root device %s.", name, node);
r = sd_device_get_devnum(parent, &pn);
if (r < 0) {
log_debug_errno(r, "%s: parent device is not a proper block device, ignoring: %m", name);
- goto not_found;
+ return 0;
}
fd = open(node, O_RDONLY|O_CLOEXEC|O_NOCTTY);
*ret = fd;
return 1;
-
-not_found:
- *ret = -1;
- return 0;
}
static int enumerate_partitions(dev_t devnum) {
-
_cleanup_close_ int fd = -1;
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
int r, k;
/* SPDX-License-Identifier: LGPL-2.1+ */
-#include <ctype.h>
#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
+
+#include "sd-hwdb.h"
#include "alloc-util.h"
-#include "conf-files.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hwdb-internal.h"
#include "hwdb-util.h"
-#include "label.h"
-#include "mkdir.h"
-#include "path-util.h"
#include "selinux-util.h"
-#include "strbuf.h"
-#include "string-util.h"
-#include "strv.h"
#include "terminal-util.h"
#include "util.h"
#include "verbs.h"
-/*
- * Generic udev properties, key-value database based on modalias strings.
- * Uses a Patricia/radix trie to index all matches for efficient lookup.
- */
-
-static const char *arg_hwdb_bin_dir = "/etc/udev";
-static const char *arg_root = "";
-static bool arg_strict;
-
-static const char * const conf_file_dirs[] = {
- "/etc/udev/hwdb.d",
- UDEVLIBEXECDIR "/hwdb.d",
- NULL
-};
-
-/* in-memory trie objects */
-struct trie {
- struct trie_node *root;
- struct strbuf *strings;
-
- size_t nodes_count;
- size_t children_count;
- size_t values_count;
-};
-
-struct trie_node {
- /* prefix, common part for all children of this node */
- size_t prefix_off;
-
- /* sorted array of pointers to children nodes */
- struct trie_child_entry *children;
- uint8_t children_count;
-
- /* sorted array of key-value pairs */
- struct trie_value_entry *values;
- size_t values_count;
-};
-
-/* children array item with char (0-255) index */
-struct trie_child_entry {
- uint8_t c;
- struct trie_node *child;
-};
-
-/* value array item with key-value pairs */
-struct trie_value_entry {
- size_t key_off;
- size_t value_off;
- size_t filename_off;
- uint32_t line_number;
- uint16_t file_priority;
-};
-
-static int trie_children_cmp(const void *v1, const void *v2) {
- const struct trie_child_entry *n1 = v1;
- const struct trie_child_entry *n2 = v2;
-
- return n1->c - n2->c;
-}
-
-static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
- struct trie_child_entry *child;
-
- /* extend array, add new entry, sort for bisection */
- child = reallocarray(node->children, node->children_count + 1, sizeof(struct trie_child_entry));
- if (!child)
- return -ENOMEM;
-
- node->children = child;
- trie->children_count++;
- node->children[node->children_count].c = c;
- node->children[node->children_count].child = node_child;
- node->children_count++;
- qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
- trie->nodes_count++;
-
- return 0;
-}
-
-static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
- struct trie_child_entry *child;
- struct trie_child_entry search;
-
- search.c = c;
- child = bsearch_safe(&search, node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
- if (child)
- return child->child;
- return NULL;
-}
-
-static void trie_node_cleanup(struct trie_node *node) {
- size_t i;
-
- for (i = 0; i < node->children_count; i++)
- trie_node_cleanup(node->children[i].child);
- free(node->children);
- free(node->values);
- free(node);
-}
-
-static void trie_free(struct trie *trie) {
- if (!trie)
- return;
-
- if (trie->root)
- trie_node_cleanup(trie->root);
-
- strbuf_cleanup(trie->strings);
- free(trie);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct trie*, trie_free);
-
-static int trie_values_cmp(const void *v1, const void *v2, void *arg) {
- const struct trie_value_entry *val1 = v1;
- const struct trie_value_entry *val2 = v2;
- struct trie *trie = arg;
-
- return strcmp(trie->strings->buf + val1->key_off,
- trie->strings->buf + val2->key_off);
-}
-
-static int trie_node_add_value(struct trie *trie, struct trie_node *node,
- const char *key, const char *value,
- const char *filename, uint16_t file_priority, uint32_t line_number) {
- ssize_t k, v, fn;
- struct trie_value_entry *val;
-
- k = strbuf_add_string(trie->strings, key, strlen(key));
- if (k < 0)
- return k;
- v = strbuf_add_string(trie->strings, value, strlen(value));
- if (v < 0)
- return v;
- fn = strbuf_add_string(trie->strings, filename, strlen(filename));
- if (fn < 0)
- return fn;
-
- if (node->values_count) {
- struct trie_value_entry search = {
- .key_off = k,
- .value_off = v,
- };
-
- val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
- if (val) {
- /* At this point we have 2 identical properties on the same match-string.
- * Since we process files in order, we just replace the previous value.
- */
- val->value_off = v;
- val->filename_off = fn;
- val->file_priority = file_priority;
- val->line_number = line_number;
- return 0;
- }
- }
-
- /* extend array, add new entry, sort for bisection */
- val = reallocarray(node->values, node->values_count + 1, sizeof(struct trie_value_entry));
- if (!val)
- return -ENOMEM;
- trie->values_count++;
- node->values = val;
- node->values[node->values_count].key_off = k;
- node->values[node->values_count].value_off = v;
- node->values[node->values_count].filename_off = fn;
- node->values[node->values_count].file_priority = file_priority;
- node->values[node->values_count].line_number = line_number;
- node->values_count++;
- qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
- return 0;
-}
-
-static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
- const char *key, const char *value,
- const char *filename, uint16_t file_priority, uint32_t line_number) {
- size_t i = 0;
- int r = 0;
-
- for (;;) {
- size_t p;
- uint8_t c;
- struct trie_node *child;
-
- for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
- _cleanup_free_ char *s = NULL;
- ssize_t off;
- _cleanup_free_ struct trie_node *new_child = NULL;
-
- if (c == search[i + p])
- continue;
-
- /* split node */
- new_child = new0(struct trie_node, 1);
- if (!new_child)
- return -ENOMEM;
-
- /* move values from parent to child */
- new_child->prefix_off = node->prefix_off + p+1;
- new_child->children = node->children;
- new_child->children_count = node->children_count;
- new_child->values = node->values;
- new_child->values_count = node->values_count;
-
- /* update parent; use strdup() because the source gets realloc()d */
- s = strndup(trie->strings->buf + node->prefix_off, p);
- if (!s)
- return -ENOMEM;
-
- off = strbuf_add_string(trie->strings, s, p);
- if (off < 0)
- return off;
-
- node->prefix_off = off;
- node->children = NULL;
- node->children_count = 0;
- node->values = NULL;
- node->values_count = 0;
- r = node_add_child(trie, node, new_child, c);
- if (r < 0)
- return r;
-
- new_child = NULL; /* avoid cleanup */
- break;
- }
- i += p;
-
- c = search[i];
- if (c == '\0')
- return trie_node_add_value(trie, node, key, value, filename, file_priority, line_number);
-
- child = node_lookup(node, c);
- if (!child) {
- ssize_t off;
-
- /* new child */
- child = new0(struct trie_node, 1);
- if (!child)
- return -ENOMEM;
-
- off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
- if (off < 0) {
- free(child);
- return off;
- }
-
- child->prefix_off = off;
- r = node_add_child(trie, node, child, c);
- if (r < 0) {
- free(child);
- return r;
- }
-
- return trie_node_add_value(trie, child, key, value, filename, file_priority, line_number);
- }
-
- node = child;
- i++;
- }
-}
-
-struct trie_f {
- FILE *f;
- struct trie *trie;
- uint64_t strings_off;
-
- uint64_t nodes_count;
- uint64_t children_count;
- uint64_t values_count;
-};
-
-/* calculate the storage space for the nodes, children arrays, value arrays */
-static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) {
- uint64_t i;
-
- for (i = 0; i < node->children_count; i++)
- trie_store_nodes_size(trie, node->children[i].child);
-
- trie->strings_off += sizeof(struct trie_node_f);
- for (i = 0; i < node->children_count; i++)
- trie->strings_off += sizeof(struct trie_child_entry_f);
- for (i = 0; i < node->values_count; i++)
- trie->strings_off += sizeof(struct trie_value_entry2_f);
-}
-
-static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
- uint64_t i;
- struct trie_node_f n = {
- .prefix_off = htole64(trie->strings_off + node->prefix_off),
- .children_count = node->children_count,
- .values_count = htole64(node->values_count),
- };
- _cleanup_free_ struct trie_child_entry_f *children = NULL;
- int64_t node_off;
-
- if (node->children_count) {
- children = new(struct trie_child_entry_f, node->children_count);
- if (!children)
- return -ENOMEM;
- }
-
- /* post-order recursion */
- for (i = 0; i < node->children_count; i++) {
- int64_t child_off;
-
- child_off = trie_store_nodes(trie, node->children[i].child);
- if (child_off < 0)
- return child_off;
-
- children[i] = (struct trie_child_entry_f) {
- .c = node->children[i].c,
- .child_off = htole64(child_off),
- };
- }
-
- /* write node */
- node_off = ftello(trie->f);
- fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
- trie->nodes_count++;
-
- /* append children array */
- if (node->children_count) {
- fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
- trie->children_count += node->children_count;
- }
-
- /* append values array */
- for (i = 0; i < node->values_count; i++) {
- struct trie_value_entry2_f v = {
- .key_off = htole64(trie->strings_off + node->values[i].key_off),
- .value_off = htole64(trie->strings_off + node->values[i].value_off),
- .filename_off = htole64(trie->strings_off + node->values[i].filename_off),
- .line_number = htole32(node->values[i].line_number),
- .file_priority = htole16(node->values[i].file_priority),
- };
-
- fwrite(&v, sizeof(struct trie_value_entry2_f), 1, trie->f);
- }
- trie->values_count += node->values_count;
+static const char *arg_hwdb_bin_dir = NULL;
+static const char *arg_root = NULL;
+static bool arg_strict = false;
- return node_off;
+static int verb_query(int argc, char *argv[], void *userdata) {
+ return hwdb_query(argv[1]);
}
-static int trie_store(struct trie *trie, const char *filename) {
- struct trie_f t = {
- .trie = trie,
- };
- _cleanup_free_ char *filename_tmp = NULL;
- int64_t pos;
- int64_t root_off;
- int64_t size;
- struct trie_header_f h = {
- .signature = HWDB_SIG,
- .tool_version = htole64(atoi(PACKAGE_VERSION)),
- .header_size = htole64(sizeof(struct trie_header_f)),
- .node_size = htole64(sizeof(struct trie_node_f)),
- .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
- .value_entry_size = htole64(sizeof(struct trie_value_entry2_f)),
- };
- int r;
-
- /* calculate size of header, nodes, children entries, value entries */
- t.strings_off = sizeof(struct trie_header_f);
- trie_store_nodes_size(&t, trie->root);
-
- r = fopen_temporary(filename, &t.f, &filename_tmp);
- if (r < 0)
- return r;
- fchmod(fileno(t.f), 0444);
-
- /* write nodes */
- if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
- goto error_fclose;
-
- root_off = trie_store_nodes(&t, trie->root);
- h.nodes_root_off = htole64(root_off);
- pos = ftello(t.f);
- h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
-
- /* write string buffer */
- fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
- h.strings_len = htole64(trie->strings->len);
-
- /* write header */
- size = ftello(t.f);
- h.file_size = htole64(size);
- if (fseeko(t.f, 0, SEEK_SET) < 0)
- goto error_fclose;
- fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
-
- if (ferror(t.f))
- goto error_fclose;
- if (fflush(t.f) < 0)
- goto error_fclose;
- if (fsync(fileno(t.f)) < 0)
- goto error_fclose;
- if (rename(filename_tmp, filename) < 0)
- goto error_fclose;
-
- /* write succeeded */
- fclose(t.f);
-
- log_debug("=== trie on-disk ===");
- log_debug("size: %8"PRIi64" bytes", size);
- log_debug("header: %8zu bytes", sizeof(struct trie_header_f));
- log_debug("nodes: %8"PRIu64" bytes (%8"PRIu64")",
- t.nodes_count * sizeof(struct trie_node_f), t.nodes_count);
- log_debug("child pointers: %8"PRIu64" bytes (%8"PRIu64")",
- t.children_count * sizeof(struct trie_child_entry_f), t.children_count);
- log_debug("value pointers: %8"PRIu64" bytes (%8"PRIu64")",
- t.values_count * sizeof(struct trie_value_entry2_f), t.values_count);
- log_debug("string store: %8zu bytes", trie->strings->len);
- log_debug("strings start: %8"PRIu64, t.strings_off);
- return 0;
-
- error_fclose:
- r = -errno;
- fclose(t.f);
- unlink(filename_tmp);
- return r;
-}
-
-static int insert_data(struct trie *trie, char **match_list, char *line,
- const char *filename, uint16_t file_priority, uint32_t line_number) {
- char *value, **entry;
-
- assert(line[0] == ' ');
-
- value = strchr(line, '=');
- if (!value)
- return log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
- "Key-value pair expected but got \"%s\", ignoring", line);
-
- value[0] = '\0';
- value++;
-
- /* Replace multiple leading spaces by a single space */
- while (isblank(line[0]) && isblank(line[1]))
- line++;
-
- if (isempty(line + 1) || isempty(value))
- return log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
- "Empty %s in \"%s=%s\", ignoring",
- isempty(line + 1) ? "key" : "value",
- line, value);
-
- STRV_FOREACH(entry, match_list)
- trie_insert(trie, trie->root, *entry, line, value, filename, file_priority, line_number);
-
- return 0;
-}
-
-static int import_file(struct trie *trie, const char *filename, uint16_t file_priority) {
- enum {
- HW_NONE,
- HW_MATCH,
- HW_DATA,
- } state = HW_NONE;
- _cleanup_fclose_ FILE *f = NULL;
- char line[LINE_MAX];
- _cleanup_strv_free_ char **match_list = NULL;
- uint32_t line_number = 0;
- char *match = NULL;
- int r = 0, err;
-
- f = fopen(filename, "re");
- if (!f)
- return -errno;
-
- while (fgets(line, sizeof(line), f)) {
- size_t len;
- char *pos;
-
- ++line_number;
-
- /* comment line */
- if (line[0] == '#')
- continue;
-
- /* strip trailing comment */
- pos = strchr(line, '#');
- if (pos)
- pos[0] = '\0';
-
- /* strip trailing whitespace */
- len = strlen(line);
- while (len > 0 && isspace(line[len-1]))
- len--;
- line[len] = '\0';
-
- switch (state) {
- case HW_NONE:
- if (len == 0)
- break;
-
- if (line[0] == ' ') {
- log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
- "Match expected but got indented property \"%s\", ignoring line", line);
- r = -EINVAL;
- break;
- }
-
- /* start of record, first match */
- state = HW_MATCH;
-
- match = strdup(line);
- if (!match)
- return -ENOMEM;
-
- err = strv_consume(&match_list, match);
- if (err < 0)
- return err;
-
- break;
-
- case HW_MATCH:
- if (len == 0) {
- log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
- "Property expected, ignoring record with no properties");
- r = -EINVAL;
- state = HW_NONE;
- strv_clear(match_list);
- break;
- }
-
- if (line[0] != ' ') {
- /* another match */
- match = strdup(line);
- if (!match)
- return -ENOMEM;
-
- err = strv_consume(&match_list, match);
- if (err < 0)
- return err;
-
- break;
- }
-
- /* first data */
- state = HW_DATA;
- err = insert_data(trie, match_list, line, filename, file_priority, line_number);
- if (err < 0)
- r = err;
- break;
-
- case HW_DATA:
- if (len == 0) {
- /* end of record */
- state = HW_NONE;
- strv_clear(match_list);
- break;
- }
-
- if (line[0] != ' ') {
- log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
- "Property or empty line expected, got \"%s\", ignoring record", line);
- r = -EINVAL;
- state = HW_NONE;
- strv_clear(match_list);
- break;
- }
-
- err = insert_data(trie, match_list, line, filename, file_priority, line_number);
- if (err < 0)
- r = err;
- break;
- };
- }
-
- if (state == HW_MATCH)
- log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
- "Property expected, ignoring record with no properties");
-
- return r;
-}
-
-static int hwdb_query(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
- const char *key, *value;
- const char *modalias;
- int r;
-
- assert(argc >= 2);
- assert(argv);
-
- modalias = argv[1];
-
- r = sd_hwdb_new(&hwdb);
- if (r < 0)
- return r;
-
- SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value)
- printf("%s=%s\n", key, value);
-
- return 0;
-}
-
-static int hwdb_update(int argc, char *argv[], void *userdata) {
- _cleanup_free_ char *hwdb_bin = NULL;
- _cleanup_(trie_freep) struct trie *trie = NULL;
- _cleanup_strv_free_ char **files = NULL;
- char **f;
- uint16_t file_priority = 1;
- int r = 0, err;
-
- trie = new0(struct trie, 1);
- if (!trie)
- return -ENOMEM;
-
- /* string store */
- trie->strings = strbuf_new();
- if (!trie->strings)
- return -ENOMEM;
-
- /* index */
- trie->root = new0(struct trie_node, 1);
- if (!trie->root)
- return -ENOMEM;
-
- trie->nodes_count++;
-
- err = conf_files_list_strv(&files, ".hwdb", arg_root, 0, conf_file_dirs);
- if (err < 0)
- return log_error_errno(err, "Failed to enumerate hwdb files: %m");
-
- STRV_FOREACH(f, files) {
- log_debug("Reading file \"%s\"", *f);
- err = import_file(trie, *f, file_priority++);
- if (err < 0 && arg_strict)
- r = err;
- }
-
- strbuf_complete(trie->strings);
-
- log_debug("=== trie in-memory ===");
- log_debug("nodes: %8zu bytes (%8zu)",
- trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
- log_debug("children arrays: %8zu bytes (%8zu)",
- trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
- log_debug("values arrays: %8zu bytes (%8zu)",
- trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
- log_debug("strings: %8zu bytes",
- trie->strings->len);
- log_debug("strings incoming: %8zu bytes (%8zu)",
- trie->strings->in_len, trie->strings->in_count);
- log_debug("strings dedup'ed: %8zu bytes (%8zu)",
- trie->strings->dedup_len, trie->strings->dedup_count);
-
- hwdb_bin = path_join(arg_root, arg_hwdb_bin_dir, "hwdb.bin");
- if (!hwdb_bin)
- return -ENOMEM;
-
- mkdir_parents_label(hwdb_bin, 0755);
- err = trie_store(trie, hwdb_bin);
- if (err < 0)
- return log_error_errno(err, "Failure writing database %s: %m", hwdb_bin);
-
- err = label_fix(hwdb_bin, 0);
- if (err < 0)
- return err;
-
- return r;
+static int verb_update(int argc, char *argv[], void *userdata) {
+ return hwdb_update(arg_root, arg_hwdb_bin_dir, arg_strict, false);
}
static int help(void) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "ust:r:h", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "ust:r:h", options, NULL)) >= 0)
switch(c) {
case 'h':
default:
assert_not_reached("Unknown option");
}
- }
return 1;
}
static int hwdb_main(int argc, char *argv[]) {
static const Verb verbs[] = {
- { "update", 1, 1, 0, hwdb_update },
- { "query", 2, 2, 0, hwdb_query },
+ { "update", 1, 1, 0, verb_update },
+ { "query", 2, 2, 0, verb_query },
{},
};
deflateEnd(&c->gzip);
else
inflateEnd(&c->gzip);
+#if HAVE_BZIP2
} else if (c->type == IMPORT_COMPRESS_BZIP2) {
if (c->encoding)
BZ2_bzCompressEnd(&c->bzip2);
else
BZ2_bzDecompressEnd(&c->bzip2);
+#endif
}
c->type = IMPORT_COMPRESS_UNKNOWN;
c->type = IMPORT_COMPRESS_GZIP;
+#if HAVE_BZIP2
} else if (memcmp(data, bzip2_signature, sizeof(bzip2_signature)) == 0) {
r = BZ2_bzDecompressInit(&c->bzip2, 0, 0);
if (r != BZ_OK)
return -EIO;
c->type = IMPORT_COMPRESS_BZIP2;
+#endif
} else
c->type = IMPORT_COMPRESS_UNCOMPRESSED;
break;
+#if HAVE_BZIP2
case IMPORT_COMPRESS_BZIP2:
c->bzip2.next_in = (void*) data;
c->bzip2.avail_in = size;
}
break;
+#endif
default:
assert_not_reached("Unknown compression");
c->type = IMPORT_COMPRESS_GZIP;
break;
+#if HAVE_BZIP2
case IMPORT_COMPRESS_BZIP2:
r = BZ2_bzCompressInit(&c->bzip2, 9, 0, 0);
if (r != BZ_OK)
c->type = IMPORT_COMPRESS_BZIP2;
break;
+#endif
case IMPORT_COMPRESS_UNCOMPRESSED:
c->type = IMPORT_COMPRESS_UNCOMPRESSED;
break;
+#if HAVE_BZIP2
case IMPORT_COMPRESS_BZIP2:
c->bzip2.next_in = (void*) data;
}
break;
+#endif
case IMPORT_COMPRESS_UNCOMPRESSED:
break;
+#if HAVE_BZIP2
case IMPORT_COMPRESS_BZIP2:
c->bzip2.avail_in = 0;
} while (r != BZ_STREAM_END);
break;
+#endif
case IMPORT_COMPRESS_UNCOMPRESSED:
break;
[IMPORT_COMPRESS_UNCOMPRESSED] = "uncompressed",
[IMPORT_COMPRESS_XZ] = "xz",
[IMPORT_COMPRESS_GZIP] = "gzip",
+#if HAVE_BZIP2
[IMPORT_COMPRESS_BZIP2] = "bzip2",
+#endif
};
DEFINE_STRING_TABLE_LOOKUP(import_compress_type, ImportCompressType);
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#if HAVE_BZIP2
#include <bzlib.h>
+#endif
#include <lzma.h>
#include <sys/types.h>
#include <zlib.h>
union {
lzma_stream xz;
z_stream gzip;
+#if HAVE_BZIP2
bz_stream bzip2;
+#endif
};
} ImportCompress;
siphash24_compress(i->language, strlen(i->language), state);
}
-static int catalog_compare_func(const void *a, const void *b) {
- const CatalogItem *i = a, *j = b;
+static int catalog_compare_func(const CatalogItem *a, const CatalogItem *b) {
unsigned k;
int r;
- for (k = 0; k < ELEMENTSOF(j->id.bytes); k++) {
- r = CMP(i->id.bytes[k], j->id.bytes[k]);
+ for (k = 0; k < ELEMENTSOF(b->id.bytes); k++) {
+ r = CMP(a->id.bytes[k], b->id.bytes[k]);
if (r != 0)
return r;
}
- return strcmp(i->language, j->language);
+ return strcmp(a->language, b->language);
}
const struct hash_ops catalog_hash_ops = {
.hash = catalog_hash_func,
- .compare = catalog_compare_func
+ .compare = (comparison_fn_t) catalog_compare_func,
};
static bool next_header(const char **s) {
}
assert(n == hashmap_size(h));
- qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
+ typesafe_qsort(items, n, catalog_compare_func);
strbuf_complete(sb);
strncpy(key.language, loc, sizeof(key.language));
key.language[strcspn(key.language, ".@")] = 0;
- f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
+ f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func);
if (!f) {
char *e;
e = strchr(key.language, '_');
if (e) {
*e = 0;
- f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
+ f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func);
}
}
}
if (!f) {
zero(key.language);
- f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
+ f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), (comparison_fn_t) catalog_compare_func);
}
if (!f)
return r;
}
-static int entry_item_cmp(const void *_a, const void *_b) {
- const EntryItem *a = _a, *b = _b;
-
- if (le64toh(a->object_offset) < le64toh(b->object_offset))
- return -1;
- if (le64toh(a->object_offset) > le64toh(b->object_offset))
- return 1;
- return 0;
+static int entry_item_cmp(const EntryItem *a, const EntryItem *b) {
+ return CMP(le64toh(a->object_offset), le64toh(b->object_offset));
}
int journal_file_append_entry(
/* Order by the position on disk, in order to improve seek
* times for rotating media. */
- qsort_safe(items, n_iovec, sizeof(EntryItem), entry_item_cmp);
+ typesafe_qsort(items, n_iovec, entry_item_cmp);
r = journal_file_append_entry_internal(f, ts, boot_id, xor_hash, items, n_iovec, seqnum, ret, offset);
bool have_seqnum;
};
-static int vacuum_compare(const void *_a, const void *_b) {
- const struct vacuum_info *a, *b;
-
- a = _a;
- b = _b;
+static int vacuum_compare(const struct vacuum_info *a, const struct vacuum_info *b) {
+ int r;
if (a->have_seqnum && b->have_seqnum &&
- sd_id128_equal(a->seqnum_id, b->seqnum_id)) {
- if (a->seqnum < b->seqnum)
- return -1;
- else if (a->seqnum > b->seqnum)
- return 1;
- else
- return 0;
- }
+ sd_id128_equal(a->seqnum_id, b->seqnum_id))
+ return CMP(a->seqnum, b->seqnum);
- if (a->realtime < b->realtime)
- return -1;
- else if (a->realtime > b->realtime)
- return 1;
- else if (a->have_seqnum && b->have_seqnum)
+ r = CMP(a->realtime, b->realtime);
+ if (r != 0)
+ return r;
+
+ if (a->have_seqnum && b->have_seqnum)
return memcmp(&a->seqnum_id, &b->seqnum_id, 16);
- else
- return strcmp(a->filename, b->filename);
+
+ return strcmp(a->filename, b->filename);
}
static void patch_realtime(
sum += size;
}
- qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
+ typesafe_qsort(list, n_list, vacuum_compare);
for (i = 0; i < n_list; i++) {
unsigned left;
int main(int argc, char *argv[]) {
_cleanup_(unlink_tempfilep) char database[] = "/tmp/test-catalog.XXXXXX";
- _cleanup_free_ char *text = NULL, *catalog_dir = NULL;
+ _cleanup_free_ char *text = NULL;
int r;
setlocale(LC_ALL, "de_DE.UTF-8");
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
/* If test-catalog is located at the build directory, then use catalogs in that.
* If it is not, e.g. installed by systemd-tests package, then use installed catalogs. */
#include "process-util.h"
#include "random-util.h"
#include "string-util.h"
+#include "tests.h"
#include "util.h"
typedef int (compress_t)(const void *src, uint64_t src_size, void *dst,
int main(int argc, char *argv[]) {
#if HAVE_XZ || HAVE_LZ4
- const char *i;
- int r;
-
- log_set_max_level(LOG_INFO);
+ test_setup_logging(LOG_INFO);
if (argc >= 2) {
unsigned x;
assert_se(safe_atou(argv[1], &x) >= 0);
arg_duration = x * USEC_PER_SEC;
- } else {
- bool slow;
-
- r = getenv_bool("SYSTEMD_SLOW_TESTS");
- slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
-
- arg_duration = slow ? 2 * USEC_PER_SEC : USEC_PER_SEC / 50;
- }
+ } else
+ arg_duration = slow_tests_enabled() ?
+ 2 * USEC_PER_SEC : USEC_PER_SEC / 50;
if (argc == 3)
(void) safe_atozu(argv[2], &arg_start);
else
arg_start = getpid_cached();
+ const char *i;
NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
#if HAVE_XZ
test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
}
return 0;
#else
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("No compression feature is enabled");
#endif
}
#include "macro.h"
#include "path-util.h"
#include "random-util.h"
+#include "tests.h"
#include "util.h"
#if HAVE_XZ
memcpy(huge, "HUGE=", 5);
char_array_0(huge);
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
random_bytes(data + 7, sizeof(data) - 7);
return 0;
#else
+ log_info("/* XZ and LZ4 tests skipped */");
return EXIT_TEST_SKIP;
#endif
}
#include "journal-internal.h"
#include "log.h"
#include "macro.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
unsigned n = 0;
_cleanup_(sd_journal_closep) sd_journal*j = NULL;
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY) >= 0);
#include "log.h"
#include "parse-util.h"
#include "rm-rf.h"
+#include "tests.h"
#include "util.h"
int main(int argc, char *argv[]) {
int r, i, I = 100;
char t[] = "/tmp/journal-stream-XXXXXX";
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
if (argc >= 2) {
r = safe_atoi(argv[1], &I);
#include "parse-util.h"
#include "rm-rf.h"
#include "util.h"
+#include "tests.h"
-/* This program tests skipping around in a multi-file journal.
- */
+/* This program tests skipping around in a multi-file journal. */
static bool arg_keep = false;
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
/* journal_file_open requires a valid machine id */
if (access("/etc/machine-id", F_OK) != 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("/etc/machine-id not found");
arg_keep = argc > 1;
#include "journal-internal.h"
#include "log.h"
#include "string-util.h"
+#include "tests.h"
#include "util.h"
int main(int argc, char *argv[]) {
_cleanup_(sd_journal_closep) sd_journal*j = NULL;
_cleanup_free_ char *t;
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(sd_journal_open(&j, 0) >= 0);
#include "macro.h"
#include "parse-util.h"
#include "rm-rf.h"
+#include "tests.h"
#include "util.h"
#define N_ENTRIES 200
/* journal_file_open requires a valid machine id */
if (access("/etc/machine-id", F_OK) != 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("/etc/machine-id not found");
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
#include "log.h"
#include "rm-rf.h"
#include "terminal-util.h"
+#include "tests.h"
#include "util.h"
#define N_ENTRIES 6000
/* journal_file_open requires a valid machine id */
if (access("/etc/machine-id", F_OK) != 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("/etc/machine-id not found");
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
#include "journal-vacuum.h"
#include "log.h"
#include "rm-rf.h"
+#include "tests.h"
static bool arg_keep = false;
sd_id128_t fake_boot_id;
char t[] = "/tmp/journal-XXXXXX";
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
JournalFile *f1, *f2, *f3, *f4;
char t[] = "/tmp/journal-XXXXXX";
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
assert_se(data_size <= sizeof(data));
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
int main(int argc, char *argv[]) {
arg_keep = argc > 1;
+ test_setup_logging(LOG_INFO);
+
/* journal_file_open requires a valid machine id */
if (access("/etc/machine-id", F_OK) != 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("/etc/machine-id not found");
test_non_empty();
test_empty();
struct ia_pd ia_pd;
struct ia_ta ia_ta;
};
- sd_event_source *timeout_t1;
- sd_event_source *timeout_t2;
LIST_HEAD(DHCP6Address, addresses);
};
size_t ntp_fqdn_count;
};
-int dhcp6_lease_clear_timers(DHCP6IA *ia);
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
+int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
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 lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) {
int r;
r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size));
const struct hash_ops lldp_neighbor_id_hash_ops = {
.hash = lldp_neighbor_id_hash_func,
- .compare = lldp_neighbor_id_compare_func
+ .compare = (__compar_fn_t) lldp_neighbor_id_compare_func,
};
int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
}
extern const struct hash_ops lldp_neighbor_id_hash_ops;
+int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y);
int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n);
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
+/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
+enum {
+ DHCP6_REQUEST_IA_NA = 1,
+ DHCP6_REQUEST_IA_TA = 2, /* currently not used */
+ DHCP6_REQUEST_IA_PD = 4,
+};
+
struct sd_dhcp6_client {
unsigned n_ref;
uint16_t arp_type;
DHCP6IA ia_na;
DHCP6IA ia_pd;
- bool prefix_delegation;
+ sd_event_source *timeout_t1;
+ sd_event_source *timeout_t2;
+ int request;
be32_t transaction_id;
usec_t transaction_start;
struct sd_dhcp6_lease *lease;
return 0;
}
-int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, bool delegation) {
+int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
+ assert_return(client, -EINVAL);
+ assert_return(delegation, -EINVAL);
+
+ *delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD);
+
+ return 0;
+}
+
+int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) {
+ assert_return(client, -EINVAL);
+
+ SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation);
+
+ return 0;
+}
+
+int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
assert_return(client, -EINVAL);
+ assert_return(request, -EINVAL);
- client->prefix_delegation = delegation;
+ *request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA);
+
+ return 0;
+}
+
+int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
+ assert_return(client, -EINVAL);
+
+ SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request);
return 0;
}
static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
assert(client);
- if (client->lease) {
- dhcp6_lease_clear_timers(&client->lease->ia);
- sd_dhcp6_lease_unref(client->lease);
- }
-
- client->lease = lease;
+ (void) sd_dhcp6_lease_unref(client->lease);
+ client->lease = sd_dhcp6_lease_ref(lease);
}
static int client_reset(sd_dhcp6_client *client) {
client->transaction_id = 0;
client->transaction_start = 0;
- client->ia_na.timeout_t1 =
- sd_event_source_unref(client->ia_na.timeout_t1);
- client->ia_na.timeout_t2 =
- sd_event_source_unref(client->ia_na.timeout_t2);
-
client->retransmit_time = 0;
client->retransmit_count = 0;
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
if (r < 0)
return r;
- r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
- if (r < 0)
- return r;
+ if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
+ r = dhcp6_option_append_ia(&opt, &optlen,
+ &client->ia_na);
+ if (r < 0)
+ return r;
+ }
if (client->fqdn) {
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
return r;
}
- if (client->prefix_delegation) {
+ if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
if (r < 0)
return r;
if (r < 0)
return r;
- r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
- if (r < 0)
- return r;
+ if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
+ r = dhcp6_option_append_ia(&opt, &optlen,
+ &client->lease->ia);
+ if (r < 0)
+ return r;
+ }
if (client->fqdn) {
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
return r;
}
- if (client->prefix_delegation) {
+ if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
if (r < 0)
return r;
case DHCP6_STATE_REBIND:
message->type = DHCP6_REBIND;
- r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
- if (r < 0)
- return r;
+ if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
+ r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
+ if (r < 0)
+ return r;
+ }
if (client->fqdn) {
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
return r;
}
- if (client->prefix_delegation) {
+ if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
if (r < 0)
return r;
assert(client);
assert(client->lease);
- client->lease->ia.timeout_t2 =
- sd_event_source_unref(client->lease->ia.timeout_t2);
+ client->timeout_t2 =
+ sd_event_source_unref(client->timeout_t2);
log_dhcp6_client(client, "Timeout T2");
assert(client);
assert(client->lease);
- client->lease->ia.timeout_t1 =
- sd_event_source_unref(client->lease->ia.timeout_t1);
+ client->timeout_t1 =
+ sd_event_source_unref(client->timeout_t1);
log_dhcp6_client(client, "Timeout T1");
if (r < 0 && r != -ENOMSG)
return r;
- r = dhcp6_lease_get_iaid(lease, &iaid_lease);
+ r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
if (r < 0)
return r;
return 0;
}
+static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
+ uint32_t *lifetime_t2) {
+ assert_return(client, -EINVAL);
+ assert_return(client->lease, -EINVAL);
+
+ if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
+ *lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
+ *lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
+
+ return 0;
+ }
+
+ if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
+ *lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
+ *lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
+
+ return 0;
+ }
+
+ return -ENOMSG;
+}
+
static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
int r;
usec_t timeout, time_now;
char time_string[FORMAT_TIMESPAN_MAX];
+ uint32_t lifetime_t1, lifetime_t2;
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
case DHCP6_STATE_BOUND:
- if (client->lease->ia.ia_na.lifetime_t1 == 0xffffffff ||
- client->lease->ia.ia_na.lifetime_t2 == 0xffffffff) {
+ r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2);
+ if (r < 0)
+ goto error;
+ if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) {
log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
- be32toh(client->lease->ia.ia_na.lifetime_t1),
- be32toh(client->lease->ia.ia_na.lifetime_t2));
+ lifetime_t1, lifetime_t2);
return 0;
}
- timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t1) * USEC_PER_SEC);
+ timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
log_dhcp6_client(client, "T1 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
- &client->lease->ia.timeout_t1,
+ &client->timeout_t1,
clock_boottime_or_monotonic(), time_now + timeout,
10 * USEC_PER_SEC, client_timeout_t1,
client);
if (r < 0)
goto error;
- r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
+ r = sd_event_source_set_priority(client->timeout_t1,
client->event_priority);
if (r < 0)
goto error;
- r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
+ r = sd_event_source_set_description(client->timeout_t1, "dhcp6-t1-timeout");
if (r < 0)
goto error;
- timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t2) * USEC_PER_SEC);
+ timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
log_dhcp6_client(client, "T2 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
- &client->lease->ia.timeout_t2,
+ &client->timeout_t2,
clock_boottime_or_monotonic(), time_now + timeout,
10 * USEC_PER_SEC, client_timeout_t2,
client);
if (r < 0)
goto error;
- r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
+ r = sd_event_source_set_priority(client->timeout_t2,
client->event_priority);
if (r < 0)
goto error;
- r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
+ r = sd_event_source_set_description(client->timeout_t2, "dhcp6-t2-timeout");
if (r < 0)
goto error;
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
return -EBUSY;
+ if (!client->information_request && !client->request)
+ return -EINVAL;
+
r = client_reset(client);
if (r < 0)
return r;
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
client->ifindex = -1;
+ client->request = DHCP6_REQUEST_IA_NA;
client->fd = -1;
client->req_opts_len = ELEMENTSOF(default_req_opts);
#include "strv.h"
#include "util.h"
-int dhcp6_lease_clear_timers(DHCP6IA *ia) {
- assert_return(ia, -EINVAL);
-
- ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1);
- ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2);
-
- return 0;
-}
-
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
DHCP6Address *addr;
uint32_t valid = 0, t;
if (!ia)
return NULL;
- dhcp6_lease_clear_timers(ia);
-
while (ia->addresses) {
address = ia->addresses;
return 0;
}
+int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
+ assert_return(lease, -EINVAL);
+ assert_return(iaid, -EINVAL);
+
+ *iaid = lease->pd.ia_pd.id;
+
+ return 0;
+}
+
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
uint32_t *lifetime_preferred,
uint32_t *lifetime_valid) {
return 0;
}
-static int neighbor_compare_func(const void *a, const void *b) {
- const sd_lldp_neighbor * const*x = a, * const *y = b;
-
- return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id);
+static int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
+ return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
}
static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
assert((size_t) k == hashmap_size(lldp->neighbor_by_id));
/* Return things in a stable order */
- qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func);
+ typesafe_qsort(l, k, neighbor_compare_func);
*ret = l;
return k;
#include "in-addr-util.h"
#include "netlink-util.h"
+#include "tests.h"
#include "util.h"
static void acd_handler(sd_ipv4acd *acd, int event, void *userdata) {
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
if (argc == 3)
return test_acd(argv[1], argv[2]);
#include "dhcp-internal.h"
#include "dhcp-protocol.h"
#include "fd-util.h"
+#include "tests.h"
#include "util.h"
static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
int main(int argc, char *argv[]) {
_cleanup_(sd_event_unrefp) sd_event *e;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
assert_se(sd_event_new(&e) >= 0);
#include "sd-event.h"
#include "dhcp-server-internal.h"
+#include "tests.h"
static void test_pool(struct in_addr *address, unsigned size, int ret) {
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
test_pool(&address_lo, 1, 0);
r = sd_dhcp_server_start(server);
-
if (r == -EPERM)
- return EXIT_TEST_SKIP;
+ return log_info_errno(r, "sd_dhcp_server_start failed: %m");
assert_se(r >= 0);
assert_se(sd_dhcp_server_start(server) == -EBUSY);
_cleanup_(sd_event_unrefp) sd_event *e;
int r;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
assert_se(sd_event_new(&e) >= 0);
r = test_basic(e);
if (r != 0)
- return r;
+ return log_tests_skipped("cannot start dhcp server");
test_message_handler();
test_client_id_hash();
#include "fd-util.h"
#include "macro.h"
#include "socket-util.h"
+#include "tests.h"
#include "virt.h"
static struct ether_addr mac_addr = {
static int test_client_basic(sd_event *e) {
sd_dhcp6_client *client;
+ int v;
if (verbose)
printf("* %s\n", __FUNCTION__);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
+ assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0);
+ v = 0;
+ assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0);
+ assert_se(v);
+ assert_se(sd_dhcp6_client_set_information_request(client, 0) >= 0);
+ v = 42;
+ assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0);
+ assert_se(v == 0);
+
+ v = 0;
+ assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
+ assert_se(v);
+ v = 0;
+ assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
+ assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
+ assert_se(v);
+ v = 42;
+ assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
+ assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
+ assert_se(v);
+
+ assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
+ assert_se(sd_dhcp6_client_set_prefix_delegation(client, 1) >= 0);
+ v = 0;
+ assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
+ assert_se(v);
+ v = 0;
+ assert_se(sd_dhcp6_client_get_prefix_delegation(client, &v) >= 0);
+ assert_se(v);
+
assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
assert_se(sd_dhcp6_client_detach_event(client) >= 0);
sd_dhcp6_client *client;
usec_t time_now = now(clock_boottime_or_monotonic());
struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
- int val = true;
+ int val;
if (verbose)
printf("* %s\n", __FUNCTION__);
assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
- assert_se(val == false);
- assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0);
+ assert_se(val == 0);
+ assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0);
assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
- assert_se(val == true);
+ assert_se(val);
assert_se(sd_dhcp6_client_set_callback(client,
test_client_information_cb, e) >= 0);
assert_se(sd_event_new(&e) >= 0);
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_client_basic(e);
test_option(e);
#include "netlink-util.h"
#include "parse-util.h"
#include "string-util.h"
+#include "tests.h"
#include "util.h"
static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
if (argc == 2)
return test_ll(argv[1], NULL);
#include "arp-util.h"
#include "fd-util.h"
#include "socket-util.h"
+#include "tests.h"
#include "util.h"
static bool verbose = false;
int main(int argc, char *argv[]) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
assert_se(sd_event_new(&e) >= 0);
#include "icmp6-util.h"
#include "socket-util.h"
#include "strv.h"
+#include "tests.h"
static struct ether_addr mac_addr = {
.ether_addr_octet = { 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53 }
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_radv_prefix();
test_radv();
#include "socket-util.h"
#include "strv.h"
#include "ndisc-internal.h"
+#include "tests.h"
static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_rs();
test_timeout();
sd-device/device-util.h
sd-device/sd-device.c
sd-hwdb/hwdb-internal.h
+ sd-hwdb/hwdb-util.c
sd-hwdb/hwdb-util.h
sd-hwdb/sd-hwdb.c
sd-netlink/generic-netlink.c
return -EINVAL;
}
-static int match_component_compare(const void *a, const void *b) {
- const struct bus_match_component *x = a, *y = b;
-
- if (x->type < y->type)
- return -1;
- if (x->type > y->type)
- return 1;
-
- return 0;
+static int match_component_compare(const struct bus_match_component *a, const struct bus_match_component *b) {
+ return CMP(a->type, b->type);
}
void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) {
}
/* Order the whole thing, so that we always generate the same tree */
- qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare);
+ typesafe_qsort(components, n_components, match_component_compare);
/* Check for duplicates */
for (i = 0; i+1 < n_components; i++)
#include "format-util.h"
#include "log.h"
#include "macro.h"
+#include "tests.h"
#include "util.h"
static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
void *p;
int q, r;
+ test_setup_logging(LOG_INFO);
+
r = server_init(&bus);
- if (r < 0) {
- log_info("Failed to connect to bus, skipping tests.");
- return EXIT_TEST_SKIP;
- }
+ if (r < 0)
+ return log_tests_skipped("Failed to connect to bus");
log_info("Initialized...");
#include "bus-message.h"
#include "bus-util.h"
#include "refcnt.h"
+#include "tests.h"
static void test_bus_new(void) {
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
}
int main(int argc, char **argv) {
- int r;
-
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_INFO);
test_bus_new();
- r = test_bus_open();
- if (r < 0) {
- log_info("Failed to connect to bus, skipping tests.");
- return EXIT_TEST_SKIP;
- }
+
+ if (test_bus_open() < 0)
+ return log_tests_skipped("Failed to connect to bus");
test_bus_new_method_call();
test_bus_new_signal();
#include "bus-dump.h"
#include "bus-util.h"
#include "cgroup-util.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
int r;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
- if (cg_unified_flush() == -ENOMEDIUM) {
- log_info("Skipping test: /sys/fs/cgroup/ not available");
- return EXIT_TEST_SKIP;
- }
+ if (cg_unified_flush() == -ENOMEDIUM)
+ return log_tests_skipped("/sys/fs/cgroup/ not available");
r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL);
log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG, r, "sd_bus_creds_new_from_pid: %m");
#include "bus-message.h"
#include "bus-util.h"
#include "macro.h"
+#include "tests.h"
#include "util.h"
static void test_bus_gvariant_is_fixed_size(void) {
assert_se(bus_gvariant_get_alignment("((t)(t))") == 8);
}
-static void test_marshal(void) {
+static int test_marshal(void) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *n = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- _cleanup_free_ void *blob;
+ _cleanup_free_ void *blob = NULL;
size_t sz;
int r;
r = sd_bus_open_user(&bus);
if (r < 0)
- exit(EXIT_TEST_SKIP);
+ return log_tests_skipped_errno(r, "Failed to connect to bus");
bus->message_version = 2; /* dirty hack to enable gvariant */
assert_se(sd_bus_message_seal(m, 4712, 0) >= 0);
assert_se(bus_message_dump(m, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
+
+ return EXIT_SUCCESS;
}
int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_INFO);
test_bus_gvariant_is_fixed_size();
test_bus_gvariant_get_size();
test_bus_gvariant_get_alignment();
- test_marshal();
- return 0;
+ return test_marshal();
}
#include "fd-util.h"
#include "hexdecoct.h"
#include "log.h"
+#include "tests.h"
#include "util.h"
static void test_bus_path_encode_unique(void) {
double dbl;
uint64_t u64;
+ test_setup_logging(LOG_INFO);
+
r = sd_bus_default_user(&bus);
if (r < 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("Failed to connect to bus");
r = sd_bus_message_new_method_call(bus, &m, "foobar.waldo", "/", "foobar.waldo", "Piep");
assert_se(r >= 0);
#include "bus-util.h"
#include "log.h"
#include "macro.h"
+#include "tests.h"
static bool mask[32];
sd_bus_slot slots[19];
int r;
+ test_setup_logging(LOG_INFO);
+
r = sd_bus_open_user(&bus);
if (r < 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("Failed to connect to bus");
assert_se(match_add(slots, &root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
assert_se(match_add(slots, &root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
#include "sd-bus.h"
#include "macro.h"
+#include "tests.h"
static bool track_cb_called_x = false;
static bool track_cb_called_y = false;
const char *unique;
int r;
+ test_setup_logging(LOG_INFO);
+
r = sd_event_default(&event);
assert_se(r >= 0);
r = sd_bus_open_user(&a);
- if (IN_SET(r, -ECONNREFUSED, -ENOENT)) {
- log_info("Failed to connect to bus, skipping tests.");
- return EXIT_TEST_SKIP;
- }
+ if (IN_SET(r, -ECONNREFUSED, -ENOENT))
+ return log_tests_skipped("Failed to connect to bus");
assert_se(r >= 0);
r = sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL);
int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator);
sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator);
sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator);
+sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices);
#define FOREACH_DEVICE_AND_SUBSYSTEM(enumerator, device) \
for (device = device_enumerator_get_first(enumerator); \
#include "device-util.h"
#include "dirent-util.h"
#include "fd-util.h"
-#include "prioq.h"
#include "set.h"
#include "string-util.h"
#include "strv.h"
unsigned n_ref;
DeviceEnumerationType type;
- Prioq *devices;
+ sd_device **devices;
+ size_t n_devices, n_allocated, current_device_index;
bool scan_uptodate;
Set *match_subsystem;
}
static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) {
- sd_device *device;
+ size_t i;
assert(enumerator);
- while ((device = prioq_pop(enumerator->devices)))
- sd_device_unref(device);
-
- prioq_free(enumerator->devices);
+ for (i = 0; i < enumerator->n_devices; i++)
+ sd_device_unref(enumerator->devices[i]);
+ free(enumerator->devices);
set_free_free(enumerator->match_subsystem);
set_free_free(enumerator->nomatch_subsystem);
hashmap_free_free_free(enumerator->match_sysattr);
return 0;
}
-static int device_compare(const void *_a, const void *_b) {
- sd_device *a = (sd_device *)_a, *b = (sd_device *)_b;
+static int device_compare(sd_device * const *_a, sd_device * const *_b) {
+ sd_device *a = *(sd_device **)_a, *b = *(sd_device **)_b;
const char *devpath_a, *devpath_b, *sound_a;
bool delay_a, delay_b;
+ int r;
assert_se(sd_device_get_devpath(a, &devpath_a) >= 0);
assert_se(sd_device_get_devpath(b, &devpath_b) >= 0);
/* md and dm devices are enumerated after all other devices */
delay_a = strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-");
delay_b = strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-");
- if (delay_a != delay_b)
- return delay_a - delay_b;
+ r = CMP(delay_a, delay_b);
+ if (r != 0)
+ return r;
return strcmp(devpath_a, devpath_b);
}
int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
- int r;
-
assert_return(enumerator, -EINVAL);
assert_return(device, -EINVAL);
- r = prioq_ensure_allocated(&enumerator->devices, device_compare);
- if (r < 0)
- return r;
-
- r = prioq_put(enumerator->devices, device, NULL);
- if (r < 0)
- return r;
+ if (!GREEDY_REALLOC(enumerator->devices, enumerator->n_allocated, enumerator->n_devices + 1))
+ return -ENOMEM;
- sd_device_ref(device);
+ enumerator->devices[enumerator->n_devices++] = sd_device_ref(device);
return 0;
}
continue;
}
- k = sd_device_get_devnum(device, &devnum);
- if (k < 0) {
- r = k;
- continue;
- }
-
- k = sd_device_get_ifindex(device, &ifindex);
- if (k < 0) {
- r = k;
- continue;
- }
-
k = sd_device_get_is_initialized(device, &initialized);
if (k < 0) {
r = k;
*/
if (!enumerator->match_allow_uninitialized &&
!initialized &&
- (major(devnum) > 0 || ifindex > 0))
+ (sd_device_get_devnum(device, &devnum) >= 0 ||
+ (sd_device_get_ifindex(device, &ifindex) >= 0 && ifindex > 0)))
continue;
if (!match_parent(enumerator, device))
}
int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
- sd_device *device;
int r = 0, k;
+ size_t i;
assert(enumerator);
enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
return 0;
- while ((device = prioq_pop(enumerator->devices)))
- sd_device_unref(device);
+ for (i = 0; i < enumerator->n_devices; i++)
+ sd_device_unref(enumerator->devices[i]);
+
+ enumerator->n_devices = 0;
if (!set_isempty(enumerator->match_tag)) {
k = enumerator_scan_devices_tags(enumerator);
r = k;
}
+ typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
+
enumerator->scan_uptodate = true;
+ enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
return r;
}
if (r < 0)
return NULL;
- enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
+ enumerator->current_device_index = 0;
+
+ if (enumerator->n_devices == 0)
+ return NULL;
- return prioq_peek(enumerator->devices);
+ return enumerator->devices[0];
}
_public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
assert_return(enumerator, NULL);
if (!enumerator->scan_uptodate ||
- enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES)
+ enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES ||
+ enumerator->current_device_index + 1 >= enumerator->n_devices)
return NULL;
- sd_device_unref(prioq_pop(enumerator->devices));
-
- return prioq_peek(enumerator->devices);
+ return enumerator->devices[++enumerator->current_device_index];
}
int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
- sd_device *device;
const char *subsysdir;
int r = 0, k;
+ size_t i;
assert(enumerator);
enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
return 0;
- while ((device = prioq_pop(enumerator->devices)))
- sd_device_unref(device);
+ for (i = 0; i < enumerator->n_devices; i++)
+ sd_device_unref(enumerator->devices[i]);
+
+ enumerator->n_devices = 0;
/* modules */
if (match_subsystem(enumerator, "module")) {
}
}
+ typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
+
enumerator->scan_uptodate = true;
+ enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
return r;
}
if (r < 0)
return NULL;
- enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
+ enumerator->current_device_index = 0;
+
+ if (enumerator->n_devices == 0)
+ return NULL;
- return prioq_peek(enumerator->devices);
+ return enumerator->devices[0];
}
_public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
assert_return(enumerator, NULL);
if (!enumerator->scan_uptodate ||
- enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
+ enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS ||
+ enumerator->current_device_index + 1 >= enumerator->n_devices)
return NULL;
- sd_device_unref(prioq_pop(enumerator->devices));
-
- return prioq_peek(enumerator->devices);
+ return enumerator->devices[++enumerator->current_device_index];
}
sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
assert_return(enumerator, NULL);
- return prioq_peek(enumerator->devices);
+ if (!enumerator->scan_uptodate)
+ return NULL;
+
+ enumerator->current_device_index = 0;
+
+ if (enumerator->n_devices == 0)
+ return NULL;
+
+ return enumerator->devices[0];
}
sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
assert_return(enumerator, NULL);
- sd_device_unref(prioq_pop(enumerator->devices));
+ if (!enumerator->scan_uptodate ||
+ enumerator->current_device_index + 1 >= enumerator->n_devices)
+ return NULL;
+
+ return enumerator->devices[++enumerator->current_device_index];
+}
+
+sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices) {
+ assert(enumerator);
+ assert(ret_n_devices);
+
+ if (!enumerator->scan_uptodate)
+ return NULL;
- return prioq_peek(enumerator->devices);
+ *ret_n_devices = enumerator->n_devices;
+ return enumerator->devices;
}
if (r < 0)
return r;
+ if (device->devmode == (mode_t) -1)
+ return -ENOENT;
+
*mode = device->devmode;
return 0;
if (r < 0)
return r;
+ if (device->devuid == (uid_t) -1)
+ return -ENOENT;
+
*uid = device->devuid;
return 0;
if (r < 0)
return r;
+ if (device->devgid == (gid_t) -1)
+ return -ENOENT;
+
*gid = device->devgid;
return 0;
if (r < 0)
return r;
+ if (device->watch_handle < 0)
+ return -ENOENT;
+
*handle = device->watch_handle;
return 0;
*device = (sd_device) {
.n_ref = 1,
.watch_handle = -1,
+ .ifindex = -1,
+ .devmode = (mode_t) -1,
+ .devuid = (uid_t) -1,
+ .devgid = (gid_t) -1,
};
*ret = device;
if (r < 0)
return r;
+ if (device->ifindex < 0)
+ return -ENOENT;
+
*ifindex = device->ifindex;
return 0;
if (r < 0)
return r;
+ if (!device->devtype)
+ return -ENOENT;
+
*devtype = device->devtype;
return 0;
if (r < 0)
return r;
+ if (major(device->devnum) <= 0)
+ return -ENOENT;
+
*devnum = device->devnum;
return 0;
return r;
}
+ if (!device->sysnum)
+ return -ENOENT;
+
*ret = device->sysnum;
return 0;
if (r < 0)
return r;
- r = sd_device_get_devnum(device, &devnum);
- if (r < 0)
- return r;
-
- r = sd_device_get_ifindex(device, &ifindex);
- if (r < 0)
- return r;
-
- if (major(devnum) > 0) {
+ if (sd_device_get_devnum(device, &devnum) >= 0) {
assert(subsystem);
/* use dev_t — b259:131072, c254:0 */
major(devnum), minor(devnum));
if (r < 0)
return -ENOMEM;
- } else if (ifindex > 0) {
+ } else if (sd_device_get_ifindex(device, &ifindex) >= 0 && ifindex > 0) {
/* use netdev ifindex — n3 */
r = asprintf(&id, "n%u", ifindex);
if (r < 0)
/* set the attribute and save it in the cache. If a NULL value is passed the
* attribute is cleared from the cache */
-_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
+_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) {
_cleanup_close_ int fd = -1;
_cleanup_free_ char *value = NULL;
const char *syspath;
#include "signal-util.h"
#include "stdio-util.h"
#include "string-util.h"
+#include "tests.h"
#include "util.h"
static int prepare_handler(sd_event_source *s, void *userdata) {
}
int main(int argc, char *argv[]) {
-
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
test_basic();
test_sd_event_now();
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include <stdint.h>
+
#include "sparse-endian.h"
-#include "util.h"
#define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' }
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include "alloc-util.h"
+#include "conf-files.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hwdb-internal.h"
+#include "hwdb-util.h"
+#include "label.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "strbuf.h"
+#include "string-util.h"
+#include "strv.h"
+
+static const char *default_hwdb_bin_dir = "/etc/udev";
+static const char * const conf_file_dirs[] = {
+ "/etc/udev/hwdb.d",
+ UDEVLIBEXECDIR "/hwdb.d",
+ NULL
+};
+
+/*
+ * Generic udev properties, key-value database based on modalias strings.
+ * Uses a Patricia/radix trie to index all matches for efficient lookup.
+ */
+
+/* in-memory trie objects */
+struct trie {
+ struct trie_node *root;
+ struct strbuf *strings;
+
+ size_t nodes_count;
+ size_t children_count;
+ size_t values_count;
+};
+
+struct trie_node {
+ /* prefix, common part for all children of this node */
+ size_t prefix_off;
+
+ /* sorted array of pointers to children nodes */
+ struct trie_child_entry *children;
+ uint8_t children_count;
+
+ /* sorted array of key-value pairs */
+ struct trie_value_entry *values;
+ size_t values_count;
+};
+
+/* children array item with char (0-255) index */
+struct trie_child_entry {
+ uint8_t c;
+ struct trie_node *child;
+};
+
+/* value array item with key-value pairs */
+struct trie_value_entry {
+ size_t key_off;
+ size_t value_off;
+ size_t filename_off;
+ uint32_t line_number;
+ uint16_t file_priority;
+};
+
+static int trie_children_cmp(const struct trie_child_entry *a, const struct trie_child_entry *b) {
+ return CMP(a->c, b->c);
+}
+
+static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
+ struct trie_child_entry *child;
+
+ /* extend array, add new entry, sort for bisection */
+ child = reallocarray(node->children, node->children_count + 1, sizeof(struct trie_child_entry));
+ if (!child)
+ return -ENOMEM;
+
+ node->children = child;
+ trie->children_count++;
+ node->children[node->children_count].c = c;
+ node->children[node->children_count].child = node_child;
+ node->children_count++;
+ typesafe_qsort(node->children, node->children_count, trie_children_cmp);
+ trie->nodes_count++;
+
+ return 0;
+}
+
+static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
+ struct trie_child_entry *child;
+ struct trie_child_entry search;
+
+ search.c = c;
+ child = typesafe_bsearch(&search, node->children, node->children_count, trie_children_cmp);
+ if (child)
+ return child->child;
+ return NULL;
+}
+
+static void trie_node_cleanup(struct trie_node *node) {
+ size_t i;
+
+ if (!node)
+ return;
+
+ for (i = 0; i < node->children_count; i++)
+ trie_node_cleanup(node->children[i].child);
+ free(node->children);
+ free(node->values);
+ free(node);
+}
+
+static void trie_free(struct trie *trie) {
+ if (!trie)
+ return;
+
+ trie_node_cleanup(trie->root);
+ strbuf_cleanup(trie->strings);
+ free(trie);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct trie*, trie_free);
+
+static int trie_values_cmp(const struct trie_value_entry *a, const struct trie_value_entry *b, struct trie *trie) {
+ return strcmp(trie->strings->buf + a->key_off,
+ trie->strings->buf + b->key_off);
+}
+
+static int trie_node_add_value(struct trie *trie, struct trie_node *node,
+ const char *key, const char *value,
+ const char *filename, uint16_t file_priority, uint32_t line_number, bool compat) {
+ ssize_t k, v, fn = 0;
+ struct trie_value_entry *val;
+
+ k = strbuf_add_string(trie->strings, key, strlen(key));
+ if (k < 0)
+ return k;
+ v = strbuf_add_string(trie->strings, value, strlen(value));
+ if (v < 0)
+ return v;
+
+ if (!compat) {
+ fn = strbuf_add_string(trie->strings, filename, strlen(filename));
+ if (fn < 0)
+ return fn;
+ }
+
+ if (node->values_count) {
+ struct trie_value_entry search = {
+ .key_off = k,
+ .value_off = v,
+ };
+
+ val = typesafe_bsearch_r(&search, node->values, node->values_count, trie_values_cmp, trie);
+ if (val) {
+ /* At this point we have 2 identical properties on the same match-string.
+ * Since we process files in order, we just replace the previous value. */
+ val->value_off = v;
+ val->filename_off = fn;
+ val->file_priority = file_priority;
+ val->line_number = line_number;
+ return 0;
+ }
+ }
+
+ /* extend array, add new entry, sort for bisection */
+ val = reallocarray(node->values, node->values_count + 1, sizeof(struct trie_value_entry));
+ if (!val)
+ return -ENOMEM;
+ trie->values_count++;
+ node->values = val;
+ node->values[node->values_count] = (struct trie_value_entry) {
+ .key_off = k,
+ .value_off = v,
+ .filename_off = fn,
+ .file_priority = file_priority,
+ .line_number = line_number,
+ };
+ node->values_count++;
+ typesafe_qsort_r(node->values, node->values_count, trie_values_cmp, trie);
+ return 0;
+}
+
+static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
+ const char *key, const char *value,
+ const char *filename, uint16_t file_priority, uint32_t line_number, bool compat) {
+ size_t i = 0;
+ int r = 0;
+
+ for (;;) {
+ size_t p;
+ uint8_t c;
+ struct trie_node *child;
+
+ for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
+ _cleanup_free_ struct trie_node *new_child = NULL;
+ _cleanup_free_ char *s = NULL;
+ ssize_t off;
+
+ if (c == search[i + p])
+ continue;
+
+ /* split node */
+ new_child = new(struct trie_node, 1);
+ if (!new_child)
+ return -ENOMEM;
+
+ /* move values from parent to child */
+ *new_child = (struct trie_node) {
+ .prefix_off = node->prefix_off + p+1,
+ .children = node->children,
+ .children_count = node->children_count,
+ .values = node->values,
+ .values_count = node->values_count,
+ };
+
+ /* update parent; use strdup() because the source gets realloc()d */
+ s = strndup(trie->strings->buf + node->prefix_off, p);
+ if (!s)
+ return -ENOMEM;
+
+ off = strbuf_add_string(trie->strings, s, p);
+ if (off < 0)
+ return off;
+
+ *node = (struct trie_node) {
+ .prefix_off = off,
+ };
+ r = node_add_child(trie, node, new_child, c);
+ if (r < 0)
+ return r;
+
+ new_child = NULL; /* avoid cleanup */
+ break;
+ }
+ i += p;
+
+ c = search[i];
+ if (c == '\0')
+ return trie_node_add_value(trie, node, key, value, filename, file_priority, line_number, compat);
+
+ child = node_lookup(node, c);
+ if (!child) {
+ _cleanup_free_ struct trie_node *new_child = NULL;
+ ssize_t off;
+
+ /* new child */
+ new_child = new(struct trie_node, 1);
+ if (!new_child)
+ return -ENOMEM;
+
+ off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
+ if (off < 0)
+ return off;
+
+ *new_child = (struct trie_node) {
+ .prefix_off = off,
+ };
+
+ r = node_add_child(trie, node, new_child, c);
+ if (r < 0)
+ return r;
+
+ child = TAKE_PTR(new_child);
+ return trie_node_add_value(trie, child, key, value, filename, file_priority, line_number, compat);
+ }
+
+ node = child;
+ i++;
+ }
+}
+
+struct trie_f {
+ FILE *f;
+ struct trie *trie;
+ uint64_t strings_off;
+
+ uint64_t nodes_count;
+ uint64_t children_count;
+ uint64_t values_count;
+};
+
+/* calculate the storage space for the nodes, children arrays, value arrays */
+static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node, bool compat) {
+ uint64_t i;
+
+ for (i = 0; i < node->children_count; i++)
+ trie_store_nodes_size(trie, node->children[i].child, compat);
+
+ trie->strings_off += sizeof(struct trie_node_f);
+ for (i = 0; i < node->children_count; i++)
+ trie->strings_off += sizeof(struct trie_child_entry_f);
+ for (i = 0; i < node->values_count; i++)
+ trie->strings_off += compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f);
+}
+
+static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node, bool compat) {
+ uint64_t i;
+ struct trie_node_f n = {
+ .prefix_off = htole64(trie->strings_off + node->prefix_off),
+ .children_count = node->children_count,
+ .values_count = htole64(node->values_count),
+ };
+ _cleanup_free_ struct trie_child_entry_f *children = NULL;
+ int64_t node_off;
+
+ if (node->children_count) {
+ children = new(struct trie_child_entry_f, node->children_count);
+ if (!children)
+ return -ENOMEM;
+ }
+
+ /* post-order recursion */
+ for (i = 0; i < node->children_count; i++) {
+ int64_t child_off;
+
+ child_off = trie_store_nodes(trie, node->children[i].child, compat);
+ if (child_off < 0)
+ return child_off;
+
+ children[i] = (struct trie_child_entry_f) {
+ .c = node->children[i].c,
+ .child_off = htole64(child_off),
+ };
+ }
+
+ /* write node */
+ node_off = ftello(trie->f);
+ fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
+ trie->nodes_count++;
+
+ /* append children array */
+ if (node->children_count) {
+ fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
+ trie->children_count += node->children_count;
+ }
+
+ /* append values array */
+ for (i = 0; i < node->values_count; i++) {
+ struct trie_value_entry2_f v = {
+ .key_off = htole64(trie->strings_off + node->values[i].key_off),
+ .value_off = htole64(trie->strings_off + node->values[i].value_off),
+ .filename_off = htole64(trie->strings_off + node->values[i].filename_off),
+ .line_number = htole32(node->values[i].line_number),
+ .file_priority = htole16(node->values[i].file_priority),
+ };
+
+ fwrite(&v, compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f), 1, trie->f);
+ }
+ trie->values_count += node->values_count;
+
+ return node_off;
+}
+
+static int trie_store(struct trie *trie, const char *filename, bool compat) {
+ struct trie_f t = {
+ .trie = trie,
+ };
+ _cleanup_free_ char *filename_tmp = NULL;
+ int64_t pos;
+ int64_t root_off;
+ int64_t size;
+ struct trie_header_f h = {
+ .signature = HWDB_SIG,
+ .tool_version = htole64(atoi(PACKAGE_VERSION)),
+ .header_size = htole64(sizeof(struct trie_header_f)),
+ .node_size = htole64(sizeof(struct trie_node_f)),
+ .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
+ .value_entry_size = htole64(compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f)),
+ };
+ int r;
+
+ /* calculate size of header, nodes, children entries, value entries */
+ t.strings_off = sizeof(struct trie_header_f);
+ trie_store_nodes_size(&t, trie->root, compat);
+
+ r = fopen_temporary(filename, &t.f, &filename_tmp);
+ if (r < 0)
+ return r;
+ fchmod(fileno(t.f), 0444);
+
+ /* write nodes */
+ if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
+ goto error_fclose;
+
+ root_off = trie_store_nodes(&t, trie->root, compat);
+ h.nodes_root_off = htole64(root_off);
+ pos = ftello(t.f);
+ h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
+
+ /* write string buffer */
+ fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
+ h.strings_len = htole64(trie->strings->len);
+
+ /* write header */
+ size = ftello(t.f);
+ h.file_size = htole64(size);
+ if (fseeko(t.f, 0, SEEK_SET) < 0)
+ goto error_fclose;
+ fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
+
+ if (ferror(t.f))
+ goto error_fclose;
+ if (fflush(t.f) < 0)
+ goto error_fclose;
+ if (fsync(fileno(t.f)) < 0)
+ goto error_fclose;
+ if (rename(filename_tmp, filename) < 0)
+ goto error_fclose;
+
+ /* write succeeded */
+ fclose(t.f);
+
+ log_debug("=== trie on-disk ===");
+ log_debug("size: %8"PRIi64" bytes", size);
+ log_debug("header: %8zu bytes", sizeof(struct trie_header_f));
+ log_debug("nodes: %8"PRIu64" bytes (%8"PRIu64")",
+ t.nodes_count * sizeof(struct trie_node_f), t.nodes_count);
+ log_debug("child pointers: %8"PRIu64" bytes (%8"PRIu64")",
+ t.children_count * sizeof(struct trie_child_entry_f), t.children_count);
+ log_debug("value pointers: %8"PRIu64" bytes (%8"PRIu64")",
+ t.values_count * (compat ? sizeof(struct trie_value_entry_f) : sizeof(struct trie_value_entry2_f)), t.values_count);
+ log_debug("string store: %8zu bytes", trie->strings->len);
+ log_debug("strings start: %8"PRIu64, t.strings_off);
+ return 0;
+
+ error_fclose:
+ r = -errno;
+ fclose(t.f);
+ unlink(filename_tmp);
+ return r;
+}
+
+static int insert_data(struct trie *trie, char **match_list, char *line, const char *filename,
+ uint16_t file_priority, uint32_t line_number, bool compat) {
+ char *value, **entry;
+
+ assert(line[0] == ' ');
+
+ value = strchr(line, '=');
+ if (!value)
+ return log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+ "Key-value pair expected but got \"%s\", ignoring", line);
+
+ value[0] = '\0';
+ value++;
+
+ /* Replace multiple leading spaces by a single space */
+ while (isblank(line[0]) && isblank(line[1]))
+ line++;
+
+ if (isempty(line + 1) || isempty(value))
+ return log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+ "Empty %s in \"%s=%s\", ignoring",
+ isempty(line + 1) ? "key" : "value",
+ line, value);
+
+ STRV_FOREACH(entry, match_list)
+ trie_insert(trie, trie->root, *entry, line, value, filename, file_priority, line_number, compat);
+
+ return 0;
+}
+
+static int import_file(struct trie *trie, const char *filename, uint16_t file_priority, bool compat) {
+ enum {
+ HW_NONE,
+ HW_MATCH,
+ HW_DATA,
+ } state = HW_NONE;
+ _cleanup_fclose_ FILE *f = NULL;
+ char line[LINE_MAX];
+ _cleanup_strv_free_ char **match_list = NULL;
+ uint32_t line_number = 0;
+ char *match = NULL;
+ int r = 0, err;
+
+ f = fopen(filename, "re");
+ if (!f)
+ return -errno;
+
+ while (fgets(line, sizeof(line), f)) {
+ size_t len;
+ char *pos;
+
+ ++line_number;
+
+ /* comment line */
+ if (line[0] == '#')
+ continue;
+
+ /* strip trailing comment */
+ pos = strchr(line, '#');
+ if (pos)
+ pos[0] = '\0';
+
+ /* strip trailing whitespace */
+ len = strlen(line);
+ while (len > 0 && isspace(line[len-1]))
+ len--;
+ line[len] = '\0';
+
+ switch (state) {
+ case HW_NONE:
+ if (len == 0)
+ break;
+
+ if (line[0] == ' ') {
+ log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+ "Match expected but got indented property \"%s\", ignoring line", line);
+ r = -EINVAL;
+ break;
+ }
+
+ /* start of record, first match */
+ state = HW_MATCH;
+
+ match = strdup(line);
+ if (!match)
+ return -ENOMEM;
+
+ err = strv_consume(&match_list, match);
+ if (err < 0)
+ return err;
+
+ break;
+
+ case HW_MATCH:
+ if (len == 0) {
+ log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+ "Property expected, ignoring record with no properties");
+ r = -EINVAL;
+ state = HW_NONE;
+ strv_clear(match_list);
+ break;
+ }
+
+ if (line[0] != ' ') {
+ /* another match */
+ match = strdup(line);
+ if (!match)
+ return -ENOMEM;
+
+ err = strv_consume(&match_list, match);
+ if (err < 0)
+ return err;
+
+ break;
+ }
+
+ /* first data */
+ state = HW_DATA;
+ err = insert_data(trie, match_list, line, filename, file_priority, line_number, compat);
+ if (err < 0)
+ r = err;
+ break;
+
+ case HW_DATA:
+ if (len == 0) {
+ /* end of record */
+ state = HW_NONE;
+ strv_clear(match_list);
+ break;
+ }
+
+ if (line[0] != ' ') {
+ log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+ "Property or empty line expected, got \"%s\", ignoring record", line);
+ r = -EINVAL;
+ state = HW_NONE;
+ strv_clear(match_list);
+ break;
+ }
+
+ err = insert_data(trie, match_list, line, filename, file_priority, line_number, compat);
+ if (err < 0)
+ r = err;
+ break;
+ };
+ }
+
+ if (state == HW_MATCH)
+ log_syntax(NULL, LOG_WARNING, filename, line_number, EINVAL,
+ "Property expected, ignoring record with no properties");
+
+ return r;
+}
+
+int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool compat) {
+ _cleanup_free_ char *hwdb_bin = NULL;
+ _cleanup_(trie_freep) struct trie *trie = NULL;
+ _cleanup_strv_free_ char **files = NULL;
+ char **f;
+ uint16_t file_priority = 1;
+ int r = 0, err;
+
+ /* The argument 'compat' controls the format version of database. If false, then hwdb.bin will be created with
+ * additional information such that priority, line number, and filename of database source. If true, then hwdb.bin
+ * will be created without the information. systemd-hwdb command should set the argument false, and 'udevadm hwdb'
+ * command should set it true. */
+
+ trie = new0(struct trie, 1);
+ if (!trie)
+ return -ENOMEM;
+
+ /* string store */
+ trie->strings = strbuf_new();
+ if (!trie->strings)
+ return -ENOMEM;
+
+ /* index */
+ trie->root = new0(struct trie_node, 1);
+ if (!trie->root)
+ return -ENOMEM;
+
+ trie->nodes_count++;
+
+ err = conf_files_list_strv(&files, ".hwdb", root, 0, conf_file_dirs);
+ if (err < 0)
+ return log_error_errno(err, "Failed to enumerate hwdb files: %m");
+
+ STRV_FOREACH(f, files) {
+ log_debug("Reading file \"%s\"", *f);
+ err = import_file(trie, *f, file_priority++, compat);
+ if (err < 0 && strict)
+ r = err;
+ }
+
+ strbuf_complete(trie->strings);
+
+ log_debug("=== trie in-memory ===");
+ log_debug("nodes: %8zu bytes (%8zu)",
+ trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
+ log_debug("children arrays: %8zu bytes (%8zu)",
+ trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
+ log_debug("values arrays: %8zu bytes (%8zu)",
+ trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
+ log_debug("strings: %8zu bytes",
+ trie->strings->len);
+ log_debug("strings incoming: %8zu bytes (%8zu)",
+ trie->strings->in_len, trie->strings->in_count);
+ log_debug("strings dedup'ed: %8zu bytes (%8zu)",
+ trie->strings->dedup_len, trie->strings->dedup_count);
+
+ hwdb_bin = path_join(root, hwdb_bin_dir ?: default_hwdb_bin_dir, "hwdb.bin");
+ if (!hwdb_bin)
+ return -ENOMEM;
+
+ mkdir_parents_label(hwdb_bin, 0755);
+ err = trie_store(trie, hwdb_bin, compat);
+ if (err < 0)
+ return log_error_errno(err, "Failed to write database %s: %m", hwdb_bin);
+
+ err = label_fix(hwdb_bin, 0);
+ if (err < 0)
+ return err;
+
+ return r;
+}
+
+int hwdb_query(const char *modalias) {
+ _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
+ const char *key, *value;
+ int r;
+
+ assert(modalias);
+
+ r = sd_hwdb_new(&hwdb);
+ if (r < 0)
+ return r;
+
+ SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value)
+ printf("%s=%s\n", key, value);
+
+ return 0;
+}
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-#include "sd-hwdb.h"
+#include <stdbool.h>
-#include "util.h"
+#include "sd-hwdb.h"
bool hwdb_validate(sd_hwdb *hwdb);
+int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool compat);
+int hwdb_query(const char *modalias);
#include "hwdb-util.h"
#include "refcnt.h"
#include "string-util.h"
+#include "util.h"
struct sd_hwdb {
RefCount n_ref;
#include "macro.h"
#include "netlink-util.h"
-static int address_compare(const void *_a, const void *_b) {
- const struct local_address *a = _a, *b = _b;
+static int address_compare(const struct local_address *a, const struct local_address *b) {
+ int r;
/* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
if (a->family == AF_INET6 && b->family == AF_INET)
return 1;
- if (a->scope < b->scope)
- return -1;
- if (a->scope > b->scope)
- return 1;
+ r = CMP(a->scope, b->scope);
+ if (r != 0)
+ return r;
- if (a->metric < b->metric)
- return -1;
- if (a->metric > b->metric)
- return 1;
+ r = CMP(a->metric, b->metric);
+ if (r != 0)
+ return r;
- if (a->ifindex < b->ifindex)
- return -1;
- if (a->ifindex > b->ifindex)
- return 1;
+ r = CMP(a->ifindex, b->ifindex);
+ if (r != 0)
+ return r;
return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
}
n_list++;
};
- qsort_safe(list, n_list, sizeof(struct local_address), address_compare);
+ typesafe_qsort(list, n_list, address_compare);
*ret = TAKE_PTR(list);
n_list++;
}
- if (n_list > 0)
- qsort(list, n_list, sizeof(struct local_address), address_compare);
+ typesafe_qsort(list, n_list, address_compare);
*ret = TAKE_PTR(list);
#include "alloc-util.h"
#include "in-addr-util.h"
#include "local-addresses.h"
+#include "tests.h"
static void print_local_addresses(struct local_address *a, unsigned n) {
unsigned i;
struct local_address *a;
int n;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
a = NULL;
n = local_addresses(NULL, 0, AF_UNSPEC, &a);
sd_device *device;
/* legacy */
- int refcount;
+ unsigned n_ref;
struct udev_device *parent;
bool parent_set;
bool sysattrs_read;
};
-struct udev_device *udev_device_new(struct udev *udev);
+struct udev_device *udev_device_new(struct udev *udev, sd_device *device);
}
struct udev_device *udev_device_shallow_clone(struct udev_device *old_device) {
- struct udev_device *device;
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
assert(old_device);
- device = udev_device_new(old_device->udev);
- if (!device)
- return NULL;
-
- r = device_shallow_clone(old_device->device, &device->device);
+ r = device_shallow_clone(old_device->device, &device);
if (r < 0) {
- udev_device_unref(device);
errno = -r;
return NULL;
}
- return device;
+ return udev_device_new(old_device->udev, device);
}
struct udev_device *udev_device_clone_with_db(struct udev_device *udev_device_old) {
- struct udev_device *udev_device;
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
assert(udev_device_old);
- udev_device = udev_device_new(udev_device_old->udev);
- if (!udev_device)
- return NULL;
-
- r = device_clone_with_db(udev_device_old->device, &udev_device->device);
+ r = device_clone_with_db(udev_device_old->device, &device);
if (r < 0) {
- udev_device_unref(udev_device);
errno = -r;
return NULL;
}
- return udev_device;
+ return udev_device_new(udev_device_old->udev, device);
}
struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen) {
- struct udev_device *device;
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
- device = udev_device_new(udev);
- if (!device)
- return NULL;
-
- r = device_new_from_nulstr(&device->device, (uint8_t*)nulstr, buflen);
+ r = device_new_from_nulstr(&device, (uint8_t*)nulstr, buflen);
if (r < 0) {
- udev_device_unref(device);
errno = -r;
return NULL;
}
- return device;
+ return udev_device_new(udev, device);
}
struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, const char *syspath, const char *action) {
- struct udev_device *device;
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
- device = udev_device_new(udev);
- if (!device)
- return NULL;
-
- r = device_new_from_synthetic_event(&device->device, syspath, action);
+ r = device_new_from_synthetic_event(&device, syspath, action);
if (r < 0) {
- udev_device_unref(device);
errno = -r;
return NULL;
}
- return device;
+ return udev_device_new(udev, device);
}
int udev_device_copy_properties(struct udev_device *udev_device_dst, struct udev_device *udev_device_src) {
*
* Returns: the kernel event sequence number, or 0 if there is no sequence number available.
**/
-_public_ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
-{
+_public_ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device) {
const char *seqnum;
unsigned long long ret;
int r;
*
* Returns: the dev_t number.
**/
-_public_ dev_t udev_device_get_devnum(struct udev_device *udev_device)
-{
+_public_ dev_t udev_device_get_devnum(struct udev_device *udev_device) {
dev_t devnum;
int r;
r = sd_device_get_devnum(udev_device->device, &devnum);
if (r < 0) {
- errno = -r;
+ if (r != -ENOENT)
+ errno = -r;
return makedev(0, 0);
}
*
* Returns: the driver name string, or #NULL if there is no driver attached.
**/
-_public_ const char *udev_device_get_driver(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_driver(struct udev_device *udev_device) {
const char *driver;
int r;
*
* Returns: the devtype name of the udev device, or #NULL if it cannot be determined
**/
-_public_ const char *udev_device_get_devtype(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_devtype(struct udev_device *udev_device) {
const char *devtype;
int r;
r = sd_device_get_devtype(udev_device->device, &devtype);
if (r < 0) {
- errno = -r;
+ if (r != -ENOENT)
+ errno = -r;
return NULL;
}
*
* Returns: the subsystem name of the udev device, or #NULL if it cannot be determined
**/
-_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device) {
const char *subsystem;
int r;
*
* Returns: the property string, or #NULL if there is no such property.
**/
-_public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key)
-{
+_public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) {
const char *value = NULL;
int r;
return value;
}
-struct udev_device *udev_device_new(struct udev *udev) {
+struct udev_device *udev_device_new(struct udev *udev, sd_device *device) {
struct udev_device *udev_device;
- udev_device = new0(struct udev_device, 1);
+ assert(device);
+
+ udev_device = new(struct udev_device, 1);
if (!udev_device) {
errno = ENOMEM;
return NULL;
}
- udev_device->refcount = 1;
- udev_device->udev = udev;
+
+ *udev_device = (struct udev_device) {
+ .n_ref = 1,
+ .udev = udev,
+ .device = sd_device_ref(device),
+ };
+
udev_list_init(udev, &udev_device->properties, true);
udev_list_init(udev, &udev_device->tags, true);
udev_list_init(udev, &udev_device->sysattrs, true);
* Returns: a new udev device, or #NULL, if it does not exist
**/
_public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) {
- struct udev_device *udev_device;
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
- udev_device = udev_device_new(udev);
- if (!udev_device)
- return NULL;
-
- r = sd_device_new_from_syspath(&udev_device->device, syspath);
+ r = sd_device_new_from_syspath(&device, syspath);
if (r < 0) {
errno = -r;
- udev_device_unref(udev_device);
return NULL;
}
- return udev_device;
+ return udev_device_new(udev, device);
}
/**
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
-_public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
-{
- struct udev_device *udev_device;
+_public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) {
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
- udev_device = udev_device_new(udev);
- if (!udev_device)
- return NULL;
-
- r = sd_device_new_from_devnum(&udev_device->device, type, devnum);
+ r = sd_device_new_from_devnum(&device, type, devnum);
if (r < 0) {
errno = -r;
- udev_device_unref(udev_device);
return NULL;
}
- return udev_device;
+ return udev_device_new(udev, device);
}
/**
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
-_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id)
-{
- struct udev_device *udev_device;
+_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) {
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
- udev_device = udev_device_new(udev);
- if (!udev_device)
- return NULL;
-
- r = sd_device_new_from_device_id(&udev_device->device, id);
+ r = sd_device_new_from_device_id(&device, id);
if (r < 0) {
errno = -r;
- udev_device_unref(udev_device);
return NULL;
}
- return udev_device;
+ return udev_device_new(udev, device);
}
/**
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
-_public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
-{
- struct udev_device *udev_device;
+_public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) {
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
- udev_device = udev_device_new(udev);
- if (!udev_device)
- return NULL;
-
- r = sd_device_new_from_subsystem_sysname(&udev_device->device, subsystem, sysname);
+ r = sd_device_new_from_subsystem_sysname(&device, subsystem, sysname);
if (r < 0) {
errno = -r;
- udev_device_unref(udev_device);
return NULL;
}
- return udev_device;
+ return udev_device_new(udev, device);
}
/**
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
-_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev)
-{
- struct udev_device *udev_device;
+_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev) {
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
int r;
- udev_device = udev_device_new(udev);
- if (!udev_device)
- return NULL;
-
- r = device_new_from_strv(&udev_device->device, environ);
+ r = device_new_from_strv(&device, environ);
if (r < 0) {
errno = -r;
- udev_device_unref(udev_device);
return NULL;
}
- return udev_device;
+ return udev_device_new(udev, device);
}
-static struct udev_device *device_new_from_parent(struct udev_device *child)
-{
- struct udev_device *parent;
+static struct udev_device *device_new_from_parent(struct udev_device *child) {
+ sd_device *parent;
int r;
assert_return_errno(child, NULL, EINVAL);
- parent = udev_device_new(child->udev);
- if (!parent)
- return NULL;
-
- r = sd_device_get_parent(child->device, &parent->device);
+ r = sd_device_get_parent(child->device, &parent);
if (r < 0) {
errno = -r;
- udev_device_unref(parent);
return NULL;
}
- /* the parent is unref'ed with the child, so take a ref from libudev as well */
- sd_device_ref(parent->device);
-
- return parent;
+ return udev_device_new(child->udev, parent);
}
/**
*
* Returns: a new udev device, or #NULL, if it no parent exist.
**/
-_public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
-{
+_public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (!udev_device->parent_set) {
*
* Returns: a new udev device, or #NULL if no matching parent exists.
**/
-_public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype)
-{
+_public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) {
sd_device *parent;
int r;
*
* Returns: the udev library context
**/
-_public_ struct udev *udev_device_get_udev(struct udev_device *udev_device)
-{
+_public_ struct udev *udev_device_get_udev(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
return udev_device->udev;
}
+static struct udev_device *udev_device_free(struct udev_device *udev_device) {
+ assert(udev_device);
+
+ sd_device_unref(udev_device->device);
+ udev_device_unref(udev_device->parent);
+
+ udev_list_cleanup(&udev_device->properties);
+ udev_list_cleanup(&udev_device->sysattrs);
+ udev_list_cleanup(&udev_device->tags);
+ udev_list_cleanup(&udev_device->devlinks);
+
+ return mfree(udev_device);
+}
+
/**
* udev_device_ref:
* @udev_device: udev device
*
* Returns: the passed udev device
**/
-_public_ struct udev_device *udev_device_ref(struct udev_device *udev_device)
-{
- if (udev_device)
- udev_device->refcount++;
-
- return udev_device;
-}
/**
* udev_device_unref:
*
* Returns: #NULL
**/
-_public_ struct udev_device *udev_device_unref(struct udev_device *udev_device)
-{
- if (udev_device && (-- udev_device->refcount) == 0) {
- sd_device_unref(udev_device->device);
- udev_device_unref(udev_device->parent);
-
- udev_list_cleanup(&udev_device->properties);
- udev_list_cleanup(&udev_device->sysattrs);
- udev_list_cleanup(&udev_device->tags);
- udev_list_cleanup(&udev_device->devlinks);
-
- free(udev_device);
- }
-
- return NULL;
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_device, udev_device, udev_device_free);
/**
* udev_device_get_devpath:
*
* Returns: the devpath of the udev device
**/
-_public_ const char *udev_device_get_devpath(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_devpath(struct udev_device *udev_device) {
const char *devpath;
int r;
*
* Returns: the sys path of the udev device
**/
-_public_ const char *udev_device_get_syspath(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_syspath(struct udev_device *udev_device) {
const char *syspath;
int r;
*
* Returns: the name string of the device
**/
-_public_ const char *udev_device_get_sysname(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_sysname(struct udev_device *udev_device) {
const char *sysname;
int r;
*
* Returns: the trailing number string of the device name
**/
-_public_ const char *udev_device_get_sysnum(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_sysnum(struct udev_device *udev_device) {
const char *sysnum;
int r;
r = sd_device_get_sysnum(udev_device->device, &sysnum);
if (r < 0) {
- errno = -r;
+ if (r != -ENOENT)
+ errno = -r;
return NULL;
}
*
* Returns: the device node file name of the udev device, or #NULL if no device node exists
**/
-_public_ const char *udev_device_get_devnode(struct udev_device *udev_device)
-{
+_public_ const char *udev_device_get_devnode(struct udev_device *udev_device) {
const char *devnode;
int r;
*
* Returns: the first entry of the device node link list
**/
-_public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device)
-{
+_public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (device_get_devlinks_generation(udev_device->device) != udev_device->devlinks_generation ||
*
* Returns: the first entry of the property list
**/
-_public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device)
-{
+_public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (device_get_properties_generation(udev_device->device) != udev_device->properties_generation ||
*
* Returns: the number of microseconds since the device was first seen.
**/
-_public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device)
-{
+_public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) {
usec_t ts;
int r;
r = sd_device_get_usec_since_initialized(udev_device->device, &ts);
if (r < 0) {
- errno = EINVAL;
+ errno = -r;
return 0;
}
*
* Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value.
**/
-_public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr)
-{
+_public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) {
const char *value;
int r;
*
* Returns: Negative error code on failure or 0 on success.
**/
-_public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value)
-{
+_public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, const char *value) {
int r;
assert_return(udev_device, -EINVAL);
*
* Returns: the first entry of the property list
**/
-_public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device)
-{
+_public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (!udev_device->sysattrs_read) {
*
* Returns: 1 if the device is set up. 0 otherwise.
**/
-_public_ int udev_device_get_is_initialized(struct udev_device *udev_device)
-{
+_public_ int udev_device_get_is_initialized(struct udev_device *udev_device) {
int r, initialized;
assert_return(udev_device, -EINVAL);
r = sd_device_get_is_initialized(udev_device->device, &initialized);
if (r < 0) {
errno = -r;
-
return 0;
}
*
* Returns: the first entry of the tag list
**/
-_public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device)
-{
+_public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) {
assert_return_errno(udev_device, NULL, EINVAL);
if (device_get_tags_generation(udev_device->device) != udev_device->tags_generation ||
*
* Returns: 1 if the tag is found. 0 otherwise.
**/
-_public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag)
-{
+_public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag) {
assert_return(udev_device, 0);
- return sd_device_has_tag(udev_device->device, tag);
+ return sd_device_has_tag(udev_device->device, tag) > 0;
}
*/
struct udev_enumerate {
struct udev *udev;
- int refcount;
+ unsigned n_ref;
struct udev_list devices_list;
bool devices_uptodate:1;
* Returns: an enumeration context.
**/
_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
- _cleanup_free_ struct udev_enumerate *udev_enumerate = NULL;
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ struct udev_enumerate *udev_enumerate;
int r;
- udev_enumerate = new0(struct udev_enumerate, 1);
- if (!udev_enumerate) {
- errno = ENOMEM;
+ r = sd_device_enumerator_new(&e);
+ if (r < 0) {
+ errno = -r;
return NULL;
}
- r = sd_device_enumerator_new(&udev_enumerate->enumerator);
+ r = sd_device_enumerator_allow_uninitialized(e);
if (r < 0) {
errno = -r;
return NULL;
}
- r = sd_device_enumerator_allow_uninitialized(udev_enumerate->enumerator);
- if (r < 0) {
- errno = -r;
+ udev_enumerate = new(struct udev_enumerate, 1);
+ if (!udev_enumerate) {
+ errno = ENOMEM;
return NULL;
}
- udev_enumerate->refcount = 1;
- udev_enumerate->udev = udev;
+ *udev_enumerate = (struct udev_enumerate) {
+ .udev = udev,
+ .n_ref = 1,
+ .enumerator = TAKE_PTR(e),
+ };
udev_list_init(udev, &udev_enumerate->devices_list, false);
- return TAKE_PTR(udev_enumerate);
+ return udev_enumerate;
+}
+
+static struct udev_enumerate *udev_enumerate_free(struct udev_enumerate *udev_enumerate) {
+ assert(udev_enumerate);
+
+ udev_list_cleanup(&udev_enumerate->devices_list);
+ sd_device_enumerator_unref(udev_enumerate->enumerator);
+ return mfree(udev_enumerate);
}
/**
*
* Returns: the passed enumeration context
**/
-_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
- if (udev_enumerate)
- udev_enumerate->refcount++;
-
- return udev_enumerate;
-}
/**
* udev_enumerate_unref:
*
* Returns: #NULL
**/
-_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) {
- if (udev_enumerate && (-- udev_enumerate->refcount) == 0) {
- udev_list_cleanup(&udev_enumerate->devices_list);
- sd_device_enumerator_unref(udev_enumerate->enumerator);
- free(udev_enumerate);
- }
-
- return NULL;
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_enumerate, udev_enumerate, udev_enumerate_free);
/**
* udev_enumerate_get_udev:
* Opaque object representing the hardware database.
*/
struct udev_hwdb {
- struct udev *udev;
- int refcount;
-
+ unsigned n_ref;
sd_hwdb *hwdb;
-
struct udev_list properties_list;
};
/**
* udev_hwdb_new:
- * @udev: udev library context
+ * @udev: udev library context (unused)
*
* Create a hardware database context to query properties for devices.
*
return NULL;
}
- hwdb = new0(struct udev_hwdb, 1);
+ hwdb = new(struct udev_hwdb, 1);
if (!hwdb) {
errno = ENOMEM;
return NULL;
}
- hwdb->refcount = 1;
- hwdb->hwdb = TAKE_PTR(hwdb_internal);
+ *hwdb = (struct udev_hwdb) {
+ .n_ref = 1,
+ .hwdb = TAKE_PTR(hwdb_internal),
+ };
udev_list_init(udev, &hwdb->properties_list, true);
return hwdb;
}
+static struct udev_hwdb *udev_hwdb_free(struct udev_hwdb *hwdb) {
+ assert(hwdb);
+
+ sd_hwdb_unref(hwdb->hwdb);
+ udev_list_cleanup(&hwdb->properties_list);
+ return mfree(hwdb);
+}
+
/**
* udev_hwdb_ref:
* @hwdb: context
*
* Returns: the passed enumeration context
**/
-_public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) {
- if (!hwdb)
- return NULL;
- hwdb->refcount++;
- return hwdb;
-}
/**
* udev_hwdb_unref:
*
* Returns: #NULL
**/
-_public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) {
- if (!hwdb)
- return NULL;
- hwdb->refcount--;
- if (hwdb->refcount > 0)
- return NULL;
- sd_hwdb_unref(hwdb->hwdb);
- udev_list_cleanup(&hwdb->properties_list);
- return mfree(hwdb);
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_hwdb, udev_hwdb, udev_hwdb_free);
/**
* udev_hwdb_get_properties_list_entry:
const char *key, *value;
struct udev_list_entry *e;
- if (!hwdb || !modalias) {
- errno = EINVAL;
- return NULL;
- }
+ assert_return_errno(hwdb, NULL, EINVAL);
+ assert_return_errno(modalias, NULL, EINVAL);
udev_list_cleanup(&hwdb->properties_list);
#include "libudev.h"
#include "alloc-util.h"
+#include "device-private.h"
+#include "device-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
-#include "libudev-private.h"
+#include "hashmap.h"
#include "libudev-device-internal.h"
+#include "libudev-private.h"
#include "missing.h"
#include "mount-util.h"
+#include "set.h"
#include "socket-util.h"
#include "string-util.h"
+#include "strv.h"
/**
* SECTION:libudev-monitor
*/
struct udev_monitor {
struct udev *udev;
- int refcount;
+ unsigned n_ref;
int sock;
union sockaddr_union snl;
union sockaddr_union snl_trusted_sender;
union sockaddr_union snl_destination;
socklen_t addrlen;
- struct udev_list filter_subsystem_list;
- struct udev_list filter_tag_list;
+ Hashmap *subsystem_filter;
+ Set *tag_filter;
bool bound;
};
* magic to protect against daemon <-> library message format mismatch
* used in the kernel from socket filter rules; needs to be stored in network order
*/
- unsigned int magic;
+ unsigned magic;
/* total length of header structure known to the sender */
- unsigned int header_size;
+ unsigned header_size;
/* properties string buffer */
- unsigned int properties_off;
- unsigned int properties_len;
+ unsigned properties_off;
+ unsigned properties_len;
/*
* hashes of primary device properties strings, to let libudev subscribers
* use in-kernel socket filters; values need to be stored in network order
*/
- unsigned int filter_subsystem_hash;
- unsigned int filter_devtype_hash;
- unsigned int filter_tag_bloom_hi;
- unsigned int filter_tag_bloom_lo;
+ unsigned filter_subsystem_hash;
+ unsigned filter_devtype_hash;
+ unsigned filter_tag_bloom_hi;
+ unsigned filter_tag_bloom_lo;
};
-static struct udev_monitor *udev_monitor_new(struct udev *udev) {
- struct udev_monitor *udev_monitor;
-
- udev_monitor = new0(struct udev_monitor, 1);
- if (udev_monitor == NULL) {
- errno = ENOMEM;
- return NULL;
- }
- udev_monitor->refcount = 1;
- udev_monitor->udev = udev;
- udev_list_init(udev, &udev_monitor->filter_subsystem_list, false);
- udev_list_init(udev, &udev_monitor->filter_tag_list, true);
- return udev_monitor;
-}
-
-/* we consider udev running when /dev is on devtmpfs */
-static bool udev_has_devtmpfs(struct udev *udev) {
-
- _cleanup_fclose_ FILE *f = NULL;
- char line[LINE_MAX], *e;
- int mount_id, r;
-
- r = path_get_mnt_id("/dev", &mount_id);
- if (r < 0) {
- if (r != -EOPNOTSUPP)
- log_debug_errno(r, "name_to_handle_at on /dev: %m");
-
- return false;
- }
-
- f = fopen("/proc/self/mountinfo", "re");
- if (!f)
- return false;
-
- FOREACH_LINE(line, f, return false) {
- int mid;
-
- if (sscanf(line, "%i", &mid) != 1)
- continue;
-
- if (mid != mount_id)
- continue;
-
- e = strstr(line, " - ");
- if (!e)
- continue;
-
- /* accept any name that starts with the currently expected type */
- if (startswith(e + 3, "devtmpfs"))
- return true;
- }
-
- return false;
-}
-
-static void monitor_set_nl_address(struct udev_monitor *udev_monitor) {
+static int udev_monitor_set_nl_address(struct udev_monitor *udev_monitor) {
union sockaddr_union snl;
socklen_t addrlen;
- int r;
assert(udev_monitor);
- /* get the address the kernel has assigned us
- * it is usually, but not necessarily the pid
- */
+ /* Get the address the kernel has assigned us.
+ * It is usually, but not necessarily the pid. */
addrlen = sizeof(struct sockaddr_nl);
- r = getsockname(udev_monitor->sock, &snl.sa, &addrlen);
- if (r >= 0)
- udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid;
+ if (getsockname(udev_monitor->sock, &snl.sa, &addrlen) < 0)
+ return -errno;
+
+ udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid;
+ return 0;
}
struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd) {
- struct udev_monitor *udev_monitor;
- unsigned int group;
+ _cleanup_(udev_monitor_unrefp) struct udev_monitor *udev_monitor = NULL;
+ _cleanup_close_ int sock = -1;
+ unsigned group;
+ int r;
- if (name == NULL)
+ assert_return_errno(!name || STR_IN_SET(name, "udev", "kernel"), NULL, EINVAL);
+
+ if (!name)
group = UDEV_MONITOR_NONE;
else if (streq(name, "udev")) {
/*
* We do not set a netlink multicast group here, so the socket
* will not receive any messages.
*/
- if (access("/run/udev/control", F_OK) < 0 && !udev_has_devtmpfs(udev)) {
- log_debug("the udev service seems not to be active, disable the monitor");
+ if (access("/run/udev/control", F_OK) < 0 && dev_is_devtmpfs() <= 0) {
+ log_debug("The udev service seems not to be active, disabling the monitor");
group = UDEV_MONITOR_NONE;
} else
group = UDEV_MONITOR_UDEV;
- } else if (streq(name, "kernel"))
+ } else {
+ assert(streq(name, "kernel"));
group = UDEV_MONITOR_KERNEL;
- else {
- errno = EINVAL;
- return NULL;
}
- udev_monitor = udev_monitor_new(udev);
- if (udev_monitor == NULL)
- return NULL;
-
if (fd < 0) {
- udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
- if (udev_monitor->sock < 0) {
- log_debug_errno(errno, "error getting socket: %m");
- return mfree(udev_monitor);
+ sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
+ if (sock < 0) {
+ log_debug_errno(errno, "Failed to create socket: %m");
+ return NULL;
}
- } else {
- udev_monitor->bound = true;
- udev_monitor->sock = fd;
- monitor_set_nl_address(udev_monitor);
}
- udev_monitor->snl.nl.nl_family = AF_NETLINK;
- udev_monitor->snl.nl.nl_groups = group;
+ udev_monitor = new(struct udev_monitor, 1);
+ if (!udev_monitor) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ *udev_monitor = (struct udev_monitor) {
+ .udev = udev,
+ .n_ref = 1,
+ .sock = fd >= 0 ? fd : TAKE_FD(sock),
+ .bound = fd >= 0,
+ .snl.nl.nl_family = AF_NETLINK,
+ .snl.nl.nl_groups = group,
+
+ /* default destination for sending */
+ .snl_destination.nl.nl_family = AF_NETLINK,
+ .snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV,
+ };
- /* default destination for sending */
- udev_monitor->snl_destination.nl.nl_family = AF_NETLINK;
- udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV;
+ if (fd >= 0) {
+ r = udev_monitor_set_nl_address(udev_monitor);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to set netlink address: %m");
+ return NULL;
+ }
+ }
- return udev_monitor;
+ return TAKE_PTR(udev_monitor);
}
/**
return udev_monitor_new_from_netlink_fd(udev, name, -1);
}
-static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i,
- unsigned short code, unsigned int data)
-{
- struct sock_filter *ins = &inss[*i];
-
- ins->code = code;
- ins->k = data;
- (*i)++;
+static void bpf_stmt(struct sock_filter *ins, unsigned *i,
+ unsigned short code, unsigned data) {
+ ins[(*i)++] = (struct sock_filter) {
+ .code = code,
+ .k = data,
+ };
}
-static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
- unsigned short code, unsigned int data,
- unsigned short jt, unsigned short jf)
-{
- struct sock_filter *ins = &inss[*i];
-
- ins->code = code;
- ins->jt = jt;
- ins->jf = jf;
- ins->k = data;
- (*i)++;
+static void bpf_jmp(struct sock_filter *ins, unsigned *i,
+ unsigned short code, unsigned data,
+ unsigned short jt, unsigned short jf) {
+ ins[(*i)++] = (struct sock_filter) {
+ .code = code,
+ .jt = jt,
+ .jf = jf,
+ .k = data,
+ };
}
/**
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
-{
- struct sock_filter ins[512];
+_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) {
+ struct sock_filter ins[512] = {};
struct sock_fprog filter;
- unsigned int i;
- struct udev_list_entry *list_entry;
- int err;
+ const char *subsystem, *devtype, *tag;
+ unsigned i = 0;
+ Iterator it;
- if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL &&
- udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
- return 0;
+ assert_return(udev_monitor, -EINVAL);
- memzero(ins, sizeof(ins));
- i = 0;
+ if (hashmap_isempty(udev_monitor->subsystem_filter) &&
+ set_isempty(udev_monitor->tag_filter))
+ return 0;
/* load magic in A */
bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic));
/* wrong magic, pass packet */
bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
- if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) {
- int tag_matches;
-
- /* count tag matches, to calculate end of tag match block */
- tag_matches = 0;
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))
- tag_matches++;
+ if (!set_isempty(udev_monitor->tag_filter)) {
+ int tag_matches = set_size(udev_monitor->tag_filter);
/* add all tags matches */
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
- uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry));
+ SET_FOREACH(tag, udev_monitor->tag_filter, it) {
+ uint64_t tag_bloom_bits = util_string_bloom64(tag);
uint32_t tag_bloom_hi = tag_bloom_bits >> 32;
uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff;
}
/* add all subsystem matches */
- if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) {
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
- unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry));
+ if (!hashmap_isempty(udev_monitor->subsystem_filter)) {
+ HASHMAP_FOREACH_KEY(devtype, subsystem, udev_monitor->subsystem_filter, it) {
+ uint32_t hash = util_string_hash32(subsystem);
/* load device subsystem value in A */
bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash));
- if (udev_list_entry_get_value(list_entry) == NULL) {
+ if (!devtype) {
/* jump if subsystem does not match */
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
} else {
+ hash = util_string_hash32(devtype);
+
/* jump if subsystem does not match */
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
-
/* load device devtype value in A */
bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash));
/* jump if value does not match */
- hash = util_string_hash32(udev_list_entry_get_value(list_entry));
bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
}
bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
/* install filter */
- memzero(&filter, sizeof(filter));
- filter.len = i;
- filter.filter = ins;
- err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
- return err < 0 ? -errno : 0;
+ filter = (struct sock_fprog) {
+ .len = i,
+ .filter = ins,
+ };
+ if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
+ return -errno;
+
+ return 0;
}
-int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
-{
+int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender) {
+ assert_return(udev_monitor, -EINVAL);
+ assert_return(sender, -EINVAL);
+
udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid;
return 0;
}
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
-{
- int err = 0;
+_public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) {
const int on = 1;
+ int r;
- udev_monitor_filter_update(udev_monitor);
+ assert_return(udev_monitor, -EINVAL);
+
+ r = udev_monitor_filter_update(udev_monitor);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to update filter: %m");
if (!udev_monitor->bound) {
- err = bind(udev_monitor->sock,
- &udev_monitor->snl.sa, sizeof(struct sockaddr_nl));
- if (err == 0)
- udev_monitor->bound = true;
+ if (bind(udev_monitor->sock, &udev_monitor->snl.sa, sizeof(struct sockaddr_nl)) < 0)
+ return log_debug_errno(errno, "Failed to bind udev monitor socket to event source: %m");
+
+ udev_monitor->bound = true;
}
- if (err >= 0)
- monitor_set_nl_address(udev_monitor);
- else
- return log_debug_errno(errno, "bind failed: %m");
+ r = udev_monitor_set_nl_address(udev_monitor);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to set address: %m");
/* enable receiving of sender credentials */
- err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
- if (err < 0)
- log_debug_errno(errno, "setting SO_PASSCRED failed: %m");
+ if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0)
+ return log_debug_errno(errno, "Failed to set socket option SO_PASSCRED: %m");
return 0;
}
*
* Returns: 0 on success, otherwise -1 on error.
*/
-_public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
-{
- if (udev_monitor == NULL)
- return -EINVAL;
+_public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) {
+ assert_return(udev_monitor, -EINVAL);
+
if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)) < 0)
return -errno;
return 0;
}
-int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
-{
- int err;
+int udev_monitor_disconnect(struct udev_monitor *udev_monitor) {
+ assert(udev_monitor);
+
+ udev_monitor->sock = safe_close(udev_monitor->sock);
+ return 0;
+}
+
+static struct udev_monitor *udev_monitor_free(struct udev_monitor *udev_monitor) {
+ assert(udev_monitor);
- err = close(udev_monitor->sock);
- udev_monitor->sock = -1;
- return err < 0 ? -errno : 0;
+ udev_monitor_disconnect(udev_monitor);
+ hashmap_free_free_free(udev_monitor->subsystem_filter);
+ set_free_free(udev_monitor->tag_filter);
+ return mfree(udev_monitor);
}
/**
*
* Returns: the passed udev monitor
**/
-_public_ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
-{
- if (udev_monitor == NULL)
- return NULL;
- udev_monitor->refcount++;
- return udev_monitor;
-}
/**
* udev_monitor_unref:
*
* Returns: #NULL
**/
-_public_ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor)
-{
- if (udev_monitor == NULL)
- return NULL;
- udev_monitor->refcount--;
- if (udev_monitor->refcount > 0)
- return NULL;
- if (udev_monitor->sock >= 0)
- close(udev_monitor->sock);
- udev_list_cleanup(&udev_monitor->filter_subsystem_list);
- udev_list_cleanup(&udev_monitor->filter_tag_list);
- return mfree(udev_monitor);
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_monitor, udev_monitor, udev_monitor_free);
/**
* udev_monitor_get_udev:
*
* Returns: the udev library context
**/
-_public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
-{
- if (udev_monitor == NULL)
- return NULL;
+_public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) {
+ assert_return(udev_monitor, NULL);
+
return udev_monitor->udev;
}
*
* Returns: the socket file descriptor
**/
-_public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
-{
- if (udev_monitor == NULL)
- return -EINVAL;
+_public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) {
+ assert_return(udev_monitor, -EINVAL);
+
return udev_monitor->sock;
}
-static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device)
-{
- struct udev_list_entry *list_entry;
+static int passes_filter(struct udev_monitor *udev_monitor, sd_device *device) {
+ const char *tag, *subsystem, *devtype, *s, *d = NULL;
+ Iterator i;
+ int r;
+
+ assert_return(udev_monitor, -EINVAL);
+ assert_return(device, -EINVAL);
- if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
+ if (hashmap_isempty(udev_monitor->subsystem_filter))
goto tag;
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
- const char *subsys = udev_list_entry_get_name(list_entry);
- const char *dsubsys = udev_device_get_subsystem(udev_device);
- const char *devtype;
- const char *ddevtype;
- if (!streq(dsubsys, subsys))
+ r = sd_device_get_subsystem(device, &s);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_devtype(device, &d);
+ if (r < 0 && r != -ENOENT)
+ return r;
+
+ HASHMAP_FOREACH_KEY(devtype, subsystem, udev_monitor->subsystem_filter, i) {
+ if (!streq(s, subsystem))
continue;
- devtype = udev_list_entry_get_value(list_entry);
- if (devtype == NULL)
+ if (!devtype)
goto tag;
- ddevtype = udev_device_get_devtype(udev_device);
- if (ddevtype == NULL)
+
+ if (!d)
continue;
- if (streq(ddevtype, devtype))
+
+ if (streq(d, devtype))
goto tag;
}
+
return 0;
tag:
- if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
+ if (set_isempty(udev_monitor->tag_filter))
return 1;
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
- const char *tag = udev_list_entry_get_name(list_entry);
- if (udev_device_has_tag(udev_device, tag))
+ SET_FOREACH(tag, udev_monitor->tag_filter, i)
+ if (sd_device_has_tag(device, tag) > 0)
return 1;
- }
+
return 0;
}
-/**
- * udev_monitor_receive_device:
- * @udev_monitor: udev monitor
- *
- * Receive data from the udev monitor socket, allocate a new udev
- * device, fill in the received data, and return the device.
- *
- * Only socket connections with uid=0 are accepted.
- *
- * The monitor socket is by default set to NONBLOCK. A variant of poll() on
- * the file descriptor returned by udev_monitor_get_fd() should to be used to
- * wake up when new devices arrive, or alternatively the file descriptor
- * switched into blocking mode.
- *
- * The initial refcount is 1, and needs to be decremented to
- * release the resources of the udev device.
- *
- * Returns: a new udev device, or #NULL, in case of an error
- **/
-_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
-{
- struct udev_device *udev_device;
- struct msghdr smsg;
- struct iovec iov;
- char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
- struct cmsghdr *cmsg;
- union sockaddr_union snl;
- struct ucred *cred;
+static int udev_monitor_receive_device_one(struct udev_monitor *udev_monitor, sd_device **ret) {
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
union {
struct udev_monitor_netlink_header nlh;
char raw[8192];
} buf;
- ssize_t buflen;
- ssize_t bufpos;
+ struct iovec iov = {
+ .iov_base = &buf,
+ .iov_len = sizeof(buf)
+ };
+ char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+ union sockaddr_union snl;
+ struct msghdr smsg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cred_msg,
+ .msg_controllen = sizeof(cred_msg),
+ .msg_name = &snl,
+ .msg_namelen = sizeof(snl),
+ };
+ struct cmsghdr *cmsg;
+ struct ucred *cred;
+ ssize_t buflen, bufpos;
bool is_initialized = false;
+ int r;
-retry:
- if (udev_monitor == NULL) {
- errno = EINVAL;
- return NULL;
- }
- iov.iov_base = &buf;
- iov.iov_len = sizeof(buf);
- memzero(&smsg, sizeof(struct msghdr));
- smsg.msg_iov = &iov;
- smsg.msg_iovlen = 1;
- smsg.msg_control = cred_msg;
- smsg.msg_controllen = sizeof(cred_msg);
- smsg.msg_name = &snl;
- smsg.msg_namelen = sizeof(snl);
+ assert(ret);
buflen = recvmsg(udev_monitor->sock, &smsg, 0);
if (buflen < 0) {
if (errno != EINTR)
- log_debug("unable to receive message");
- return NULL;
+ log_debug_errno(errno, "Failed to receive message: %m");
+ return -errno;
}
- if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) {
- log_debug("invalid message length");
- errno = EINVAL;
- return NULL;
- }
+ if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC))
+ return log_debug_errno(EINVAL, "Invalid message length.");
- if (snl.nl.nl_groups == 0) {
+ if (snl.nl.nl_groups == UDEV_MONITOR_NONE) {
/* unicast message, check if we trust the sender */
if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 ||
- snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) {
- log_debug("unicast netlink message ignored");
- errno = EAGAIN;
- return NULL;
- }
+ snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid)
+ return log_debug_errno(EAGAIN, "Unicast netlink message ignored.");
+
} else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) {
- if (snl.nl.nl_pid > 0) {
- log_debug("multicast kernel netlink message from PID %"PRIu32" ignored",
- snl.nl.nl_pid);
- errno = EAGAIN;
- return NULL;
- }
+ if (snl.nl.nl_pid > 0)
+ return log_debug_errno(EAGAIN, "Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid);
}
cmsg = CMSG_FIRSTHDR(&smsg);
- if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
- log_debug("no sender credentials received, message ignored");
- errno = EAGAIN;
- return NULL;
- }
+ if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
+ return log_debug_errno(EAGAIN, "No sender credentials received, message ignored.");
- cred = (struct ucred *)CMSG_DATA(cmsg);
- if (cred->uid != 0) {
- log_debug("sender uid="UID_FMT", message ignored", cred->uid);
- errno = EAGAIN;
- return NULL;
- }
+ cred = (struct ucred*) CMSG_DATA(cmsg);
+ if (cred->uid != 0)
+ return log_debug_errno(EAGAIN, "Sender uid="UID_FMT", message ignored.", cred->uid);
- if (memcmp(buf.raw, "libudev", 8) == 0) {
+ if (streq(buf.raw, "libudev")) {
/* udev message needs proper version magic */
- if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) {
- log_debug("unrecognized message signature (%x != %x)",
- buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
- errno = EAGAIN;
- return NULL;
- }
- if (buf.nlh.properties_off+32 > (size_t)buflen) {
- log_debug("message smaller than expected (%u > %zd)",
- buf.nlh.properties_off+32, buflen);
- errno = EAGAIN;
- return NULL;
- }
+ if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC))
+ return log_debug_errno(EAGAIN, "Invalid message signature (%x != %x)",
+ buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
+
+ if (buf.nlh.properties_off+32 > (size_t) buflen)
+ return log_debug_errno(EAGAIN, "Invalid message length (%u > %zd)",
+ buf.nlh.properties_off+32, buflen);
bufpos = buf.nlh.properties_off;
/* devices received from udev are always initialized */
is_initialized = true;
+
} else {
/* kernel message with header */
bufpos = strlen(buf.raw) + 1;
- if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
- log_debug("invalid message length");
- errno = EAGAIN;
- return NULL;
- }
+ if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen)
+ return log_debug_errno(EAGAIN, "Invalid message length");
/* check message header */
- if (strstr(buf.raw, "@/") == NULL) {
- log_debug("unrecognized message header");
- errno = EAGAIN;
- return NULL;
- }
+ if (!strstr(buf.raw, "@/"))
+ return log_debug_errno(EAGAIN, "Invalid message header");
}
- udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos);
- if (!udev_device) {
- log_debug_errno(errno, "could not create device: %m");
- return NULL;
- }
+ r = device_new_from_nulstr(&device, (uint8_t*) &buf.raw[bufpos], buflen - bufpos);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to create device: %m");
if (is_initialized)
- udev_device_set_is_initialized(udev_device);
+ device_set_is_initialized(device);
/* skip device, if it does not pass the current filter */
- if (!passes_filter(udev_monitor, udev_device)) {
- struct pollfd pfd[1];
- int rc;
+ if (passes_filter(udev_monitor, device) <= 0)
+ return 0;
- udev_device_unref(udev_device);
+ *ret = TAKE_PTR(device);
+ return 1;
+}
- /* if something is queued, get next device */
- pfd[0].fd = udev_monitor->sock;
- pfd[0].events = POLLIN;
- rc = poll(pfd, 1, 0);
- if (rc > 0)
- goto retry;
+int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) {
+ struct pollfd pfd = {
+ .fd = udev_monitor->sock,
+ .events = POLLIN,
+ };
+ int r;
- errno = EAGAIN;
- return NULL;
- }
+ assert(udev_monitor);
+ assert(ret);
- return udev_device;
+ for (;;) {
+ /* r == 0 means a device is received but it does not pass the current filter. */
+ r = udev_monitor_receive_device_one(udev_monitor, ret);
+ if (r != 0)
+ return r;
+
+ for (;;) {
+ /* wait next message */
+ r = poll(&pfd, 1, 0);
+ if (r < 0) {
+ if (IN_SET(errno, EINTR, EAGAIN))
+ continue;
+
+ return -errno;
+ } else if (r == 0)
+ return -EAGAIN;
+
+ /* receive next message */
+ break;
+ }
+ }
}
-int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_device **ret) {
- _cleanup_(udev_device_unrefp) struct udev_device *udev_device = NULL;
+/**
+ * udev_monitor_receive_device:
+ * @udev_monitor: udev monitor
+ *
+ * Receive data from the udev monitor socket, allocate a new udev
+ * device, fill in the received data, and return the device.
+ *
+ * Only socket connections with uid=0 are accepted.
+ *
+ * The monitor socket is by default set to NONBLOCK. A variant of poll() on
+ * the file descriptor returned by udev_monitor_get_fd() should to be used to
+ * wake up when new devices arrive, or alternatively the file descriptor
+ * switched into blocking mode.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev device.
+ *
+ * Returns: a new udev device, or #NULL, in case of an error
+ **/
+_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) {
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL;
+ int r;
- assert(ret);
+ assert_return(udev_monitor, NULL);
- udev_device = udev_monitor_receive_device(udev_monitor);
- if (!udev_device)
- return -errno;
+ r = udev_monitor_receive_sd_device(udev_monitor, &device);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
+ }
- *ret = sd_device_ref(udev_device->device);
- return 0;
+ return udev_device_new(udev_monitor->udev, device);
}
-int udev_monitor_send_device(struct udev_monitor *udev_monitor,
- struct udev_monitor *destination, struct udev_device *udev_device)
-{
- const char *buf, *val;
- ssize_t blen, count;
+static int udev_monitor_send_sd_device(
+ struct udev_monitor *udev_monitor,
+ struct udev_monitor *destination,
+ sd_device *device) {
+
struct udev_monitor_netlink_header nlh = {
.prefix = "libudev",
.magic = htobe32(UDEV_MONITOR_MAGIC),
.msg_iov = iov,
.msg_iovlen = 2,
};
- struct udev_list_entry *list_entry;
uint64_t tag_bloom_bits;
+ const char *buf, *val;
+ ssize_t count;
+ size_t blen;
+ int r;
- blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
+ assert(udev_monitor);
+ assert(device);
+
+ r = device_get_properties_nulstr(device, (const uint8_t **) &buf, &blen);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to get device properties: %m");
if (blen < 32) {
- log_debug("device buffer is too small to contain a valid device");
+ log_debug("Device buffer is too small to contain a valid device");
return -EINVAL;
}
/* fill in versioned header */
- val = udev_device_get_subsystem(udev_device);
+ r = sd_device_get_subsystem(device, &val);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to get device subsystem: %m");
nlh.filter_subsystem_hash = htobe32(util_string_hash32(val));
- val = udev_device_get_devtype(udev_device);
- if (val != NULL)
+ if (sd_device_get_devtype(device, &val) >= 0 && val)
nlh.filter_devtype_hash = htobe32(util_string_hash32(val));
/* add tag bloom filter */
tag_bloom_bits = 0;
- udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
- tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry));
+ FOREACH_DEVICE_TAG(device, val)
+ tag_bloom_bits |= util_string_bloom64(val);
+
if (tag_bloom_bits > 0) {
nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32);
nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff);
/* add properties list */
nlh.properties_off = iov[0].iov_len;
nlh.properties_len = blen;
- iov[1].iov_base = (char *)buf;
- iov[1].iov_len = blen;
+ iov[1] = (struct iovec) {
+ .iov_base = (char*) buf,
+ .iov_len = blen,
+ };
/*
* Use custom address for target, or the default one.
* If we send to a multicast group, we will get
* ECONNREFUSED, which is expected.
*/
- if (destination)
- smsg.msg_name = &destination->snl;
- else
- smsg.msg_name = &udev_monitor->snl_destination;
+ smsg.msg_name = destination ? &destination->snl : &udev_monitor->snl_destination;
smsg.msg_namelen = sizeof(struct sockaddr_nl);
count = sendmsg(udev_monitor->sock, &smsg, 0);
if (count < 0) {
if (!destination && errno == ECONNREFUSED) {
- log_debug("passed device to netlink monitor %p", udev_monitor);
+ log_debug("Passed device to netlink monitor %p", udev_monitor);
return 0;
} else
- return -errno;
+ return log_debug_errno(errno, "Failed to send device to netlink monitor %p", udev_monitor);
}
- log_debug("passed %zi byte device to netlink monitor %p", count, udev_monitor);
+ log_debug("Passed %zi byte device to netlink monitor %p", count, udev_monitor);
return count;
}
+int udev_monitor_send_device(
+ struct udev_monitor *udev_monitor,
+ struct udev_monitor *destination,
+ struct udev_device *udev_device) {
+ assert(udev_device);
+
+ return udev_monitor_send_sd_device(udev_monitor, destination, udev_device->device);
+}
+
/**
* udev_monitor_filter_add_match_subsystem_devtype:
* @udev_monitor: the monitor
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
-{
- if (udev_monitor == NULL)
- return -EINVAL;
- if (subsystem == NULL)
- return -EINVAL;
- if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL)
+_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) {
+ _cleanup_free_ char *s = NULL, *d = NULL;
+ int r;
+
+ assert_return(udev_monitor, -EINVAL);
+ assert_return(subsystem, -EINVAL);
+
+ s = strdup(subsystem);
+ if (!s)
return -ENOMEM;
+
+ if (devtype) {
+ d = strdup(devtype);
+ if (!d)
+ return -ENOMEM;
+ }
+
+ r = hashmap_ensure_allocated(&udev_monitor->subsystem_filter, NULL);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(udev_monitor->subsystem_filter, s, d);
+ if (r < 0)
+ return r;
+
+ s = d = NULL;
return 0;
}
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag)
-{
- if (udev_monitor == NULL)
- return -EINVAL;
- if (tag == NULL)
- return -EINVAL;
- if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL)
+_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert_return(udev_monitor, -EINVAL);
+ assert_return(tag, -EINVAL);
+
+ t = strdup(tag);
+ if (!t)
return -ENOMEM;
+
+ r = set_ensure_allocated(&udev_monitor->tag_filter, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(udev_monitor->tag_filter, t);
+ if (r == -EEXIST)
+ return 0;
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(t);
return 0;
}
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
-{
+_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) {
static const struct sock_fprog filter = { 0, NULL };
- udev_list_cleanup(&udev_monitor->filter_subsystem_list);
+ assert_return(udev_monitor, -EINVAL);
+
+ udev_monitor->subsystem_filter = hashmap_free_free_free(udev_monitor->subsystem_filter);
+ udev_monitor->tag_filter = set_free_free(udev_monitor->tag_filter);
+
if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
return -errno;
#define READ_END 0
#define WRITE_END 1
-/* libudev.c */
-int udev_get_rules_path(struct udev *udev, char **path[], usec_t *ts_usec[]);
-
/* libudev-device.c */
struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen);
struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, const char *syspath, const char *action);
int udev_device_add_tag(struct udev_device *udev_device, const char *tag);
void udev_device_remove_tag(struct udev_device *udev_device, const char *tag);
void udev_device_cleanup_tags_list(struct udev_device *udev_device);
-usec_t udev_device_get_usec_initialized(struct udev_device *udev_device);
void udev_device_ensure_usec_initialized(struct udev_device *udev_device, struct udev_device *old_device);
int udev_device_get_devlink_priority(struct udev_device *udev_device);
int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio);
int udev_device_set_watch_handle(struct udev_device *udev_device, int handle);
int udev_device_get_ifindex(struct udev_device *udev_device);
void udev_device_set_info_loaded(struct udev_device *device);
-bool udev_device_get_db_persist(struct udev_device *udev_device);
void udev_device_set_db_persist(struct udev_device *udev_device);
void udev_device_read_db(struct udev_device *udev_device);
-
-/* libudev-device-private.c */
int udev_device_update_db(struct udev_device *udev_device);
int udev_device_delete_db(struct udev_device *udev_device);
int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add);
entry != NULL; \
entry = tmp, tmp = udev_list_entry_get_next(tmp))
-/* libudev-queue.c */
-unsigned long long int udev_get_kernel_seqnum(struct udev *udev);
-int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum);
-ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size);
-ssize_t udev_queue_skip_devpath(FILE *queue_file);
-
-/* libudev-queue-private.c */
-struct udev_queue_export *udev_queue_export_new(struct udev *udev);
-struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export);
-void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export);
-int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
-int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
-
/* libudev-util.c */
#define UTIL_PATH_SIZE 1024
#define UTIL_NAME_SIZE 512
*/
struct udev_queue {
struct udev *udev;
- int refcount;
+ unsigned n_ref;
int fd;
};
*
* Returns: the udev queue context, or #NULL on error.
**/
-_public_ struct udev_queue *udev_queue_new(struct udev *udev)
-{
+_public_ struct udev_queue *udev_queue_new(struct udev *udev) {
struct udev_queue *udev_queue;
- udev_queue = new0(struct udev_queue, 1);
+ udev_queue = new(struct udev_queue, 1);
if (udev_queue == NULL) {
errno = ENOMEM;
return NULL;
}
- udev_queue->refcount = 1;
- udev_queue->udev = udev;
- udev_queue->fd = -1;
+ *udev_queue = (struct udev_queue) {
+ .udev = udev,
+ .n_ref = 1,
+ .fd = -1,
+ };
+
return udev_queue;
}
+static struct udev_queue *udev_queue_free(struct udev_queue *udev_queue) {
+ assert(udev_queue);
+
+ safe_close(udev_queue->fd);
+ return mfree(udev_queue);
+}
+
/**
* udev_queue_ref:
* @udev_queue: udev queue context
*
* Returns: the same udev queue context.
**/
-_public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
-{
- if (udev_queue == NULL)
- return NULL;
-
- udev_queue->refcount++;
- return udev_queue;
-}
/**
* udev_queue_unref:
*
* Returns: #NULL
**/
-_public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
-{
- if (udev_queue == NULL)
- return NULL;
-
- udev_queue->refcount--;
- if (udev_queue->refcount > 0)
- return NULL;
-
- safe_close(udev_queue->fd);
-
- return mfree(udev_queue);
-}
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_queue, udev_queue, udev_queue_free);
/**
* udev_queue_get_udev:
*
* Returns: the udev library context.
**/
-_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
-{
- if (udev_queue == NULL) {
- errno = EINVAL;
- return NULL;
- }
+_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) {
+ assert_return_errno(udev_queue, NULL, EINVAL);
+
return udev_queue->udev;
}
*
* Returns: 0.
**/
-_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
-{
+_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) {
return 0;
}
*
* Returns: 0.
**/
-_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
-{
+_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) {
return 0;
}
*
* Returns: a flag indicating if udev is active.
**/
-_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
-{
+_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) {
return access("/run/udev/control", F_OK) >= 0;
}
*
* Returns: a flag indicating if udev is currently handling events.
**/
-_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
-{
+_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) {
return access("/run/udev/queue", F_OK) < 0;
}
* Returns: a flag indicating if udev is currently handling events.
**/
_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
- unsigned long long int start, unsigned long long int end)
-{
+ unsigned long long int start, unsigned long long int end) {
return udev_queue_get_queue_is_empty(udev_queue);
}
*
* Returns: a flag indicating if udev is currently handling events.
**/
-_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
-{
+_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) {
return udev_queue_get_queue_is_empty(udev_queue);
}
*
* Returns: NULL.
**/
-_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
-{
+_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) {
errno = ENODATA;
return NULL;
}
* Returns: a file descriptor to watch for a queue to become empty.
*/
_public_ int udev_queue_get_fd(struct udev_queue *udev_queue) {
- int fd;
- int r;
+ _cleanup_close_ int fd = -1;
+
+ assert_return(udev_queue, -EINVAL);
if (udev_queue->fd >= 0)
return udev_queue->fd;
if (fd < 0)
return -errno;
- r = inotify_add_watch(fd, "/run/udev" , IN_DELETE);
- if (r < 0) {
- r = -errno;
- close(fd);
- return r;
- }
+ if (inotify_add_watch(fd, "/run/udev" , IN_DELETE) < 0)
+ return -errno;
- udev_queue->fd = fd;
- return fd;
+ udev_queue->fd = TAKE_FD(fd);
+ return udev_queue->fd;
}
/**
_public_ int udev_queue_flush(struct udev_queue *udev_queue) {
int r;
- assert(udev_queue);
+ assert_return(udev_queue, -EINVAL);
if (udev_queue->fd < 0)
return -EINVAL;
/**
* SECTION:libudev
* @short_description: libudev context
- *
- * The context contains the default values read from the udev config file,
- * and is passed to all library operations.
*/
/**
* Opaque object representing the library context.
*/
struct udev {
- int refcount;
- void (*log_fn)(struct udev *udev,
- int priority, const char *file, int line, const char *fn,
- const char *format, va_list args);
+ unsigned n_ref;
void *userdata;
};
* Returns: stored userdata
**/
_public_ void *udev_get_userdata(struct udev *udev) {
- if (udev == NULL)
- return NULL;
+ assert_return(udev, NULL);
+
return udev->userdata;
}
* Store custom @userdata in the library context.
**/
_public_ void udev_set_userdata(struct udev *udev, void *userdata) {
- if (udev == NULL)
+ if (!udev)
return;
+
udev->userdata = userdata;
}
_public_ struct udev *udev_new(void) {
struct udev *udev;
- udev = new0(struct udev, 1);
+ udev = new(struct udev, 1);
if (!udev) {
errno = ENOMEM;
return NULL;
}
- udev->refcount = 1;
+
+ *udev = (struct udev) {
+ .n_ref = 1,
+ };
return udev;
}
*
* Returns: the passed udev library context
**/
-_public_ struct udev *udev_ref(struct udev *udev) {
- if (udev == NULL)
- return NULL;
- udev->refcount++;
- return udev;
-}
+DEFINE_PUBLIC_TRIVIAL_REF_FUNC(struct udev, udev);
/**
* udev_unref:
* Returns: the passed udev library context if it has still an active reference, or #NULL otherwise.
**/
_public_ struct udev *udev_unref(struct udev *udev) {
- if (udev == NULL)
+ if (!udev)
return NULL;
- udev->refcount--;
- if (udev->refcount > 0)
+
+ assert(udev->n_ref > 0);
+ udev->n_ref--;
+ if (udev->n_ref > 0)
+ /* This is different from our convetion, but let's keep backward
+ * compatibility. So, do not use DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC()
+ * macro to define this function. */
return udev;
+
return mfree(udev);
}
* This function is deprecated.
*
**/
-_public_ void udev_set_log_fn(struct udev *udev,
- void (*log_fn)(struct udev *udev,
- int priority, const char *file, int line, const char *fn,
- const char *format, va_list args)) {
+_public_ void udev_set_log_fn(
+ struct udev *udev,
+ void (*log_fn)(struct udev *udev,
+ int priority, const char *file, int line, const char *fn,
+ const char *format, va_list args)) {
return;
}
unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
-int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value);
+int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, const char *value);
int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
/*
#include "bus-error.h"
#include "bus-util.h"
#include "fd-util.h"
+#include "format-table.h"
#include "format-util.h"
#include "pager.h"
#include "process-util.h"
static const char* arg_why = "Unknown reason";
static const char* arg_mode = NULL;
static bool arg_no_pager = false;
+static bool arg_legend = true;
static enum {
ACTION_INHIBIT,
return r;
}
-static int print_inhibitors(sd_bus *bus, sd_bus_error *error) {
+static int print_inhibitors(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;
- const char *what, *who, *why, *mode;
- unsigned int uid, pid;
- unsigned n = 0;
+ _cleanup_(table_unrefp) Table *table = NULL;
int r;
(void) pager_open(arg_no_pager, false);
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"ListInhibitors",
- error,
+ &error,
&reply,
"");
if (r < 0)
- return r;
+ return log_error_errno(r, "Could not get active inhibitors: %s", bus_error_message(&error, r));
+
+ table = table_new("WHO", "UID", "USER", "PID", "COMM", "WHAT", "WHY", "MODE");
+ if (!table)
+ return log_oom();
+
+ /* If there's not enough space, shorten the "WHY" column, as it's little more than an explaining comment. */
+ (void) table_set_weight(table, TABLE_HEADER_CELL(6), 20);
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
if (r < 0)
return bus_log_parse_error(r);
- while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
+ for (;;) {
_cleanup_free_ char *comm = NULL, *u = NULL;
+ const char *what, *who, *why, *mode;
+ uint32_t uid, pid;
+
+ r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ if (r == 0)
+ break;
if (arg_mode && !streq(mode, arg_mode))
continue;
- get_process_comm(pid, &comm);
+ (void) get_process_comm(pid, &comm);
u = uid_to_name(uid);
- printf(" Who: %s (UID "UID_FMT"/%s, PID "PID_FMT"/%s)\n"
- " What: %s\n"
- " Why: %s\n"
- " Mode: %s\n\n",
- who, uid, strna(u), pid, strna(comm),
- what,
- why,
- mode);
-
- n++;
+ r = table_add_many(table,
+ TABLE_STRING, who,
+ TABLE_UINT32, uid,
+ TABLE_STRING, strna(u),
+ TABLE_UINT32, pid,
+ TABLE_STRING, strna(comm),
+ TABLE_STRING, what,
+ TABLE_STRING, why,
+ TABLE_STRING, mode);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add table row: %m");
}
- if (r < 0)
- return bus_log_parse_error(r);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
- printf("%u inhibitors listed.\n", n);
+ if (table_get_rows(table) > 1) {
+ r = table_set_sort(table, (size_t) 1, (size_t) 0, (size_t) 5, (size_t) 6, (size_t) -1);
+ if (r < 0)
+ return log_error_errno(r, "Failed to sort table: %m");
+
+ table_set_header(table, arg_legend);
+
+ r = table_print(table, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to show table: %m");
+ }
+
+ if (arg_legend) {
+ if (table_get_rows(table) > 1)
+ printf("\n%zu inhibitors listed.\n", table_get_rows(table) - 1);
+ else
+ printf("No inhibitors.\n");
+ }
+
return 0;
}
" -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
+ " --no-legend Do not show the headers and footers\n"
" --what=WHAT Operations to inhibit, colon separated list of:\n"
" shutdown, sleep, idle, handle-power-key,\n"
" handle-suspend-key, handle-hibernate-key,\n"
ARG_MODE,
ARG_LIST,
ARG_NO_PAGER,
+ ARG_NO_LEGEND,
};
static const struct option options[] = {
{ "mode", required_argument, NULL, ARG_MODE },
{ "list", no_argument, NULL, ARG_LIST },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{}
};
arg_no_pager = true;
break;
+ case ARG_NO_LEGEND:
+ arg_legend = false;
+ break;
+
case '?':
return -EINVAL;
}
int main(int argc, char *argv[]) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
if (arg_action == ACTION_LIST) {
- r = print_inhibitors(bus, &error);
+ r = print_inhibitors(bus);
pager_close();
- if (r < 0) {
- log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r));
+ if (r < 0)
return EXIT_FAILURE;
- }
} else {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_close_ int fd = -1;
_cleanup_free_ char *w = NULL;
pid_t pid;
#include "acl-util.h"
#include "alloc-util.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
#include "dirent-util.h"
#include "escape.h"
#include "fd-util.h"
if (r < 0)
return r;
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+ FOREACH_DEVICE(e, d) {
const char *node, *sn;
if (sd_device_get_property_value(d, "ID_SEAT", &sn) < 0 || isempty(sn))
if (sd_device_get_devname(d, &node) < 0)
continue;
- n = strdup(node);
- if (!n)
- return -ENOMEM;
-
- log_debug("Found udev node %s for seat %s", n, seat);
- r = set_consume(nodes, n);
+ log_debug("Found udev node %s for seat %s", node, seat);
+ r = set_put_strdup(nodes, node);
if (r < 0)
return r;
}
#include "bus-util.h"
#include "cgroup-util.h"
#include "conf-parser.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
#include "fd-util.h"
#include "logind.h"
#include "parse-util.h"
}
int manager_process_seat_device(Manager *m, sd_device *d) {
- const char *action = NULL;
+ const char *action;
Device *device;
int r;
assert(m);
- (void) sd_device_get_property_value(d, "ACTION", &action);
- if (streq_ptr(action, "remove")) {
+ if (sd_device_get_property_value(d, "ACTION", &action) >= 0 &&
+ streq(action, "remove")) {
const char *syspath;
r = sd_device_get_syspath(d, &syspath);
}
int manager_process_button_device(Manager *m, sd_device *d) {
- const char *action = NULL, *sysname;
+ const char *action, *sysname;
Button *b;
int r;
if (r < 0)
return r;
- (void) sd_device_get_property_value(d, "ACTION", &action);
- if (streq_ptr(action, "remove")) {
+ if (sd_device_get_property_value(d, "ACTION", &action) >= 0 &&
+ streq(action, "remove")) {
b = hashmap_get(m->buttons, sysname);
if (!b)
button_free(b);
} else {
- const char *sn = NULL;
+ const char *sn;
r = manager_add_button(m, sysname, &b);
if (r < 0)
if (r < 0)
return r;
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+ FOREACH_DEVICE(e, d) {
sd_device *p;
const char *status, *enabled, *dash, *nn, *i, *subsys;
bool external = false;
if (sd_device_get_sysname(d, &nn) < 0)
continue;
- /* Ignore internal displays: the type is encoded in
- * the sysfs name, as the second dash separated item
- * (the first is the card name, the last the connector
- * number). We implement a whitelist of external
- * displays here, rather than a whitelist, to ensure
- * we don't block suspends too eagerly. */
+ /* Ignore internal displays: the type is encoded in the sysfs name, as the second dash separated item
+ * (the first is the card name, the last the connector number). We implement a blacklist of external
+ * displays here, rather than a whitelist of internal ones, to ensure we don't block suspends too
+ * eagerly. */
dash = strchr(nn, '-');
if (!dash)
continue;
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
#include "dirent-util.h"
#include "efivars.h"
#include "escape.h"
return r;
}
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+ FOREACH_DEVICE(e, d) {
_cleanup_free_ char *t = NULL;
const char *p;
sd_device_get_subsystem(dev, &subsystem) < 0)
return type;
- if (streq_ptr(subsystem, "drm")) {
+ if (streq(subsystem, "drm")) {
if (startswith(sysname, "card"))
type = DEVICE_TYPE_DRM;
- } else if (streq_ptr(subsystem, "input")) {
+ } else if (streq(subsystem, "input")) {
if (startswith(sysname, "event"))
type = DEVICE_TYPE_EVDEV;
}
static int session_device_verify(SessionDevice *sd) {
_cleanup_(sd_device_unrefp) sd_device *p = NULL;
+ const char *sp, *node;
sd_device *dev;
- const char *sp = NULL, *node;
int r;
- if (sd_device_new_from_devnum(&p, 'c', sd->dev) < 0)
- return -ENODEV;
+ r = sd_device_new_from_devnum(&p, 'c', sd->dev);
+ if (r < 0)
+ return r;
dev = p;
- (void) sd_device_get_syspath(dev, &sp);
- if (sd_device_get_devname(dev, &node) < 0)
+ if (sd_device_get_syspath(dev, &sp) < 0 ||
+ sd_device_get_devname(dev, &node) < 0)
return -EINVAL;
/* detect device type so we can find the correct sysfs parent */
#include "bus-util.h"
#include "cgroup-util.h"
#include "def.h"
-#include "device-enumerator-private.h"
+#include "device-util.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "format-util.h"
if (r < 0)
return r;
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+ FOREACH_DEVICE(e, d) {
int k;
k = manager_process_seat_device(m, d);
if (r < 0)
return r;
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+ FOREACH_DEVICE(e, d) {
int k;
k = manager_process_button_device(m, d);
if (sd_device_get_sysname(d, &name) >= 0 &&
startswith(name, "vcsa") &&
sd_device_get_property_value(d, "ACTION", &action) >= 0 &&
- streq_ptr(action, "remove"))
+ streq(action, "remove"))
seat_preallocate_vts(m->seat0);
return 0;
max_width = n_columns;
while (*i_dev < n_dev) {
- const char *sysfs, *sn, *name = NULL, *subsystem = NULL, *sysname = NULL;
+ const char *sysfs, *sn, *name = NULL, *subsystem, *sysname;
_cleanup_free_ char *k = NULL, *l = NULL;
size_t lookahead;
bool is_master;
sn = "seat0";
/* Explicitly also check for tag 'seat' here */
- if (!streq(seat, sn) || sd_device_has_tag(dev_list[*i_dev], "seat") <= 0) {
+ if (!streq(seat, sn) ||
+ sd_device_has_tag(dev_list[*i_dev], "seat") <= 0 ||
+ sd_device_get_subsystem(dev_list[*i_dev], &subsystem) < 0 ||
+ sd_device_get_sysname(dev_list[*i_dev], &sysname) < 0) {
(*i_dev)++;
continue;
}
if (sd_device_get_sysattr_value(dev_list[*i_dev], "name", &name) < 0)
(void) sd_device_get_sysattr_value(dev_list[*i_dev], "id", &name);
- (void) sd_device_get_subsystem(dev_list[*i_dev], &subsystem);
- (void) sd_device_get_sysname(dev_list[*i_dev], &sysname);
-
/* Look if there's more coming after this */
for (lookahead = *i_dev + 1; lookahead < n_dev; lookahead++) {
const char *lookahead_sysfs;
int show_sysfs(const char *seat, const char *prefix, unsigned n_columns, OutputFlags flags) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
- size_t n_dev = 0, n_allocated = 0, i = 0;
- sd_device *d, **dev_list = NULL;
+ size_t n_dev = 0, i = 0;
+ sd_device **dev_list;
int r;
if (n_columns <= 0)
if (r < 0)
return r;
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
- const char *syspath;
-
- if (sd_device_get_syspath(d, &syspath) < 0)
- continue;
-
- if (!GREEDY_REALLOC(dev_list, n_allocated, n_dev + 2))
- return -ENOMEM;
-
- dev_list[n_dev++] = sd_device_ref(d);
- dev_list[n_dev] = NULL;
- }
+ dev_list = device_enumerator_get_devices(e, &n_dev);
- if (n_dev > 0)
+ if (dev_list && n_dev > 0)
show_sysfs_one(seat, dev_list, &i, n_dev, "/", prefix, n_columns, flags);
else
printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), "(none)");
- for (i = 0; i < n_dev; i++)
- sd_device_unref(dev_list[i]);
- free(dev_list);
-
return 0;
}
double progress;
} TransferInfo;
-static int compare_transfer_info(const void *a, const void *b) {
- const TransferInfo *x = a, *y = b;
-
- return strcmp(x->local, y->local);
+static int compare_transfer_info(const TransferInfo *a, const TransferInfo *b) {
+ return strcmp(a->local, b->local);
}
static int list_transfers(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
- qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
+ typesafe_qsort(transfers, n_transfers, compare_transfer_info);
if (arg_legend && n_transfers > 0)
printf("%-*s %-*s %-*s %-*s %-*s\n",
#include "sd-bus.h"
#include "sd-device.h"
-#include "device-enumerator-private.h"
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
+#include "device-util.h"
#include "dirent-util.h"
#include "escape.h"
#include "fd-util.h"
char* columns[_COLUMN_MAX];
};
-static int compare_item(const void *a, const void *b) {
- const struct item *x = a, *y = b;
-
- if (x->columns[COLUMN_NODE] == y->columns[COLUMN_NODE])
+static int compare_item(const struct item *a, const struct item *b) {
+ if (a->columns[COLUMN_NODE] == b->columns[COLUMN_NODE])
return 0;
- if (!x->columns[COLUMN_NODE])
+ if (!a->columns[COLUMN_NODE])
return 1;
- if (!y->columns[COLUMN_NODE])
+ if (!b->columns[COLUMN_NODE])
return -1;
- return path_compare(x->columns[COLUMN_NODE], y->columns[COLUMN_NODE]);
+ return path_compare(a->columns[COLUMN_NODE], b->columns[COLUMN_NODE]);
}
static int list_devices(void) {
if (r < 0)
return log_error_errno(r, "Failed to add property match: %m");
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return log_error_errno(r, "Failed to enumerate devices: %m");
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
+ FOREACH_DEVICE(e, d) {
struct item *j;
if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
goto finish;
}
- qsort_safe(items, n, sizeof(struct item), compare_item);
+ typesafe_qsort(items, n, compare_item);
(void) pager_open(arg_no_pager, false);
static bool arg_all = false;
static char *link_get_type_string(unsigned short iftype, sd_device *d) {
- const char *t;
+ const char *t, *devtype;
char *p;
- if (d) {
- const char *devtype = NULL;
-
- (void) sd_device_get_devtype(d, &devtype);
- if (!isempty(devtype))
- return strdup(devtype);
- }
+ if (d &&
+ sd_device_get_devtype(d, &devtype) >= 0 &&
+ !isempty(devtype))
+ return strdup(devtype);
t = arphrd_to_name(iftype);
if (!t)
bool has_mtu:1;
} LinkInfo;
-static int link_info_compare(const void *a, const void *b) {
- const LinkInfo *x = a, *y = b;
-
- return x->ifindex - y->ifindex;
+static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
+ return CMP(a->ifindex, b->ifindex);
}
static int decode_link(sd_netlink_message *m, LinkInfo *info) {
c++;
}
- qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
+ typesafe_qsort(links, c, link_info_compare);
*ret = TAKE_PTR(links);
c++;
}
- qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
+ typesafe_qsort(links, c, link_info_compare);
*ret = TAKE_PTR(links);
(void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
(void) sd_device_get_property_value(d, "ID_PATH", &path);
- r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor);
- if (r < 0)
+ if (sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
(void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
- r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model);
- if (r < 0)
+ if (sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model) < 0)
(void) sd_device_get_property_value(d, "ID_MODEL", &model);
}
return sd_radv_start(radv);
}
-static Network *dhcp6_reset_pd_prefix_network(Link *link) {
- assert(link);
- assert(link->manager);
- assert(link->manager->networks);
+static int dhcp6_route_remove_cb(sd_netlink *nl, sd_netlink_message *m,
+ void *userdata) {
+ Link *l = userdata;
+ int r;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0)
+ log_link_debug_errno(l, r, "Received error on unreachable route removal for DHCPv6 delegated subnetl: %m");
+
+ l = link_unref(l);
+
+ return 0;
+}
+
+int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) {
+ int r;
+ sd_dhcp6_lease *lease;
+ union in_addr_union pd_prefix;
+ uint8_t pd_prefix_len;
+ uint32_t lifetime_preferred, lifetime_valid;
+
+ r = sd_dhcp6_client_get_lease(client, &lease);
+ if (r < 0)
+ return r;
+
+ sd_dhcp6_lease_reset_pd_prefix_iter(lease);
+
+ while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
+ &lifetime_preferred,
+ &lifetime_valid) >= 0) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_free_ Route *route;
+
+ if (pd_prefix_len > 64)
+ continue;
+
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
+
+ if (pd_prefix_len < 64) {
+ r = route_new(&route);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Cannot create unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ continue;
+ }
+
+ route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
+ 0, 0, 0, &route);
+ route_update(route, NULL, 0, NULL, NULL, 0, 0,
+ RTN_UNREACHABLE);
+
+ r = route_remove(route, link, dhcp6_route_remove_cb);
+ if (r < 0) {
+ (void) in_addr_to_string(AF_INET6,
+ &pd_prefix, &buf);
+
+ log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ route_free(route);
+ continue;
+ }
+ link = link_ref(link);
+
+ log_link_debug(link, "Removing unreachable route %s/%u",
+ strnull(buf), pd_prefix_len);
+ }
+ }
- return link->manager->networks;
+ return 0;
}
static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
return r;
}
- if (n_used < n_prefixes) {
- Route *route;
- uint64_t n = n_used;
-
- r = route_new(&route);
- if (r < 0)
- return r;
-
- route->family = AF_INET6;
+ return 0;
+}
- while (n < n_prefixes) {
- route_update(route, &prefix, pd_prefix_len, NULL, NULL,
- 0, 0, RTN_UNREACHABLE);
+static int dhcp6_route_add_cb(sd_netlink *nl, sd_netlink_message *m,
+ void *userdata) {
+ Link *l = userdata;
+ int r;
- r = route_configure(route, dhcp6_link, NULL);
- if (r < 0) {
- route_free(route);
- return r;
- }
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST)
+ log_link_debug_errno(l, r, "Received error when adding unreachable route for DHCPv6 delegated subnet: %m");
- r = in_addr_prefix_next(AF_INET6, &prefix, pd_prefix_len);
- if (r < 0)
- return r;
- }
- }
+ l = link_unref(l);
- return n_used;
+ return 0;
}
+
static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
int r;
sd_dhcp6_lease *lease;
- struct in6_addr pd_prefix;
+ union in_addr_union pd_prefix;
uint8_t pd_prefix_len;
uint32_t lifetime_preferred, lifetime_valid;
_cleanup_free_ char *buf = NULL;
if (r < 0)
return r;
- dhcp6_reset_pd_prefix_network(link);
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
- while (sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len,
+ while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
&lifetime_preferred,
&lifetime_valid) >= 0) {
if (pd_prefix_len > 64) {
- (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u",
strnull(buf), pd_prefix_len);
continue;
}
if (pd_prefix_len < 48) {
- (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u",
strnull(buf), pd_prefix_len);
}
- r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix,
+ if (pd_prefix_len < 64) {
+ Route *route = NULL;
+
+ (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
+
+ r = route_new(&route);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Cannot create unreachable route for DHCPv6 delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ continue;
+ }
+
+ route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
+ 0, 0, 0, &route);
+ route_update(route, NULL, 0, NULL, NULL, 0, 0,
+ RTN_UNREACHABLE);
+
+ r = route_configure(route, link, dhcp6_route_add_cb);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Cannot configure unreachable route for delegated subnet %s/%u: %m",
+ strnull(buf),
+ pd_prefix_len);
+ route_free(route);
+ continue;
+ }
+ link = link_ref(link);
+
+ route_free(route);
+
+ log_link_debug(link, "Configuring unreachable route for %s/%u",
+ strnull(buf), pd_prefix_len);
+
+ } else
+ log_link_debug(link, "Not adding a blocking route since distributed prefix is /64");
+
+ r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix.in6,
pd_prefix_len,
lifetime_preferred,
lifetime_valid);
if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
log_link_warning(link, "DHCPv6 lease lost");
+ (void) dhcp6_lease_pd_prefix_lost(client, link);
(void) manager_dhcp6_prefix_remove_all(link->manager, link);
link->dhcp6_configured = false;
}
int dhcp6_request_address(Link *link, int ir) {
- int r, inf_req;
+ int r, inf_req, pd;
bool running;
assert(link);
assert(link->dhcp6_client);
+ assert(link->network);
assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
r = sd_dhcp6_client_is_running(link->dhcp6_client);
else
running = r;
+ r = sd_dhcp6_client_get_prefix_delegation(link->dhcp6_client, &pd);
+ if (r < 0)
+ return r;
+
+ if (pd && ir && link->network->dhcp6_force_pd_other_information) {
+ log_link_debug(link, "Enabling managed mode to request DHCPv6 PD with 'Other Information' set");
+
+ r = sd_dhcp6_client_set_address_request(link->dhcp6_client,
+ false);
+ if (r < 0 )
+ return r;
+
+ ir = false;
+ }
+
if (running) {
r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
if (r < 0)
int dhcp4_set_promote_secondaries(Link *link);
int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link, int ir);
+int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
}
static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
- void *userdata) {
+ void *userdata) {
Link *l = userdata;
int r;
- union in_addr_union prefix;
- _cleanup_free_ char *buf = NULL;
r = sd_netlink_message_get_errno(m);
- if (r != 0) {
+ if (r < 0 && r != -EEXIST)
log_link_debug_errno(l, r, "Received error adding DHCPv6 Prefix Delegation route: %m");
- return 0;
- }
-
- r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
- if (r < 0) {
- log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while adding route: %m");
- return 0;
- }
- (void) in_addr_to_string(AF_INET6, &prefix, &buf);
- log_link_debug(l, "Added DHCPv6 Prefix Deleagtion route %s/64",
- strnull(buf));
+ l = link_unref(l);
return 0;
}
int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
int r;
Route *route;
+ _cleanup_free_ char *buf = NULL;
assert_return(m, -EINVAL);
assert_return(m->dhcp6_prefixes, -ENODATA);
if (r < 0)
return r;
+ (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
+ log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
+
+ link = link_ref(link);
+
return hashmap_put(m->dhcp6_prefixes, addr, link);
}
void *userdata) {
Link *l = userdata;
int r;
- union in_addr_union prefix;
- _cleanup_free_ char *buf = NULL;
r = sd_netlink_message_get_errno(m);
- if (r != 0) {
+ if (r < 0)
log_link_debug_errno(l, r, "Received error on DHCPv6 Prefix Delegation route removal: %m");
- return 0;
- }
- r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
- if (r < 0) {
- log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while removing route: %m");
- return 0;
- }
-
- (void) in_addr_to_string(AF_INET6, &prefix, &buf);
- log_link_debug(l, "Removed DHCPv6 Prefix Delegation route %s/64",
- strnull(buf));
+ l = link_unref(l);
return 0;
}
Link *l;
int r;
Route *route;
+ _cleanup_free_ char *buf = NULL;
assert_return(m, -EINVAL);
assert_return(m->dhcp6_prefixes, -ENODATA);
(void) sd_radv_remove_prefix(l->radv, addr, 64);
r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64,
0, 0, 0, &route);
- if (r >= 0)
- (void) route_remove(route, l, dhcp6_route_remove_callback);
+ if (r < 0)
+ return r;
+
+ r = route_remove(route, l, dhcp6_route_remove_callback);
+ if (r < 0)
+ return r;
+
+ (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
+ log_link_debug(l, "Removing prefix route %s/64", strnull(buf));
+
+ l = link_ref(l);
return 0;
}
network_free(network);
while ((link = hashmap_first(m->dhcp6_prefixes)))
- link_unref(link);
+ manager_dhcp6_prefix_remove_all(m, link);
hashmap_free(m->dhcp6_prefixes);
- while ((link = hashmap_first(m->links)))
+ while ((link = hashmap_first(m->links))) {
+ if (link->dhcp6_client)
+ (void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client,
+ link);
+
+ hashmap_remove(m->links, INT_TO_PTR(link->ifindex));
+
link_unref(link);
+ }
hashmap_free(m->links);
set_free(m->links_requesting_uuid);
DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
+DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
IPv6AcceptRA.RouteTable, config_parse_uint32, 0, offsetof(Network, ipv6_accept_ra_route_table)
struct in6_addr *router_dns;
unsigned n_router_dns;
char **router_search_domains;
+ bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
+ RA flag is set, see RFC 7084,
+ WPD-4 */
/* Bridge Support */
int use_bpdu;
#include "network-internal.h"
#include "networkd-manager.h"
#include "string-util.h"
+#include "tests.h"
static void test_deserialize_in_addr(void) {
_cleanup_free_ struct in_addr *addresses = NULL;
_cleanup_(sd_device_unrefp) sd_device *loopback = NULL;
int ifindex, r;
+ test_setup_logging(LOG_INFO);
+
test_deserialize_in_addr();
test_deserialize_dhcp_routes();
test_address_equality();
r = test_load_config(manager);
if (r == -EPERM)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("Cannot load configuration");
+ assert_se(r == 0);
assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0);
assert_se(loopback);
#include "network-internal.h"
#include "networkd-manager.h"
#include "string-util.h"
+#include "tests.h"
static void test_rule_serialization(const char *title, const char *ruleset, const char *expected) {
char pattern[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX",
int main(int argc, char **argv) {
_cleanup_free_ char *p = NULL;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_rule_serialization("basic parsing",
"RULE=from=1.2.3.4/32 to=2.3.4.5/32 tos=5 fwmark=1/2 table=10", NULL);
if (!target)
return log_oom();
- r = symlink_idempotent(controller, target);
+ r = symlink_idempotent(controller, target, false);
if (r == -EINVAL)
return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
if (r < 0)
if (r < 0)
return r;
- r = symlink_idempotent(combined, target);
+ r = symlink_idempotent(combined, target, false);
if (r == -EINVAL)
return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
if (r < 0)
free(l);
}
-static int custom_mount_compare(const void *a, const void *b) {
- const CustomMount *x = a, *y = b;
+static int custom_mount_compare(const CustomMount *a, const CustomMount *b) {
int r;
- r = path_compare(x->destination, y->destination);
+ r = path_compare(a->destination, b->destination);
if (r != 0)
return r;
- if (x->type < y->type)
- return -1;
- if (x->type > y->type)
- return 1;
-
- return 0;
+ return CMP(a->type, b->type);
}
static bool source_path_is_valid(const char *p) {
assert(l || n == 0);
/* Order the custom mounts, and make sure we have a working directory */
- qsort_safe(l, n, sizeof(CustomMount), custom_mount_compare);
+ typesafe_qsort(l, n, custom_mount_compare);
for (i = 0; i < n; i++) {
CustomMount *m = l + i;
}
}
- log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
+ if (!arg_quiet)
+ log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
}
if (dissected_image) {
#include "log.h"
#include "nspawn-patch-uid.h"
#include "user-util.h"
+#include "tests.h"
#include "util.h"
int main(int argc, char *argv[]) {
uid_t shift, range;
int r;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
if (argc != 4) {
log_error("Expected PATH SHIFT RANGE parameters.");
#if HAVE_GCRYPT
-static int rr_compare(const void *a, const void *b) {
- DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
+static int rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b) {
+ const DnsResourceRecord *x = *a, *y = *b;
size_t m;
int r;
/* Let's order the RRs according to RFC 4034, Section 6.3 */
assert(x);
- assert(*x);
- assert((*x)->wire_format);
+ assert(x->wire_format);
assert(y);
- assert(*y);
- assert((*y)->wire_format);
+ assert(y->wire_format);
- m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y));
+ m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
- r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m);
+ r = memcmp(DNS_RESOURCE_RECORD_RDATA(x), DNS_RESOURCE_RECORD_RDATA(y), m);
if (r != 0)
return r;
- if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
- return -1;
- else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
- return 1;
-
- return 0;
+ return CMP(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
}
static int dnssec_rsa_verify_raw(
return -ENODATA;
/* Bring the RRs into canonical order */
- qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
+ typesafe_qsort(list, n, rr_compare);
f = open_memstream(&sig_data, &sig_size);
if (!f)
};
};
-static inline const void* DNS_RESOURCE_RECORD_RDATA(DnsResourceRecord *rr) {
+static inline const void* DNS_RESOURCE_RECORD_RDATA(const DnsResourceRecord *rr) {
if (!rr)
return NULL;
return (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset;
}
-static inline size_t DNS_RESOURCE_RECORD_RDATA_SIZE(DnsResourceRecord *rr) {
+static inline size_t DNS_RESOURCE_RECORD_RDATA_SIZE(const DnsResourceRecord *rr) {
if (!rr)
return 0;
if (!rr->wire_format)
return rr->wire_format_size - rr->wire_format_rdata_offset;
}
-static inline uint8_t DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(DnsResourceRecord *rr) {
+static inline uint8_t DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(const DnsResourceRecord *rr) {
assert(rr);
assert(rr->key->type == DNS_TYPE_OPT);
return 0;
}
-static int domain_name_cmp(const void *a, const void *b) {
- char **x = (char**) a, **y = (char**) b;
-
- return dns_name_compare_func(*x, *y);
+static int domain_name_cmp(char * const *a, char * const *b) {
+ return dns_name_compare_func(*a, *b);
}
static int dns_trust_anchor_dump(DnsTrustAnchor *d) {
if (!l)
return log_oom();
- qsort_safe(l, set_size(d->negative_by_name), sizeof(char*), domain_name_cmp);
+ typesafe_qsort(l, set_size(d->negative_by_name), domain_name_cmp);
j = strv_join(l, " ");
if (!j)
return 0;
}
-static int mdns_rr_compare(const void *a, const void *b) {
- DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
+static int mdns_rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b) {
+ DnsResourceRecord *x = *(DnsResourceRecord **) a, *y = *(DnsResourceRecord **) b;
size_t m;
int r;
assert(x);
- assert(*x);
assert(y);
- assert(*y);
- if (CLEAR_CACHE_FLUSH((*x)->key->class) < CLEAR_CACHE_FLUSH((*y)->key->class))
- return -1;
- else if (CLEAR_CACHE_FLUSH((*x)->key->class) > CLEAR_CACHE_FLUSH((*y)->key->class))
- return 1;
+ r = CMP(CLEAR_CACHE_FLUSH(x->key->class), CLEAR_CACHE_FLUSH(y->key->class));
+ if (r != 0)
+ return r;
- if ((*x)->key->type < (*y)->key->type)
- return -1;
- else if ((*x)->key->type > (*y)->key->type)
- return 1;
+ r = CMP(x->key->type, y->key->type);
+ if (r != 0)
+ return r;
- r = dns_resource_record_to_wire_format(*x, false);
+ r = dns_resource_record_to_wire_format(x, false);
if (r < 0) {
log_warning_errno(r, "Can't wire-format RR: %m");
return 0;
}
- r = dns_resource_record_to_wire_format(*y, false);
+ r = dns_resource_record_to_wire_format(y, false);
if (r < 0) {
log_warning_errno(r, "Can't wire-format RR: %m");
return 0;
}
- m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y));
+ m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
- r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m);
+ r = memcmp(DNS_RESOURCE_RECORD_RDATA(x), DNS_RESOURCE_RECORD_RDATA(y), m);
if (r != 0)
return r;
- if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
- return -1;
- else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
- return 1;
-
- return 0;
+ return CMP(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
}
static int proposed_rrs_cmp(DnsResourceRecord **x, unsigned x_size, DnsResourceRecord **y, unsigned y_size) {
list[n++] = p->answer->items[i].rr;
}
assert(n == size);
- qsort_safe(list, size, sizeof(DnsResourceRecord*), mdns_rr_compare);
+ typesafe_qsort(list, size, mdns_rr_compare);
*ret_rrs = TAKE_PTR(list);
DNS_ANSWER_FOREACH(rr, answer)
our[i++] = rr;
- qsort_safe(our, size, sizeof(DnsResourceRecord*), mdns_rr_compare);
+
+ typesafe_qsort(our, size, mdns_rr_compare);
r = mdns_packet_extract_matching_rrs(p, key, &remote);
if (r < 0)
if (r < 0)
continue;
- if (sd_device_get_sysname(t, &name) >= 0 && streq_ptr(name, sysname)) {
+ if (sd_device_get_sysname(t, &name) >= 0 && streq(name, sysname)) {
*ret = TAKE_PTR(t);
return 0;
}
return 0;
}
-static int boot_entry_compare(const void *a, const void *b) {
- const BootEntry *aa = a, *bb = b;
-
- return str_verscmp(aa->filename, bb->filename);
+static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
+ return str_verscmp(a->filename, b->filename);
}
int boot_entries_find(const char *dir, BootEntry **ret_entries, size_t *ret_n_entries) {
n++;
}
- qsort_safe(array, n, sizeof(BootEntry), boot_entry_compare);
+ typesafe_qsort(array, n, boot_entry_compare);
*ret_entries = array;
*ret_n_entries = n;
free(cg);
}
-static int cgroup_info_compare_func(const void *a, const void *b) {
- const struct CGroupInfo *x = *(const struct CGroupInfo* const*) a, *y = *(const struct CGroupInfo* const*) b;
-
- assert(x);
- assert(y);
-
- return strcmp(x->cgroup_path, y->cgroup_path);
+static int cgroup_info_compare_func(struct CGroupInfo * const *a, struct CGroupInfo * const *b) {
+ return strcmp((*a)->cgroup_path, (*b)->cgroup_path);
}
static int dump_processes(
pids[n++] = PTR_TO_PID(pidp);
assert(n == hashmap_size(cg->pids));
- qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
+ typesafe_qsort(pids, n, pid_compare_func);
width = DECIMAL_STR_WIDTH(pids[n-1]);
LIST_FOREACH(siblings, child, cg->children)
children[n++] = child;
assert(n == cg->n_children);
- qsort_safe(children, n, sizeof(struct CGroupInfo*), cgroup_info_compare_func);
+ typesafe_qsort(children, n, cgroup_info_compare_func);
if (n_columns != 0)
n_columns = MAX(LESS_BY(n_columns, 2U), 20U);
if (n == 0)
return 0;
- qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
+ typesafe_qsort(pids, n, pid_compare_func);
width = DECIMAL_STR_WIDTH(pids[n-1]);
for (k = 0; k < n; k++) {
typedef int (*bus_message_print_t) (const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all);
-int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *fmt, ...);
+int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) _printf_(4,5);
int bus_message_print_all_properties(sd_bus_message *m, bus_message_print_t func, char **filter, bool value, bool all, Set **found_properties);
int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, bus_message_print_t func, char **filter, bool value, bool all, Set **found_properties);
if (n_pids == 0)
return;
- qsort(pids, n_pids, sizeof(pid_t), pid_compare_func);
+ typesafe_qsort(pids, n_pids, pid_compare_func);
/* Filter duplicates */
for (j = 0, i = 1; i < n_pids; i++) {
#include "copy.h"
#include "crypt-util.h"
#include "def.h"
-#include "device-enumerator-private.h"
#include "device-nodes.h"
+#include "device-util.h"
#include "dissect-image.h"
#include "fd-util.h"
#include "fileio.h"
if (r < 0)
return r;
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
/* Count the partitions enumerated by the kernel */
n = 0;
- FOREACH_DEVICE_AND_SUBSYSTEM(e, q) {
+ FOREACH_DEVICE(e, q) {
dev_t qn;
if (sd_device_get_devnum(q, &qn) < 0)
e = sd_device_enumerator_unref(e);
}
- r = device_enumerator_scan_devices(e);
- if (r < 0)
- return r;
-
- FOREACH_DEVICE_AND_SUBSYSTEM(e, q) {
+ FOREACH_DEVICE(e, q) {
unsigned long long pflags;
blkid_partition pp;
const char *node;
return id;
}
-static int cmp_uint16(const void *_a, const void *_b) {
- const uint16_t *a = _a, *b = _b;
-
- return (int)*a - (int)*b;
+static int cmp_uint16(const uint16_t *a, const uint16_t *b) {
+ return CMP(*a, *b);
}
int efi_get_boot_options(uint16_t **options) {
list[count++] = id;
}
- qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
+ typesafe_qsort(list, count, cmp_uint16);
*options = TAKE_PTR(list);
new_size = old_size + max_add;
r = btrfs_resize_loopback("/var/lib/machines", new_size, true);
- if (r <= 0)
- return r;
+ if (r < 0)
+ return log_debug_errno(r, "Failed to resize loopback: %m");
+ if (r == 0)
+ return 0;
/* Also bump the quota, of both the subvolume leaf qgroup, as
* well as of any subtree quota group by the same id but a
* higher level, if it exists. */
- (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
- (void) btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
+ r = btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
+ if (r < 0)
+ log_debug_errno(r, "Failed to set btrfs limit: %m");
+
+ r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
+ if (r < 0)
+ log_debug_errno(r, "Failed to set btrfs subtree limit: %m");
log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
return 1;
#include <util.h>
#include "alloc-util.h"
+#include "env-util.h"
#include "fileio.h"
+#include "log.h"
#include "path-util.h"
#include "strv.h"
#include "tests.h"
}
return env;
}
+
+bool slow_tests_enabled(void) {
+ int r;
+
+ r = getenv_bool("SYSTEMD_SLOW_TESTS");
+ if (r >= 0)
+ return r;
+
+ if (r != -ENXIO)
+ log_warning_errno(r, "Cannot parse $SYSTEMD_SLOW_TESTS, ignoring.");
+ return SYSTEMD_SLOW_TESTS_DEFAULT;
+}
+
+void test_setup_logging(int level) {
+ log_set_max_level(level);
+ log_parse_environment();
+ log_open();
+}
+
+int log_tests_skipped(const char *message) {
+ log_notice("%s: %s, skipping tests.",
+ program_invocation_short_name, message);
+ return EXIT_TEST_SKIP;
+}
+
+int log_tests_skipped_errno(int r, const char *message) {
+ log_notice_errno(r, "%s: %s, skipping tests: %m",
+ program_invocation_short_name, message);
+ return EXIT_TEST_SKIP;
+}
char* setup_fake_runtime_dir(void);
const char* get_testdata_dir(void);
const char* get_catalog_dir(void);
+bool slow_tests_enabled(void);
+void test_setup_logging(int level);
+int log_tests_skipped(const char *message);
+int log_tests_skipped_errno(int r, const char *message);
#include "macro.h"
#include "uid-range.h"
#include "user-util.h"
+#include "util.h"
static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
assert(range);
}
}
-static int uid_range_compare(const void *a, const void *b) {
- const UidRange *x = a, *y = b;
-
- if (x->start < y->start)
- return -1;
- if (x->start > y->start)
- return 1;
+static int uid_range_compare(const UidRange *a, const UidRange *b) {
+ int r;
- if (x->nr < y->nr)
- return -1;
- if (x->nr > y->nr)
- return 1;
+ r = CMP(a->start, b->start);
+ if (r != 0)
+ return r;
- return 0;
+ return CMP(a->nr, b->nr);
}
int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
x->nr = nr;
}
- qsort(*p, *n, sizeof(UidRange), uid_range_compare);
+ typesafe_qsort(*p, *n, uid_range_compare);
uid_range_coalesce(p, n);
return *n;
return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");;
}
- execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
+ execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
log_struct(LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
"SLEEP=%s", arg_verb);
arguments[1] = (char*) "post";
- execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
+ execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
return r;
}
return false;
}
-static int compare_unit_info(const void *a, const void *b) {
- const UnitInfo *u = a, *v = b;
+static int compare_unit_info(const UnitInfo *a, const UnitInfo *b) {
const char *d1, *d2;
int r;
/* First, order by machine */
- if (!u->machine && v->machine)
+ if (!a->machine && b->machine)
return -1;
- if (u->machine && !v->machine)
+ if (a->machine && !b->machine)
return 1;
- if (u->machine && v->machine) {
- r = strcasecmp(u->machine, v->machine);
+ if (a->machine && b->machine) {
+ r = strcasecmp(a->machine, b->machine);
if (r != 0)
return r;
}
/* Second, order by unit type */
- d1 = strrchr(u->id, '.');
- d2 = strrchr(v->id, '.');
+ d1 = strrchr(a->id, '.');
+ d2 = strrchr(b->id, '.');
if (d1 && d2) {
r = strcasecmp(d1, d2);
if (r != 0)
}
/* Third, order by name */
- return strcasecmp(u->id, v->id);
+ return strcasecmp(a->id, b->id);
}
static const char* unit_type_suffix(const char *name) {
if (r < 0)
return r;
- qsort_safe(unit_infos, r, sizeof(UnitInfo), compare_unit_info);
+ typesafe_qsort(unit_infos, r, compare_unit_info);
return output_units_list(unit_infos, r);
}
};
static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
- int o;
+ int r;
assert(a);
assert(b);
if (a->machine && !b->machine)
return 1;
if (a->machine && b->machine) {
- o = strcasecmp(a->machine, b->machine);
- if (o != 0)
- return o;
+ r = strcasecmp(a->machine, b->machine);
+ if (r != 0)
+ return r;
}
- o = strcmp(a->path, b->path);
- if (o == 0)
- o = strcmp(a->type, b->type);
+ r = strcmp(a->path, b->path);
+ if (r == 0)
+ r = strcmp(a->type, b->type);
- return o;
+ return r;
}
static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
listening = triggered = NULL; /* avoid cleanup */
}
- qsort_safe(socket_infos, cs, sizeof(struct socket_info),
- (__compar_fn_t) socket_info_compare);
+ typesafe_qsort(socket_infos, cs, socket_info_compare);
output_sockets_list(socket_infos, cs);
};
static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
- int o;
+ int r;
assert(a);
assert(b);
if (a->machine && !b->machine)
return 1;
if (a->machine && b->machine) {
- o = strcasecmp(a->machine, b->machine);
- if (o != 0)
- return o;
+ r = strcasecmp(a->machine, b->machine);
+ if (r != 0)
+ return r;
}
- if (a->next_elapse < b->next_elapse)
- return -1;
- if (a->next_elapse > b->next_elapse)
- return 1;
+ r = CMP(a->next_elapse, b->next_elapse);
+ if (r != 0)
+ return r;
return strcmp(a->id, b->id);
}
};
}
- qsort_safe(timer_infos, c, sizeof(struct timer_info),
- (__compar_fn_t) timer_info_compare);
+ typesafe_qsort(timer_infos, c, timer_info_compare);
output_timers_list(timer_infos, c);
return r;
}
-static int compare_unit_file_list(const void *a, const void *b) {
+static int compare_unit_file_list(const UnitFileList *a, const UnitFileList *b) {
const char *d1, *d2;
- const UnitFileList *u = a, *v = b;
- d1 = strrchr(u->path, '.');
- d2 = strrchr(v->path, '.');
+ d1 = strrchr(a->path, '.');
+ d2 = strrchr(b->path, '.');
if (d1 && d2) {
int r;
return r;
}
- return strcasecmp(basename(u->path), basename(v->path));
+ return strcasecmp(basename(a->path), basename(b->path));
}
static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
(void) pager_open(arg_no_pager, false);
- qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
+ typesafe_qsort(units, c, compare_unit_file_list);
output_unit_file_list(units, c);
if (install_client_side())
return 0;
}
-static int list_dependencies_compare(const void *_a, const void *_b) {
- const char **a = (const char**) _a, **b = (const char**) _b;
-
+static int list_dependencies_compare(char * const *a, char * const *b) {
if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
return 1;
if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
if (r < 0)
return r;
- qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
+ typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
STRV_FOREACH(c, deps) {
if (strv_contains(*units, *c)) {
free(machine_infos);
}
-static int compare_machine_info(const void *a, const void *b) {
- const struct machine_info *u = a, *v = b;
+static int compare_machine_info(const struct machine_info *a, const struct machine_info *b) {
+ int r;
- if (u->is_host != v->is_host)
- return u->is_host > v->is_host ? -1 : 1;
+ r = CMP(b->is_host, a->is_host);
+ if (r != 0)
+ return r;
- return strcasecmp(u->name, v->name);
+ return strcasecmp(a->name, b->name);
}
static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
(void) pager_open(arg_no_pager, false);
- qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info);
+ typesafe_qsort(machine_infos, r, compare_machine_info);
output_machines_list(machine_infos, r);
free_machines_list(machine_infos, r);
c = (unsigned) r;
- qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
+ typesafe_qsort(unit_infos, c, compare_unit_info);
for (u = unit_infos; u < unit_infos + c; u++) {
_cleanup_free_ char *p = NULL;
foreach header : _systemd_headers
foreach opt : opts
name = ''.join([header, ':'] + opt)
- test('cc-' + name,
- check_compilation_sh,
- args : cc.cmd_array() + ['-c', '-x'] + opt +
- ['-Werror', '-include',
- join_paths(meson.current_source_dir(), header)])
+ if want_tests != 'false'
+ test('cc-' + name,
+ check_compilation_sh,
+ args : cc.cmd_array() + ['-c', '-x'] + opt +
+ ['-Werror', '-include',
+ join_paths(meson.current_source_dir(), header)])
+ endif
endforeach
endforeach
int sd_device_get_property_value(sd_device *device, const char *key, const char **value);
int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value);
-int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *value);
+int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value);
/* device enumerator */
#include <inttypes.h>
#include <net/ethernet.h>
-#include <stdbool.h>
#include <sys/types.h>
#include "sd-dhcp6-lease.h"
int sd_dhcp6_client_set_request_option(
sd_dhcp6_client *client,
uint16_t option);
+int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client,
+ int *delegation);
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,
- bool delegation);
+ int delegation);
+int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client,
+ int *request);
+int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
+ int request);
int sd_dhcp6_client_get_lease(
sd_dhcp6_client *client,
input : [awkscript, 'test-hashmap-plain.c'],
output : 'test-hashmap-ordered.c',
command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
- capture : true)
+ capture : true,
+ build_by_default : want_tests != 'false')
test_include_dir = include_directories('.')
input : [libsystemd_sym_path] + systemd_headers,
output : 'test-libsystemd-sym.c',
command : [generate_sym_test_py, libsystemd_sym_path] + systemd_headers,
- capture : true)
+ capture : true,
+ build_by_default : want_tests != 'false')
test_libudev_sym_c = custom_target(
'test-libudev-sym.c',
input : [libudev_sym_path, libudev_h_path],
output : 'test-libudev-sym.c',
command : [generate_sym_test_py, '@INPUT0@', '@INPUT1@'],
- capture : true)
+ capture : true,
+ build_by_default : want_tests != 'false')
test_dlopen_c = files('test-dlopen.c')
libblkid,
libkmod,
libacl],
- '', 'manual'],
+ '', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'],
[['src/test/test-id128.c'],
[],
#include "architecture.h"
#include "log.h"
+#include "tests.h"
#include "util.h"
#include "virt.h"
int a, v;
const char *p;
+ test_setup_logging(LOG_INFO);
+
assert_se(architecture_from_string("") < 0);
assert_se(architecture_from_string(NULL) < 0);
assert_se(architecture_from_string("hoge") < 0);
v = detect_virtualization();
if (IN_SET(v, -EPERM, -EACCES))
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("Cannot detect virtualization");
assert_se(v >= 0);
#include "barrier.h"
#include "util.h"
+#include "tests.h"
/* 20ms to test deadlocks; All timings use multiples of this constant as
* alarm/sleep timers. If this timeout is too small for slow machines to perform
TEST_BARRIER_WAIT_SUCCESS(pid2));
int main(int argc, char *argv[]) {
- /*
- * This test uses real-time alarms and sleeps to test for CPU races
- * explicitly. This is highly fragile if your system is under load. We
- * already increased the BASE_TIME value to make the tests more robust,
- * but that just makes the test take significantly longer. Hence,
- * disable the test by default, so it will not break CI.
- */
- if (argc < 2)
- return EXIT_TEST_SKIP;
+ test_setup_logging(LOG_INFO);
- log_parse_environment();
- log_open();
+ if (!slow_tests_enabled())
+ return log_tests_skipped("slow tests are disabled");
test_barrier_sync();
test_barrier_wait_next();
#include "boot-timestamps.h"
#include "efivars.h"
#include "log.h"
+#include "tests.h"
#include "util.h"
static int test_acpi_fpdt(void) {
int main(int argc, char* argv[]) {
int p, q, r;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
p = test_acpi_fpdt();
assert(p >= 0);
r = test_boot_timestamps();
assert(r >= 0);
- return (p > 0 || q > 0 || r >> 0) ? EXIT_SUCCESS : EXIT_TEST_SKIP;
+ if (p == 0 && q == 0 && r == 0)
+ return log_tests_skipped("access to firmware variables not possible");
+
+ return EXIT_SUCCESS;
}
char log_buf[65535];
int r;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- log_notice("cgroupfs not available, skipping tests");
- return EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
assert_se(set_unit_path(get_testdata_dir()) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = bpf_program_add_instructions(p, exit_insn, ELEMENTSOF(exit_insn));
assert(r == 0);
- if (getuid() != 0) {
- log_notice("Not running as root, skipping kernel related tests.");
- return EXIT_TEST_SKIP;
- }
+ if (getuid() != 0)
+ return log_tests_skipped("not running as root");
r = bpf_firewall_supported();
- if (r == BPF_FIREWALL_UNSUPPORTED) {
- log_notice("BPF firewalling not supported, skipping");
- return EXIT_TEST_SKIP;
- }
+ if (r == BPF_FIREWALL_UNSUPPORTED)
+ return log_tests_skipped("BPF firewalling not supported");
assert_se(r > 0);
if (r == BPF_FIREWALL_SUPPORTED_WITH_MULTI)
unit_dump(u, stdout, NULL);
r = bpf_firewall_compile(u);
- if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM ))
- /* Kernel doesn't support the necessary bpf bits, or masked out via seccomp? */
- return EXIT_TEST_SKIP;
+ if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM))
+ return log_tests_skipped("Kernel doesn't support the necessary bpf bits (masked out via seccomp?)");
assert_se(r >= 0);
assert(u->ip_bpf_ingress);
#include "bus-util.h"
#include "log.h"
+#include "tests.h"
static void test_name_async(unsigned n_messages) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
}
int main(int argc, char **argv) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_name_async(0);
test_name_async(20);
#include "fileio.h"
#include "macro.h"
#include "parse-util.h"
+#include "tests.h"
#include "util.h"
static uid_t test_uid = -1;
int r;
nobody = getpwnam(NOBODY_USER_NAME);
- if (!nobody) {
- log_error_errno(errno, "Could not find nobody user: %m");
- return -EXIT_TEST_SKIP;
- }
+ if (!nobody)
+ return log_error_errno(errno, "Could not find nobody user: %m");
+
test_uid = nobody->pw_uid;
test_gid = nobody->pw_gid;
}
int main(int argc, char *argv[]) {
- int r;
bool run_ambient;
+ test_setup_logging(LOG_INFO);
+
test_last_cap_file();
test_last_cap_probe();
- log_parse_environment();
- log_open();
-
log_info("have ambient caps: %s", yes_no(ambient_capabilities_supported()));
if (getuid() != 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("not running as root");
- r = setup_tests(&run_ambient);
- if (r < 0)
- return -r;
+ if (setup_tests(&run_ambient) < 0)
+ return log_tests_skipped("setup failed");
show_capabilities();
int r;
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- puts("Skipping test: cgroupfs not available");
- return EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
/* Prepare the manager. */
assert_se(set_unit_path(get_testdata_dir()) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (IN_SET(r, -EPERM, -EACCES)) {
- puts("manager_new: Permission denied. Skipping test.");
- return EXIT_TEST_SKIP;
+ log_error_errno(r, "manager_new: %m");
+ return log_tests_skipped("cannot create manager");
}
+
assert_se(r >= 0);
/* Turn off all kinds of default accouning, so that we can
}
int main(int argc, char* argv[]) {
- int rc = 0;
+ int rc = EXIT_SUCCESS;
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
- TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
test_cg_mask_to_string();
+ TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
return rc;
}
#include "string-util.h"
#include "strv.h"
#include "test-helper.h"
+#include "tests.h"
#include "user-util.h"
#include "util.h"
test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo");
test_shift_path_one("/foobar/waldo", "", "/foobar/waldo");
test_shift_path_one("/foobar/waldo", "/foobar", "/waldo");
- test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
+ test_shift_path_one("/foobar/waldo", "/hogehoge", "/foobar/waldo");
}
static void test_mask_supported(void) {
}
int main(void) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_path_decode_unit();
test_path_get_unit();
#include "strv.h"
#include "tomoyo-util.h"
#include "user-util.h"
+#include "tests.h"
#include "util.h"
#include "virt.h"
condition_free(condition);
}
-static int test_condition_test_control_group_controller(void) {
+static void test_condition_test_control_group_controller(void) {
Condition *condition;
CGroupMask system_mask;
CGroupController controller;
r = cg_unified_flush();
if (r < 0) {
log_notice_errno(r, "Skipping ConditionControlGroupController tests: %m");
- return EXIT_TEST_SKIP;
+ return;
}
/* Invalid controllers are ignored */
assert_se(condition);
assert_se(!condition_test(condition));
condition_free(condition);
-
- return EXIT_SUCCESS;
}
static void test_condition_test_ac_power(void) {
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_condition_test_path();
test_condition_test_ac_power();
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "user-util.h"
#include "util.h"
}
int main(int argc, char **argv) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_conf_files_list(false);
test_conf_files_list(true);
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "user-util.h"
#include "util.h"
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
test_copy_file();
test_copy_file_fd();
#include "alloc-util.h"
#include "string-util.h"
+#include "tests.h"
#include "util.h"
static void test_should_pass(const char *p) {
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_one("17:41");
test_one("18:42:44");
#include "log.h"
#include "loop-util.h"
#include "string-util.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
int r, i;
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
if (argc < 2) {
log_error("Requires one command line argument.");
#include "dns-domain.h"
#include "macro.h"
#include "string-util.h"
+#include "tests.h"
static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
char buffer[buffer_sz];
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_dns_label_unescape();
test_dns_label_unescape_suffix();
Job *j;
int r;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- log_notice_errno(r, "Skipping test: cgroupfs not available");
- return EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
/* prepare the test */
assert_se(set_unit_path(get_testdata_dir()) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
- if (MANAGER_SKIP_TEST(r)) {
- log_notice_errno(r, "Skipping test: manager_new: %m");
- return EXIT_TEST_SKIP;
- }
+ if (MANAGER_SKIP_TEST(r))
+ return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);
assert_se(manager_startup(m, NULL, NULL) >= 0);
#include "alloc-util.h"
#include "escape.h"
#include "macro.h"
+#include "tests.h"
static void test_cescape(void) {
_cleanup_free_ char *escaped;
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_cescape();
test_cunescape();
#include "fs-util.h"
#include "log.h"
#include "macro.h"
+#include "path-util.h"
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
static int here = 0, here2 = 0, here3 = 0;
void *ignore_stdout_args[] = {&here, &here2, &here3};
assert_se(chmod(mask2e, 0755) == 0);
if (gather_stdout)
- execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL);
+ execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL);
else
- execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL);
+ execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL);
assert_se(chdir(template_lo) == 0);
assert_se(access("it_works", F_OK) >= 0);
assert_se(chmod(override, 0755) == 0);
assert_se(chmod(masked, 0755) == 0);
- execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL);
+ execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL);
assert_se(read_full_file(output, &contents, NULL) >= 0);
assert_se(streq(contents, "30-override\n80-foo\n90-bar\nlast\n"));
assert_se(chmod(name2, 0755) == 0);
assert_se(chmod(name3, 0755) == 0);
- r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL);
+ r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL, NULL);
assert_se(r >= 0);
log_info("got: %s", output);
static void test_environment_gathering(void) {
char template[] = "/tmp/test-exec-util.XXXXXXX", **p;
const char *dirs[] = {template, NULL};
- const char *name, *name2, *name3;
+ const char *name, *name2, *name3, *old;
int r;
char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
assert_se(chmod(name2, 0755) == 0);
assert_se(chmod(name3, 0755) == 0);
- r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL);
+ /* When booting in containers or without initramfs there might not be
+ * any PATH in the environ and if there is no PATH /bin/sh built-in
+ * PATH may leak and override systemd's DEFAULT_PATH which is not
+ * good. Force our own PATH in environment, to prevent expansion of sh
+ * built-in $PATH */
+ old = getenv("PATH");
+ r = setenv("PATH", "no-sh-built-in-path", 1);
+ assert_se(r >= 0);
+
+ r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, NULL);
+ assert_se(r >= 0);
+
+ STRV_FOREACH(p, env)
+ log_info("got env: \"%s\"", *p);
+
+ assert_se(streq(strv_env_get(env, "A"), "22:23:24"));
+ assert_se(streq(strv_env_get(env, "B"), "12"));
+ assert_se(streq(strv_env_get(env, "C"), "001"));
+ assert_se(streq(strv_env_get(env, "PATH"), "no-sh-built-in-path:/no/such/file"));
+
+ /* now retest with "default" path passed in, as created by
+ * manager_default_environment */
+ env = strv_free(env);
+ env = strv_new("PATH=" DEFAULT_PATH, NULL);
+
+ r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, env);
assert_se(r >= 0);
STRV_FOREACH(p, env)
assert_se(streq(strv_env_get(env, "A"), "22:23:24"));
assert_se(streq(strv_env_get(env, "B"), "12"));
assert_se(streq(strv_env_get(env, "C"), "001"));
- assert_se(endswith(strv_env_get(env, "PATH"), ":/no/such/file"));
+ assert_se(streq(strv_env_get(env, "PATH"), DEFAULT_PATH ":/no/such/file"));
+
+ /* reset environ PATH */
+ (void) setenv("PATH", old, 1);
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_execute_directory(true);
test_execute_directory(false);
assert_se(tests);
r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
- if (MANAGER_SKIP_TEST(r)) {
- log_notice_errno(r, "Skipping test: manager_new: %m");
- return EXIT_TEST_SKIP;
- }
+ if (MANAGER_SKIP_TEST(r))
+ return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);
assert_se(manager_startup(m, NULL, NULL) >= 0);
};
int r;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
(void) unsetenv("USER");
(void) unsetenv("LOGNAME");
(void) unsetenv("SHELL");
/* It is needed otherwise cgroup creation fails */
- if (getuid() != 0) {
- puts("Skipping test: not root");
- return EXIT_TEST_SKIP;
- }
+ if (getuid() != 0)
+ return log_tests_skipped("not root");
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- puts("Skipping test: cgroupfs not available");
- return EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
assert_se(runtime_dir = setup_fake_runtime_dir());
test_execute_path = path_join(NULL, get_testdata_dir(), "test-execute");
#include "random-util.h"
#include "string-util.h"
#include "util.h"
+#include "tests.h"
static void test_close_many(void) {
int fds[3];
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
test_close_many();
test_close_nointr();
#include "process-util.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "util.h"
static void test_parse_env_file(void) {
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_parse_env_file();
test_parse_multiline_env_file();
#include "firewall-util.h"
#include "log.h"
+#include "tests.h"
#define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))}
int main(int argc, char *argv[]) {
int r;
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0);
if (r < 0)
#include "log.h"
#include "string-util.h"
#include "khash.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
_cleanup_(khash_unrefp) khash *h = NULL, *copy = NULL;
_cleanup_free_ char *s = NULL;
int r;
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(khash_new(&h, NULL) == -EINVAL);
assert_se(khash_new(&h, "") == -EINVAL);
r = khash_supported();
assert_se(r >= 0);
- if (r == 0) {
- puts("khash not supported on this kernel, skipping");
- return EXIT_TEST_SKIP;
- }
+ if (r == 0)
+ return log_tests_skipped("khash not supported on this kernel");
assert_se(khash_new(&h, "foobar") == -EOPNOTSUPP); /* undefined hash function */
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "alloc-util.h"
-#include "env-util.h"
#include "hashmap.h"
#include "log.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "util.h"
-static bool arg_slow = false;
-
void test_hashmap_funcs(void);
static void test_hashmap_replace(void) {
Hashmap *h;
unsigned i, j;
void *v, *k;
+ bool slow = slow_tests_enabled();
const struct {
const struct hash_ops *ops;
unsigned n_entries;
} tests[] = {
- { .ops = NULL, .n_entries = arg_slow ? 1 << 20 : 240 },
- { .ops = &crippled_hashmap_ops, .n_entries = arg_slow ? 1 << 14 : 140 },
+ { .ops = NULL, .n_entries = slow ? 1 << 20 : 240 },
+ { .ops = &crippled_hashmap_ops, .n_entries = slow ? 1 << 14 : 140 },
};
- log_info("%s (%s)", __func__, arg_slow ? "slow" : "fast");
+ log_info("%s (%s)", __func__, slow ? "slow" : "fast");
for (j = 0; j < ELEMENTSOF(tests); j++) {
assert_se(h = hashmap_new(tests[j].ops));
}
void test_hashmap_funcs(void) {
- int r;
-
log_parse_environment();
log_open();
- r = getenv_bool("SYSTEMD_SLOW_TESTS");
- arg_slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
-
test_hashmap_copy();
test_hashmap_get_strv();
test_hashmap_move_one();
#include "rm-rf.h"
#include "special.h"
#include "string-util.h"
+#include "tests.h"
static void test_basic_mask_and_enable(const char *root) {
const char *p;
UnitFileChange *changes = NULL;
size_t n_changes = 0;
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT);
#include <string.h>
#include "install.h"
+#include "tests.h"
static void dump_changes(UnitFileChange *c, unsigned n) {
unsigned i;
size_t n_changes = 0;
UnitFileState state = 0;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
h = hashmap_new(&string_hash_ops);
r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
#include "clean-ipc.h"
#include "user-util.h"
+#include "tests.h"
#include "util.h"
int main(int argc, char *argv[]) {
int r;
const char* name = argv[1] ?: NOBODY_USER_NAME;
+ test_setup_logging(LOG_INFO);
+
r = get_user_creds(&name, &uid, NULL, NULL, NULL, 0);
+ if (r == -ESRCH)
+ return log_tests_skipped("Failed to resolve user");
if (r < 0) {
- log_full_errno(r == -ESRCH ? LOG_NOTICE : LOG_ERR,
- r, "Failed to resolve \"%s\": %m", name);
- return r == -ESRCH ? EXIT_TEST_SKIP : EXIT_FAILURE;
+ log_error_errno(r, "Failed to resolve \"%s\": %m", name);
+ return EXIT_FAILURE;
}
r = clean_ipc_by_uid(uid);
}
int main(int argc, char **argv) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
test_basic_parsing();
test_bad_input();
#include "log.h"
#include "loopback-setup.h"
+#include "tests.h"
int main(int argc, char* argv[]) {
int r;
- log_open();
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
r = loopback_setup();
if (r < 0)
#include "path-util.h"
#include "rm-rf.h"
#include "string-util.h"
+#include "tests.h"
static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) {
long unsigned flags;
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
test_mount_propagation_flags("shared", 0, MS_SHARED);
test_mount_propagation_flags("slave", 0, MS_SLAVE);
#include "namespace.h"
#include "process-util.h"
#include "string-util.h"
+#include "tests.h"
#include "util.h"
static void test_tmpdir(const char *id, const char *A, const char *B) {
assert_se(rmdir(b) >= 0);
}
-static void test_netns(void) {
+static int test_netns(void) {
_cleanup_close_pair_ int s[2] = { -1, -1 };
pid_t pid1, pid2, pid3;
int r, n = 0;
siginfo_t si;
- if (geteuid() > 0) {
- log_info("Skipping test: not root");
- exit(EXIT_TEST_SKIP);
- }
+ if (geteuid() > 0)
+ return log_tests_skipped("not root");
assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0);
n += si.si_status;
assert_se(n == 1);
+ return EXIT_SUCCESS;
}
int main(int argc, char *argv[]) {
char boot_id[SD_ID128_STRING_MAX];
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL;
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_INFO);
assert_se(sd_id128_get_boot(&bid) >= 0);
sd_id128_to_string(bid, boot_id);
test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz);
- test_netns();
-
- return 0;
+ return test_netns();
}
#include "macro.h"
#include "module-util.h"
+#include "tests.h"
#include "util.h"
static int load_module(const char *mod_name) {
/* skip test if module cannot be loaded */
r = load_module("ipip");
if (r < 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped_errno(r, "failed to load module 'ipip'");
+
+ r = load_module("sit");
+ if (r < 0)
+ return log_tests_skipped_errno(r, "failed to load module 'sit'");
if (getuid() != 0)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("not root");
/* IPIP tunnel */
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
assert_se((m = sd_netlink_message_unref(m)) == NULL);
- r = load_module("sit");
- if (r < 0)
- return EXIT_TEST_SKIP;
-
/* sit */
assert_se(sd_rtnl_message_new_link(rtnl, &n, RTM_NEWLINK, 0) >= 0);
assert_se(n);
sd_netlink *rtnl;
int r;
+ test_setup_logging(LOG_INFO);
+
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(rtnl);
#include "log.h"
#include "namespace.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
const char * const writable[] = {
char tmp_dir[] = "/tmp/systemd-private-XXXXXX",
var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX";
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
assert_se(mkdtemp(tmp_dir));
assert_se(mkdtemp(var_tmp_dir));
#include "log.h"
#include "os-util.h"
+#include "tests.h"
static void test_path_is_os_tree(void) {
assert_se(path_is_os_tree("/") > 0);
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_path_is_os_tree();
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
static void test_paths(UnitFileScope scope) {
char template[] = "/tmp/test-path-lookup.XXXXXXX";
}
int main(int argc, char **argv) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_paths(UNIT_FILE_SYSTEM);
test_paths(UNIT_FILE_USER);
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "util.h"
#define test_path_compare(a, b, result) { \
}
int main(int argc, char **argv) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_path();
test_path_equal_root();
assert_se(m);
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- log_notice_errno(r, "Skipping test: cgroupfs not available");
- return -EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
- if (MANAGER_SKIP_TEST(r)) {
- log_notice_errno(r, "Skipping test: manager_new: %m");
- return -EXIT_TEST_SKIP;
- }
+ if (MANAGER_SKIP_TEST(r))
+ return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);
assert_se(manager_startup(tmp, NULL, NULL) >= 0);
umask(022);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_INFO);
test_path = path_join(NULL, get_testdata_dir(), "test-path");
assert_se(set_unit_path(test_path) >= 0);
/* We create a clean environment for each test */
r = setup_test(&m);
- if (r < 0)
- return -r;
+ if (r != 0)
+ return r;
(*test)(m);
#define SET_SIZE 1024*4
-static int unsigned_compare(const void *a, const void *b) {
- const unsigned *x = a, *y = b;
-
- if (*x < *y)
- return -1;
-
- if (*x > *y)
- return 1;
-
- return 0;
+static int unsigned_compare(const unsigned *a, const unsigned *b) {
+ return CMP(*a, *b);
}
static void test_unsigned(void) {
assert_se(prioq_put(q, UINT_TO_PTR(u), NULL) >= 0);
}
- qsort(buffer, ELEMENTSOF(buffer), sizeof(buffer[0]), unsigned_compare);
+ typesafe_qsort(buffer, ELEMENTSOF(buffer), unsigned_compare);
for (i = 0; i < ELEMENTSOF(buffer); i++) {
unsigned u;
#include "string-util.h"
#include "terminal-util.h"
#include "test-helper.h"
+#include "tests.h"
#include "util.h"
#include "virt.h"
_cleanup_free_ char *line = NULL;
pid_t pid;
- if (geteuid() != 0)
+ if (geteuid() != 0) {
+ log_info("Skipping %s: not root", __func__);
return;
+ }
#if HAVE_VALGRIND_VALGRIND_H
/* valgrind patches open(/proc//cmdline)
* so, test_get_process_cmdline_harder fails always
* See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */
- if (RUNNING_ON_VALGRIND)
+ if (RUNNING_ON_VALGRIND) {
+ log_info("Skipping %s: running on valgrind", __func__);
return;
+ }
#endif
pid = fork();
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
saved_argc = argc;
saved_argv = argv;
#include "hexdecoct.h"
#include "random-util.h"
#include "log.h"
+#include "tests.h"
static void test_acquire_random_bytes(bool high_quality_required) {
uint8_t buf[16] = {};
}
int main(int argc, char **argv) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_acquire_random_bytes(false);
test_acquire_random_bytes(true);
Service *ser;
int r;
+ test_setup_logging(LOG_INFO);
+
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- log_notice_errno(r, "Skipping test: cgroupfs not available");
- return EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
/* prepare the test */
assert_se(set_unit_path(get_testdata_dir()) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
- if (MANAGER_SKIP_TEST(r)) {
- log_notice_errno(r, "Skipping test: manager_new: %m");
- return EXIT_TEST_SKIP;
- }
+ if (MANAGER_SKIP_TEST(r))
+ return log_tests_skipped_errno(r, "manager_new");
assert_se(r >= 0);
assert_se(manager_startup(m, NULL, NULL) >= 0);
#include "seccomp-util.h"
#include "set.h"
#include "string-util.h"
+#include "tests.h"
#include "util.h"
#include "virt.h"
unsigned i;
int r;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
pid_t pid;
assert_se(namespace_flags_from_string(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL);
s = mfree(s);
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping remaining tests in %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping remaining tests in %s", __func__);
return;
+ }
pid = fork();
assert_se(pid >= 0);
static void test_protect_sysctl(void) {
pid_t pid;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
- if (detect_container() > 0) /* in containers _sysctl() is likely missing anyway */
+ /* in containers _sysctl() is likely missing anyway */
+ if (detect_container() > 0) {
+ log_notice("Testing in container, skipping %s", __func__);
return;
+ }
pid = fork();
assert_se(pid >= 0);
static void test_restrict_address_families(void) {
pid_t pid;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
pid = fork();
assert_se(pid >= 0);
static void test_restrict_realtime(void) {
pid_t pid;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
- if (detect_container() > 0) /* in containers RT privs are likely missing anyway */
+ /* in containers RT privs are likely missing anyway */
+ if (detect_container() > 0) {
+ log_notice("Testing in container, skipping %s", __func__);
return;
+ }
pid = fork();
assert_se(pid >= 0);
static void test_memory_deny_write_execute_mmap(void) {
pid_t pid;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
pid = fork();
assert_se(pid >= 0);
int shmid;
pid_t pid;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
shmid = shmget(IPC_PRIVATE, page_size(), 0);
assert_se(shmid >= 0);
static void test_restrict_archs(void) {
pid_t pid;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
pid = fork();
assert_se(pid >= 0);
static void test_load_syscall_filter_set_raw(void) {
pid_t pid;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
pid = fork();
assert_se(pid >= 0);
unsigned long current;
pid_t pid;
- if (!is_seccomp_available())
+ if (!is_seccomp_available()) {
+ log_notice("Seccomp not available, skipping %s", __func__);
return;
- if (geteuid() != 0)
+ }
+ if (geteuid() != 0) {
+ log_notice("Not root, skipping %s", __func__);
return;
+ }
assert_se(opinionated_personality(¤t) >= 0);
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
test_seccomp_arch_to_string();
test_architecture_table();
#include "log.h"
#include "selinux-util.h"
#include "string-util.h"
+#include "tests.h"
#include "time-util.h"
#include "util.h"
if (argc >= 2)
path = argv[1];
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
test_testing();
test_loading();
#include <sys/mman.h>
+#if HAVE_VALGRIND_VALGRIND_H
+# include <valgrind/valgrind.h>
+#endif
+
#include "fd-util.h"
#include "sigbus.h"
+#include "tests.h"
#include "util.h"
-#if HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
-#endif
int main(int argc, char *argv[]) {
_cleanup_close_ int fd = -1;
void *addr = NULL;
uint8_t *p;
+ test_setup_logging(LOG_INFO);
+
+#ifdef __SANITIZE_ADDRESS__
+ return log_tests_skipped("address-sanitizer is enabled");
+#endif
#if HAVE_VALGRIND_VALGRIND_H
if (RUNNING_ON_VALGRIND)
- return EXIT_TEST_SKIP;
+ return log_tests_skipped("This test cannot run on valgrind");
#endif
-#ifdef __SANITIZE_ADDRESS__
- return EXIT_TEST_SKIP;
-#endif
sigbus_install();
assert_se(sigbus_pop(&addr) == 0);
#include "log.h"
#include "sleep-config.h"
#include "strv.h"
+#include "tests.h"
#include "util.h"
static void test_parse_sleep_config(void) {
if (fd < 0)
return log_error_errno(errno, "failed to open %s: %m", path);
r = read_fiemap(fd, &fiemap);
- if (r == -EOPNOTSUPP) {
- log_info("Skipping test, not supported");
- exit(EXIT_TEST_SKIP);
- }
+ if (r == -EOPNOTSUPP)
+ exit(log_tests_skipped("Not supported"));
if (r < 0)
return log_error_errno(r, "Unable to read extent map for '%s': %m", path);
log_info("extent map information for %s:", path);
int main(int argc, char* argv[]) {
int i, r = 0, k;
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_INFO);
if (getuid() != 0)
log_warning("This program is unlikely to work for unprivileged users");
#include "socket-util.h"
#include "string-util.h"
#include "util.h"
+#include "tests.h"
static void test_ifname_valid(void) {
assert(ifname_valid("foo"));
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
test_ifname_valid();
#include "specifier.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
static void test_specifier_escape_one(const char *a, const char *b) {
_cleanup_free_ char *x = NULL;
}
int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
+ test_setup_logging(LOG_DEBUG);
test_specifier_escape();
test_specifier_escape_strv();
assert_se(streq(w, ""));
}
+static void test_strv_join_prefix(void) {
+ _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL;
+
+ p = strv_join_prefix((char **)input_table_multiple, ", ", "foo");
+ assert_se(p);
+ assert_se(streq(p, "fooone, footwo, foothree"));
+
+ q = strv_join_prefix((char **)input_table_multiple, ";", "foo");
+ assert_se(q);
+ assert_se(streq(q, "fooone;footwo;foothree"));
+
+ r = strv_join_prefix((char **)input_table_multiple, NULL, "foo");
+ assert_se(r);
+ assert_se(streq(r, "fooone footwo foothree"));
+
+ s = strv_join_prefix((char **)input_table_one, ", ", "foo");
+ assert_se(s);
+ assert_se(streq(s, "fooone"));
+
+ t = strv_join_prefix((char **)input_table_none, ", ", "foo");
+ assert_se(t);
+ assert_se(streq(t, ""));
+
+ v = strv_join_prefix((char **)input_table_two_empties, ", ", "foo");
+ assert_se(v);
+ assert_se(streq(v, "foo, foo"));
+
+ w = strv_join_prefix((char **)input_table_one_empty, ", ", "foo");
+ assert_se(w);
+ assert_se(streq(w, "foo"));
+}
+
static void test_strv_unquote(const char *quoted, char **list) {
_cleanup_strv_free_ char **s;
_cleanup_free_ char *j;
static void test_strv_parse_nulstr(void) {
_cleanup_strv_free_ char **l = NULL;
- const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
+ const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
assert_se(l);
puts("Parse nulstr:");
strv_print(l);
- assert_se(streq(l[0], "fuck"));
- assert_se(streq(l[1], "fuck2"));
- assert_se(streq(l[2], "fuck3"));
+ assert_se(streq(l[0], "hoge"));
+ assert_se(streq(l[1], "hoge2"));
+ assert_se(streq(l[2], "hoge3"));
assert_se(streq(l[3], ""));
- assert_se(streq(l[4], "fuck5"));
+ assert_se(streq(l[4], "hoge5"));
assert_se(streq(l[5], ""));
assert_se(streq(l[6], "xxx"));
}
test_strv_find_prefix();
test_strv_find_startswith();
test_strv_join();
+ test_strv_join_prefix();
test_strv_unquote(" foo=bar \"waldo\" zzz ", STRV_MAKE("foo=bar", "waldo", "zzz"));
test_strv_unquote("", STRV_MAKE_EMPTY);
#include "log.h"
#include "process-util.h"
#include "string-util.h"
+#include "tests.h"
#include "util.h"
int main(int argc, char** argv) {
const char *p = argv[1] ?: "/tmp";
char *pattern;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
pattern = strjoina(p, "/systemd-test-XXXXXX");
}
int main(int argc, char **argv) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_mount_points_list(NULL);
test_mount_points_list("/test-umount/empty.mountinfo");
assert_se(h);
r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
-
- if (IN_SET(r, -EPERM, -EACCES)) {
- log_notice_errno(r, "Skipping test: unit_file_get_list: %m");
- return EXIT_TEST_SKIP;
- }
+ if (IN_SET(r, -EPERM, -EACCES))
+ return log_tests_skipped_errno(r, "unit_file_get_list");
log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r,
"unit_file_get_list: %m");
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
int r;
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_INFO);
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- log_notice_errno(r, "Skipping test: cgroupfs not available");
- return EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(get_shell(&shell) >= 0);
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
- if (MANAGER_SKIP_TEST(r)) {
- log_notice_errno(r, "Skipping test: manager_new: %m");
- return EXIT_TEST_SKIP;
- }
+ if (MANAGER_SKIP_TEST(r))
+ return log_tests_skipped_errno(r, "manager_new");
assert_se(r == 0);
#define expect(unit, pattern, expected) \
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
int r, rc = 0;
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_INFO);
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- log_notice_errno(r, "Skipping test: cgroupfs not available");
- return EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
assert_se(runtime_dir = setup_fake_runtime_dir());
Unit *a, *b, *c, *u;
int r;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
-
- if (getuid() != 0) {
- log_notice("Not running as root, skipping kernel related tests.");
- return EXIT_TEST_SKIP;
- }
+ test_setup_logging(LOG_DEBUG);
+ if (getuid() != 0)
+ return log_tests_skipped("not root");
r = enter_cgroup_subroot();
- if (r == -ENOMEDIUM) {
- log_notice("cgroupfs not available, skipping tests");
- return EXIT_TEST_SKIP;
- }
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
assert_se(set_unit_path(get_testdata_dir()) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
#include <string.h>
#include <unistd.h>
-#include "env-util.h"
#include "log.h"
+#include "tests.h"
#include "watchdog.h"
int main(int argc, char *argv[]) {
int r;
bool slow;
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
- r = getenv_bool("SYSTEMD_SLOW_TESTS");
- slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
+ slow = slow_tests_enabled();
t = slow ? 10 * USEC_PER_SEC : 1 * USEC_PER_SEC;
count = slow ? 5 : 3;
#include "fs-util.h"
#include "macro.h"
#include "string-util.h"
+#include "tests.h"
#include "xattr-util.h"
static void test_fgetxattrat_fake(void) {
}
int main(void) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
+ test_setup_logging(LOG_DEBUG);
test_fgetxattrat_fake();
test_getcrtime();
#include "log.h"
#include "macro.h"
#include "timesyncd-conf.h"
+#include "tests.h"
static void test_manager_parse_string(void) {
/* Make sure that NTP_SERVERS is configured to something
}
int main(int argc, char **argv) {
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
+ test_setup_logging(LOG_DEBUG);
test_manager_parse_string();
free(a);
}
-static int item_compare(const void *a, const void *b) {
- const Item *x = a, *y = b;
-
+static int item_compare(const Item *a, const Item *b) {
/* Make sure that the ownership taking item is put first, so
* that we first create the node, and then can adjust it */
- if (takes_ownership(x->type) && !takes_ownership(y->type))
+ if (takes_ownership(a->type) && !takes_ownership(b->type))
return -1;
- if (!takes_ownership(x->type) && takes_ownership(y->type))
+ if (!takes_ownership(a->type) && takes_ownership(b->type))
return 1;
- return (int) x->type - (int) y->type;
+ return CMP(a->type, b->type);
}
static bool item_compatible(Item *a, Item *b) {
memcpy(existing->items + existing->count++, &i, sizeof(i));
/* Sort item array, to enforce stable ordering of application */
- qsort_safe(existing->items, existing->count, sizeof(Item), item_compare);
+ typesafe_qsort(existing->items, existing->count, item_compare);
zero(i);
return 0;
*
* Two character prefixes based on the type of interface:
* en — Ethernet
+ * ib — InfiniBand
* sl — serial line IP (slip)
* wl — wlan
* ww — wwan
* ID_NET_NAME_MAC=wlx0024d7e31130
* ID_NET_NAME_PATH=wlp3s0
*
+ * PCI IB host adapter with 2 ports:
+ * /sys/devices/pci0000:00/0000:00:03.0/0000:15:00.0/net/ibp21s0f0
+ * ID_NET_NAME_PATH=ibp21s0f0
+ * /sys/devices/pci0000:00/0000:00:03.0/0000:15:00.1/net/ibp21s0f1
+ * ID_NET_NAME_PATH=ibp21s0f1
+ *
* USB built-in 3G modem:
* /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
* ID_NET_NAME_MAC=wwx028037ec0200
/* retrieve on-board index number and label from firmware */
static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
- unsigned dev_port = 0;
+ unsigned long idx, dev_port = 0;
+ const char *attr, *port_name;
size_t l;
char *s;
- const char *attr, *port_name;
- int idx;
/* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
/* kernel provided port index for multiple ports on a single PCI function */
attr = udev_device_get_sysattr_value(dev, "dev_port");
if (attr)
- dev_port = strtol(attr, NULL, 10);
+ dev_port = strtoul(attr, NULL, 10);
/* kernel provided front panel port name for multiple port PCI device */
port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
s = names->pci_onboard;
l = sizeof(names->pci_onboard);
- l = strpcpyf(&s, l, "o%d", idx);
+ l = strpcpyf(&s, l, "o%lu", idx);
if (port_name)
l = strpcpyf(&s, l, "n%s", port_name);
else if (dev_port > 0)
- l = strpcpyf(&s, l, "d%d", dev_port);
+ l = strpcpyf(&s, l, "d%lu", dev_port);
if (l == 0)
names->pci_onboard[0] = '\0';
}
static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
- unsigned domain, bus, slot, func, dev_port = 0, hotplug_slot = 0;
+ unsigned long dev_port = 0;
+ unsigned domain, bus, slot, func, hotplug_slot = 0;
size_t l;
char *s;
const char *attr, *port_name;
/* kernel provided port index for multiple ports on a single PCI function */
attr = udev_device_get_sysattr_value(dev, "dev_port");
- if (attr)
- dev_port = strtol(attr, NULL, 10);
+ if (attr) {
+ dev_port = strtoul(attr, NULL, 10);
+ /* With older kernels IP-over-InfiniBand network interfaces sometimes erroneously
+ * provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port',
+ * which thus stays initialized as 0. */
+ if (dev_port == 0) {
+ unsigned long type;
+
+ attr = udev_device_get_sysattr_value(dev, "type");
+ /* The 'type' attribute always exists. */
+ type = strtoul(attr, NULL, 10);
+ if (type == ARPHRD_INFINIBAND) {
+ attr = udev_device_get_sysattr_value(dev, "dev_id");
+ if (attr)
+ dev_port = strtoul(attr, NULL, 16);
+ }
+ }
+ }
/* kernel provided front panel port name for multiple port PCI device */
port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
if (port_name)
l = strpcpyf(&s, l, "n%s", port_name);
else if (dev_port > 0)
- l = strpcpyf(&s, l, "d%u", dev_port);
+ l = strpcpyf(&s, l, "d%lu", dev_port);
if (l == 0)
names->pci_path[0] = '\0';
if (port_name)
l = strpcpyf(&s, l, "n%s", port_name);
else if (dev_port > 0)
- l = strpcpyf(&s, l, "d%d", dev_port);
+ l = strpcpyf(&s, l, "d%lu", dev_port);
if (l == 0)
names->pci_slot[0] = '\0';
}
static int names_mac(struct udev_device *dev, struct netnames *names) {
const char *s;
- unsigned int i;
+ unsigned long i;
unsigned int a1, a2, a3, a4, a5, a6;
+ /* Some kinds of devices tend to have hardware addresses
+ * that are impossible to use in an iface name.
+ */
+ s = udev_device_get_sysattr_value(dev, "type");
+ if (!s)
+ return EXIT_FAILURE;
+ i = strtoul(s, NULL, 0);
+ switch (i) {
+ /* The persistent part of a hardware address of an InfiniBand NIC
+ * is 8 bytes long. We cannot fit this much in an iface name.
+ */
+ case ARPHRD_INFINIBAND:
+ return -EINVAL;
+ default:
+ break;
+ }
+
/* check for NET_ADDR_PERM, skip random MAC addresses */
s = udev_device_get_sysattr_value(dev, "addr_assign_type");
if (!s)
static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
const char *s;
const char *p;
- unsigned int i;
+ unsigned long i;
const char *devtype;
const char *prefix = "en";
struct netnames names = {};
int err;
- /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
+ /* handle only ARPHRD_ETHER, ARPHRD_SLIP
+ * and ARPHRD_INFINIBAND devices
+ */
s = udev_device_get_sysattr_value(dev, "type");
if (!s)
return EXIT_FAILURE;
case ARPHRD_ETHER:
prefix = "en";
break;
+ case ARPHRD_INFINIBAND:
+ prefix = "ib";
+ break;
case ARPHRD_SLIP:
prefix = "sl";
break;
break;
}
case 'V':
- return version();
+ return print_version();
case 'h':
return help();
case '?':
/* SPDX-License-Identifier: LGPL-2.1+ */
-#include <ctype.h>
#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include "alloc-util.h"
-#include "conf-files.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hwdb-internal.h"
#include "hwdb-util.h"
-#include "label.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "strbuf.h"
-#include "string-util.h"
-#include "udev.h"
#include "udevadm.h"
#include "util.h"
-/*
- * Generic udev properties, key/value database based on modalias strings.
- * Uses a Patricia/radix trie to index all matches for efficient lookup.
- */
-
static const char *arg_test = NULL;
static const char *arg_root = NULL;
-static const char *arg_hwdb_bin_dir = "/etc/udev";
+static const char *arg_hwdb_bin_dir = NULL;
static bool arg_update = false;
static bool arg_strict = false;
-static const char * const conf_file_dirs[] = {
- "/etc/udev/hwdb.d",
- UDEVLIBEXECDIR "/hwdb.d",
- NULL
-};
-
-/* in-memory trie objects */
-struct trie {
- struct trie_node *root;
- struct strbuf *strings;
-
- size_t nodes_count;
- size_t children_count;
- size_t values_count;
-};
-
-struct trie_node {
- /* prefix, common part for all children of this node */
- size_t prefix_off;
-
- /* sorted array of pointers to children nodes */
- struct trie_child_entry *children;
- uint8_t children_count;
-
- /* sorted array of key/value pairs */
- struct trie_value_entry *values;
- size_t values_count;
-};
-
-/* children array item with char (0-255) index */
-struct trie_child_entry {
- uint8_t c;
- struct trie_node *child;
-};
-
-/* value array item with key/value pairs */
-struct trie_value_entry {
- size_t key_off;
- size_t value_off;
-};
-
-static int trie_children_cmp(const void *v1, const void *v2) {
- const struct trie_child_entry *n1 = v1;
- const struct trie_child_entry *n2 = v2;
-
- return n1->c - n2->c;
-}
-
-static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
- struct trie_child_entry *child;
-
- /* extend array, add new entry, sort for bisection */
- child = reallocarray(node->children, node->children_count + 1, sizeof(struct trie_child_entry));
- if (!child)
- return -ENOMEM;
-
- node->children = child;
- trie->children_count++;
- node->children[node->children_count].c = c;
- node->children[node->children_count].child = node_child;
- node->children_count++;
- qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
- trie->nodes_count++;
-
- return 0;
-}
-
-static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
- struct trie_child_entry *child;
- struct trie_child_entry search;
-
- search.c = c;
- child = bsearch_safe(&search,
- node->children, node->children_count, sizeof(struct trie_child_entry),
- trie_children_cmp);
- if (child)
- return child->child;
- return NULL;
-}
-
-static void trie_node_cleanup(struct trie_node *node) {
- size_t i;
-
- if (!node)
- return;
-
- for (i = 0; i < node->children_count; i++)
- trie_node_cleanup(node->children[i].child);
- free(node->children);
- free(node->values);
- free(node);
-}
-
-static void trie_free(struct trie *trie) {
- if (!trie)
- return;
-
- trie_node_cleanup(trie->root);
- strbuf_cleanup(trie->strings);
- free(trie);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct trie*, trie_free);
-
-static int trie_values_cmp(const void *v1, const void *v2, void *arg) {
- const struct trie_value_entry *val1 = v1;
- const struct trie_value_entry *val2 = v2;
- struct trie *trie = arg;
-
- return strcmp(trie->strings->buf + val1->key_off,
- trie->strings->buf + val2->key_off);
-}
-
-static int trie_node_add_value(struct trie *trie, struct trie_node *node,
- const char *key, const char *value) {
- ssize_t k, v;
- struct trie_value_entry *val;
-
- k = strbuf_add_string(trie->strings, key, strlen(key));
- if (k < 0)
- return k;
- v = strbuf_add_string(trie->strings, value, strlen(value));
- if (v < 0)
- return v;
-
- if (node->values_count) {
- struct trie_value_entry search = {
- .key_off = k,
- .value_off = v,
- };
-
- val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
- if (val) {
- /* replace existing earlier key with new value */
- val->value_off = v;
- return 0;
- }
- }
-
- /* extend array, add new entry, sort for bisection */
- val = reallocarray(node->values, node->values_count + 1, sizeof(struct trie_value_entry));
- if (!val)
- return -ENOMEM;
- trie->values_count++;
- node->values = val;
- node->values[node->values_count].key_off = k;
- node->values[node->values_count].value_off = v;
- node->values_count++;
- qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
- return 0;
-}
-
-static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
- const char *key, const char *value) {
- size_t i = 0;
- int err = 0;
-
- for (;;) {
- size_t p;
- uint8_t c;
- struct trie_node *child;
-
- for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
- _cleanup_free_ char *s = NULL;
- ssize_t off;
- _cleanup_free_ struct trie_node *new_child = NULL;
-
- if (c == search[i + p])
- continue;
-
- /* split node */
- new_child = new0(struct trie_node, 1);
- if (!new_child)
- return -ENOMEM;
-
- /* move values from parent to child */
- new_child->prefix_off = node->prefix_off + p+1;
- new_child->children = node->children;
- new_child->children_count = node->children_count;
- new_child->values = node->values;
- new_child->values_count = node->values_count;
-
- /* update parent; use strdup() because the source gets realloc()d */
- s = strndup(trie->strings->buf + node->prefix_off, p);
- if (!s)
- return -ENOMEM;
-
- off = strbuf_add_string(trie->strings, s, p);
- if (off < 0)
- return off;
-
- node->prefix_off = off;
- node->children = NULL;
- node->children_count = 0;
- node->values = NULL;
- node->values_count = 0;
- err = node_add_child(trie, node, new_child, c);
- if (err)
- return err;
-
- new_child = NULL; /* avoid cleanup */
- break;
- }
- i += p;
-
- c = search[i];
- if (c == '\0')
- return trie_node_add_value(trie, node, key, value);
-
- child = node_lookup(node, c);
- if (!child) {
- ssize_t off;
-
- /* new child */
- child = new0(struct trie_node, 1);
- if (!child)
- return -ENOMEM;
-
- off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
- if (off < 0) {
- free(child);
- return off;
- }
-
- child->prefix_off = off;
- err = node_add_child(trie, node, child, c);
- if (err) {
- free(child);
- return err;
- }
-
- return trie_node_add_value(trie, child, key, value);
- }
-
- node = child;
- i++;
- }
-}
-
-struct trie_f {
- FILE *f;
- struct trie *trie;
- uint64_t strings_off;
-
- uint64_t nodes_count;
- uint64_t children_count;
- uint64_t values_count;
-};
-
-/* calculate the storage space for the nodes, children arrays, value arrays */
-static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) {
- uint64_t i;
-
- for (i = 0; i < node->children_count; i++)
- trie_store_nodes_size(trie, node->children[i].child);
-
- trie->strings_off += sizeof(struct trie_node_f);
- for (i = 0; i < node->children_count; i++)
- trie->strings_off += sizeof(struct trie_child_entry_f);
- for (i = 0; i < node->values_count; i++)
- trie->strings_off += sizeof(struct trie_value_entry_f);
-}
-
-static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
- uint64_t i;
- struct trie_node_f n = {
- .prefix_off = htole64(trie->strings_off + node->prefix_off),
- .children_count = node->children_count,
- .values_count = htole64(node->values_count),
- };
- struct trie_child_entry_f *children = NULL;
- int64_t node_off;
-
- if (node->children_count) {
- children = new0(struct trie_child_entry_f, node->children_count);
- if (!children)
- return -ENOMEM;
- }
-
- /* post-order recursion */
- for (i = 0; i < node->children_count; i++) {
- int64_t child_off;
-
- child_off = trie_store_nodes(trie, node->children[i].child);
- if (child_off < 0) {
- free(children);
- return child_off;
- }
- children[i].c = node->children[i].c;
- children[i].child_off = htole64(child_off);
- }
-
- /* write node */
- node_off = ftello(trie->f);
- fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
- trie->nodes_count++;
-
- /* append children array */
- if (node->children_count) {
- fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
- trie->children_count += node->children_count;
- free(children);
- }
-
- /* append values array */
- for (i = 0; i < node->values_count; i++) {
- struct trie_value_entry_f v = {
- .key_off = htole64(trie->strings_off + node->values[i].key_off),
- .value_off = htole64(trie->strings_off + node->values[i].value_off),
- };
-
- fwrite(&v, sizeof(struct trie_value_entry_f), 1, trie->f);
- trie->values_count++;
- }
-
- return node_off;
-}
-
-static int trie_store(struct trie *trie, const char *filename) {
- struct trie_f t = {
- .trie = trie,
- };
- _cleanup_free_ char *filename_tmp = NULL;
- int64_t pos;
- int64_t root_off;
- int64_t size;
- struct trie_header_f h = {
- .signature = HWDB_SIG,
- .tool_version = htole64(atoi(PACKAGE_VERSION)),
- .header_size = htole64(sizeof(struct trie_header_f)),
- .node_size = htole64(sizeof(struct trie_node_f)),
- .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
- .value_entry_size = htole64(sizeof(struct trie_value_entry_f)),
- };
- int err;
-
- /* calculate size of header, nodes, children entries, value entries */
- t.strings_off = sizeof(struct trie_header_f);
- trie_store_nodes_size(&t, trie->root);
-
- err = fopen_temporary(filename, &t.f, &filename_tmp);
- if (err < 0)
- return err;
- fchmod(fileno(t.f), 0444);
-
- /* write nodes */
- if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
- goto error_fclose;
- root_off = trie_store_nodes(&t, trie->root);
- h.nodes_root_off = htole64(root_off);
- pos = ftello(t.f);
- h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
-
- /* write string buffer */
- fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
- h.strings_len = htole64(trie->strings->len);
-
- /* write header */
- size = ftello(t.f);
- h.file_size = htole64(size);
- if (fseeko(t.f, 0, SEEK_SET < 0))
- goto error_fclose;
- fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
-
- if (ferror(t.f))
- goto error_fclose;
- if (fflush(t.f) < 0)
- goto error_fclose;
- if (fsync(fileno(t.f)) < 0)
- goto error_fclose;
- if (rename(filename_tmp, filename) < 0)
- goto error_fclose;
-
- /* write succeeded */
- fclose(t.f);
-
- log_debug("=== trie on-disk ===");
- log_debug("size: %8"PRIi64" bytes", size);
- log_debug("header: %8zu bytes", sizeof(struct trie_header_f));
- log_debug("nodes: %8"PRIu64" bytes (%8"PRIu64")",
- t.nodes_count * sizeof(struct trie_node_f), t.nodes_count);
- log_debug("child pointers: %8"PRIu64" bytes (%8"PRIu64")",
- t.children_count * sizeof(struct trie_child_entry_f), t.children_count);
- log_debug("value pointers: %8"PRIu64" bytes (%8"PRIu64")",
- t.values_count * sizeof(struct trie_value_entry_f), t.values_count);
- log_debug("string store: %8zu bytes", trie->strings->len);
- log_debug("strings start: %8"PRIu64, t.strings_off);
-
- return 0;
-
- error_fclose:
- err = -errno;
- fclose(t.f);
- unlink(filename_tmp);
- return err;
-}
-
-static int insert_data(struct trie *trie, struct udev_list *match_list,
- char *line, const char *filename) {
- char *value;
- struct udev_list_entry *entry;
-
- value = strchr(line, '=');
- if (!value) {
- log_error("Error, key/value pair expected but got '%s' in '%s':", line, filename);
- return -EINVAL;
- }
-
- value[0] = '\0';
- value++;
-
- /* libudev requires properties to start with a space */
- while (isblank(line[0]) && isblank(line[1]))
- line++;
-
- if (line[0] == '\0' || value[0] == '\0') {
- log_error("Error, empty key or value '%s' in '%s':", line, filename);
- return -EINVAL;
- }
-
- udev_list_entry_foreach(entry, udev_list_get_entry(match_list))
- trie_insert(trie, trie->root, udev_list_entry_get_name(entry), line, value);
-
- return 0;
-}
-
-static int import_file(struct trie *trie, const char *filename) {
- enum {
- HW_MATCH,
- HW_DATA,
- HW_NONE,
- } state = HW_NONE;
- FILE *f;
- char line[LINE_MAX];
- struct udev_list match_list;
- int r = 0, err;
-
- udev_list_init(NULL, &match_list, false);
-
- f = fopen(filename, "re");
- if (f == NULL)
- return -errno;
-
- while (fgets(line, sizeof(line), f)) {
- size_t len;
- char *pos;
-
- /* comment line */
- if (line[0] == '#')
- continue;
-
- /* strip trailing comment */
- pos = strchr(line, '#');
- if (pos)
- pos[0] = '\0';
-
- /* strip trailing whitespace */
- len = strlen(line);
- while (len > 0 && isspace(line[len-1]))
- len--;
- line[len] = '\0';
-
- switch (state) {
- case HW_NONE:
- if (len == 0)
- break;
-
- if (line[0] == ' ') {
- log_error("Error, MATCH expected but got '%s' in '%s':", line, filename);
- r = -EINVAL;
- break;
- }
-
- /* start of record, first match */
- state = HW_MATCH;
- udev_list_entry_add(&match_list, line, NULL);
- break;
-
- case HW_MATCH:
- if (len == 0) {
- log_error("Error, DATA expected but got empty line in '%s':", filename);
- r = -EINVAL;
- state = HW_NONE;
- udev_list_cleanup(&match_list);
- break;
- }
-
- /* another match */
- if (line[0] != ' ') {
- udev_list_entry_add(&match_list, line, NULL);
- break;
- }
-
- /* first data */
- state = HW_DATA;
- err = insert_data(trie, &match_list, line, filename);
- if (err < 0)
- r = err;
- break;
-
- case HW_DATA:
- /* end of record */
- if (len == 0) {
- state = HW_NONE;
- udev_list_cleanup(&match_list);
- break;
- }
-
- if (line[0] != ' ') {
- log_error("Error, DATA expected but got '%s' in '%s':", line, filename);
- r = -EINVAL;
- state = HW_NONE;
- udev_list_cleanup(&match_list);
- break;
- }
-
- err = insert_data(trie, &match_list, line, filename);
- if (err < 0)
- r = err;
- break;
- };
- }
-
- fclose(f);
- udev_list_cleanup(&match_list);
- return r;
-}
-
-static int hwdb_update(void) {
- _cleanup_(trie_freep) struct trie *trie = NULL;
- _cleanup_strv_free_ char **files = NULL;
- _cleanup_free_ char *hwdb_bin = NULL;
- char **f;
- int r;
-
- trie = new0(struct trie, 1);
- if (!trie)
- return -ENOMEM;
-
- /* string store */
- trie->strings = strbuf_new();
- if (!trie->strings)
- return -ENOMEM;
-
- /* index */
- trie->root = new0(struct trie_node, 1);
- if (!trie->root)
- return -ENOMEM;
-
- trie->nodes_count++;
-
- r = conf_files_list_strv(&files, ".hwdb", arg_root, 0, conf_file_dirs);
- if (r < 0)
- return log_error_errno(r, "failed to enumerate hwdb files: %m");
-
- STRV_FOREACH(f, files) {
- log_debug("Reading file '%s'", *f);
- r = import_file(trie, *f);
- if (r < 0 && arg_strict)
- return r;
- }
-
- strbuf_complete(trie->strings);
-
- log_debug("=== trie in-memory ===");
- log_debug("nodes: %8zu bytes (%8zu)",
- trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
- log_debug("children arrays: %8zu bytes (%8zu)",
- trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
- log_debug("values arrays: %8zu bytes (%8zu)",
- trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
- log_debug("strings: %8zu bytes",
- trie->strings->len);
- log_debug("strings incoming: %8zu bytes (%8zu)",
- trie->strings->in_len, trie->strings->in_count);
- log_debug("strings dedup'ed: %8zu bytes (%8zu)",
- trie->strings->dedup_len, trie->strings->dedup_count);
-
- hwdb_bin = path_join(arg_root, arg_hwdb_bin_dir, "/hwdb.bin");
- if (!hwdb_bin)
- return -ENOMEM;
-
- mkdir_parents_label(hwdb_bin, 0755);
-
- r = trie_store(trie, hwdb_bin);
- if (r < 0)
- log_error_errno(r, "Failed to write database %s: %m", hwdb_bin);
-
- (void) label_fix(hwdb_bin, 0);
-
- return r;
-}
-
-static int hwdb_test(void) {
- _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
- const char *key, *value;
- int r;
-
- r = sd_hwdb_new(&hwdb);
- if (r < 0)
- return r;
-
- SD_HWDB_FOREACH_PROPERTY(hwdb, arg_test, key, value)
- printf("%s=%s\n", key, value);
-
- return 0;
-}
-
static int help(void) {
printf("%s hwdb [OPTIONS]\n\n"
" -h --help Print this message\n"
arg_root = optarg;
break;
case 'V':
- return version();
+ return print_version();
case 'h':
return help();
case '?':
int hwdb_main(int argc, char *argv[], void *userdata) {
int r;
+ log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level());
+
r = parse_argv(argc, argv);
- if (r < 0)
+ if (r <= 0)
return r;
if (!arg_update && !arg_test) {
}
if (arg_update) {
- r = hwdb_update();
+ r = hwdb_update(arg_root, arg_hwdb_bin_dir, arg_strict, true);
if (r < 0)
return r;
}
if (arg_test)
- return hwdb_test();
+ return hwdb_query(arg_test);
return 0;
}
export_prefix = optarg;
break;
case 'V':
- return version();
+ return print_version();
case 'h':
return help();
case '?':
break;
}
case 'V':
- return version();
+ return print_version();
case 'h':
return help();
case '?':
arg_exists = optarg;
break;
case 'V':
- return version();
+ return print_version();
case 'h':
return help();
case 's':
while ((c = getopt_long(argc, argv, "Vh", options, NULL)) >= 0)
switch (c) {
case 'V':
- return version();
+ return print_version();
case 'h':
return help();
case '?':
}
break;
case 'V':
- return version();
+ return print_version();
case 'h':
return help();
case '?':
}
case 'V':
- return version();
+ return print_version();
case 'h':
return help();
case '?':
return help();
case 'V':
- return version();
+ return print_version();
case '?':
return -EINVAL;
}
static int version_main(int argc, char *argv[], void *userdata) {
- return version();
+ return print_version();
}
static int help_main(int argc, char *argv[], void *userdata) {
/* SPDX-License-Identifier: GPL-2.0+ */
#pragma once
+#include <stdio.h>
+
int info_main(int argc, char *argv[], void *userdata);
int trigger_main(int argc, char *argv[], void *userdata);
int settle_main(int argc, char *argv[], void *userdata);
int hwdb_main(int argc, char *argv[], void *userdata);
int test_main(int argc, char *argv[], void *userdata);
int builtin_main(int argc, char *argv[], void *userdata);
+
+static inline int print_version(void) {
+ puts(PACKAGE_VERSION);
+ return 0;
+}
############################################################
rule_syntax_check_py = find_program('rule-syntax-check.py')
-test('rule-syntax-check',
- rule_syntax_check_py,
- args : all_rules)
+if want_tests != 'false'
+ test('rule-syntax-check',
+ rule_syntax_check_py,
+ args : all_rules)
+endif
############################################################
if conf.get('HAVE_SYSV_COMPAT') == 1
sysv_generator_test_py = find_program('sysv-generator-test.py')
- test('sysv-generator-test',
- sysv_generator_test_py)
+ if want_tests != 'false'
+ test('sysv-generator-test',
+ sysv_generator_test_py)
+ endif
endif
############################################################
'sys',
command : [sys_script_py, meson.current_build_dir()],
output : 'sys',
- build_by_default : true)
+ build_by_default : want_tests != 'false')
if perl.found()
udev_test_pl = find_program('udev-test.pl')
- test('udev-test',
- udev_test_pl)
+ if want_tests != 'false'
+ test('udev-test',
+ udev_test_pl)
+ endif
else
message('Skipping udev-test because perl is not available')
endif
if conf.get('ENABLE_HWDB') == 1
hwdb_test_sh = find_program('hwdb-test.sh')
- test('hwdb-test',
- hwdb_test_sh,
- timeout : 90)
+ if want_tests != 'false'
+ test('hwdb-test',
+ hwdb_test_sh,
+ timeout : 90)
+ endif
endif
subdir('fuzz-regressions')
ExecStart=test -d /var/lib/test-dynamicuser-migrate2/hoge
ExecStart=touch /var/lib/test-dynamicuser-migrate/yay
ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
Type=oneshot
DynamicUser=no
ExecStart=touch /var/lib/test-dynamicuser-migrate2/hoge/yayyay
ExecStart=touch /var/lib/private/test-dynamicuser-migrate/yay
ExecStart=touch /var/lib/private/test-dynamicuser-migrate2/hoge/yayyay
+ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/test-dynamicuser-migrate:%S/test-dynamicuser-migrate2/hoge"'
Type=oneshot
DynamicUser=yes
ExecStart=test -f /var/lib/quux/pief/yayyay
ExecStart=test -f /var/lib/private/waldo/yay
ExecStart=test -f /var/lib/private/quux/pief/yayyay
+ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/waldo:%S/quux/pief"'
# Make sure that /var/lib/private/waldo is really the only writable directory besides the obvious candidates
ExecStart=sh -x -c 'test $$(find / \( -path /var/tmp -o -path /tmp -o -path /proc -o -path /dev/mqueue -o -path /dev/shm -o -path /sys/fs/bpf \) -prune -o -type d -writable -print 2>/dev/null | sort -u | tr -d '\\\\n') = /var/lib/private/quux/pief/var/lib/private/waldo'
[Service]
ExecStart=/bin/sh -x -c 'mode=$$(stat -c %%a %t/test-exec_runtimedirectory-mode); test "$$mode" = "750"'
+ExecStart=/bin/sh -x -c 'test "$$RUNTIME_DIRECTORY" = "%t/test-exec_runtimedirectory-mode"'
Type=oneshot
RuntimeDirectory=test-exec_runtimedirectory-mode
RuntimeDirectoryMode=0750
[Service]
ExecStart=/bin/sh -x -c 'test -d %t/test-exec_runtimedirectory'
ExecStart=/bin/sh -x -c 'test -d %t/test-exec_runtimedirectory2/hogehoge'
+ExecStart=/bin/sh -x -c 'test "$$RUNTIME_DIRECTORY" = "%t/test-exec_runtimedirectory:%t/test-exec_runtimedirectory2/hogehoge"'
Type=oneshot
RuntimeDirectory=test-exec_runtimedirectory
RuntimeDirectory=./test-exec_runtimedirectory2///./hogehoge/.
set -x
DEFAULT_ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
-DEFAULT_ENVIRONMENT=ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS
+DEFAULT_UBSAN_OPTIONS=print_stacktrace=1:print_summary=1
+DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mkdir -p "\$JOURNALD_CONF_DIR"
printf "[Service]\nEnvironment=ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd-journald.asan.log\n" >"\$JOURNALD_CONF_DIR/env.conf"
-export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log
+export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
exec $ROOTLIBDIR/systemd "\$@"
EOF
export PKG_CONFIG_PATH=$BUILD_DIR/src/core/
systemdsystemunitdir=$(pkg-config --variable=systemdsystemunitdir systemd)
systemduserunitdir=$(pkg-config --variable=systemduserunitdir systemd)
- egrep -ho '^Exec[^ ]*=[^ ]+' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
- | while read i; do
- i=${i##Exec*=}; i=${i##[@+\!-]}; i=${i##\!}
+ sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
+ | sort -u | while read i; do
# some {rc,halt}.local scripts and programs are okay to not exist, the rest should
inst $i || [ "${i%.local}" != "$i" ] || [ "${i%systemd-update-done}" != "$i" ]
done
case "$target" in
*/)
- mkdir -p -m 0755 "$dir"
+ mkdir -vp -m 0755 "$dir"
;;
*)
- mkdir -p -m 0755 "$(basename "$dir")"
+ mkdir -vp -m 0755 "$(dirname "$dir")"
;;
esac
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
DefaultDependencies=no
Conflicts=shutdown.target
-After=local-fs.target systemd-sysusers.service
+After=local-fs.target systemd-sysusers.service systemd-journald.service
Before=sysinit.target shutdown.target
RefuseManualStop=yes