Compare commits
38 Commits
18fe53b40a
...
8e5c5c1f48
Author | SHA1 | Date |
---|---|---|
![]() |
8e5c5c1f48 | |
![]() |
b8fd3f77db | |
![]() |
44c2c9a036 | |
![]() |
9fea5b4250 | |
![]() |
793e187718 | |
![]() |
95609f3dff | |
![]() |
5d226b2f9a | |
![]() |
93a1f7921a | |
![]() |
c68eb22064 | |
![]() |
03e17cbe6e | |
![]() |
edfd847d47 | |
![]() |
5a124e8ee1 | |
![]() |
69ebfef1a1 | |
![]() |
4a52d26d2b | |
![]() |
b14f74f9ab | |
![]() |
defd5060d6 | |
![]() |
a4bff6ef8e | |
![]() |
ae04218383 | |
![]() |
2a6ca54154 | |
![]() |
40d60725ec | |
![]() |
39dd06dbc4 | |
![]() |
a30684b983 | |
![]() |
bdf4f200fd | |
![]() |
4cbc25ab4c | |
![]() |
885001ed5d | |
![]() |
2d4c4d9e10 | |
![]() |
828513ee3e | |
![]() |
b0a2d49b61 | |
![]() |
f6a2a9ba93 | |
![]() |
1785961660 | |
![]() |
7c78827c19 | |
![]() |
1b88fa8ae4 | |
![]() |
2f7d51ee01 | |
![]() |
74c2faff3d | |
![]() |
354be2190f | |
![]() |
d17ae799f2 | |
![]() |
13d9fecdd0 | |
![]() |
d9ac4b925d |
|
@ -32,23 +32,23 @@ The following exceptions apply:
|
||||||
* some sources under src/udev/ are licensed under **GPL-2.0-or-later**,
|
* some sources under src/udev/ are licensed under **GPL-2.0-or-later**,
|
||||||
so all udev programs (`systemd-udevd`, `udevadm`, and the udev builtins
|
so all udev programs (`systemd-udevd`, `udevadm`, and the udev builtins
|
||||||
and test programs) are also distributed under **GPL-2.0-or-later**.
|
and test programs) are also distributed under **GPL-2.0-or-later**.
|
||||||
* the header files contained in src/basic/linux/ and src/shared/linux/ are copied
|
* the header files contained in src/basic/include/linux are copied
|
||||||
verbatim from the Linux kernel source tree and are licensed under **GPL-2.0 WITH
|
verbatim from the Linux kernel source tree and are licensed under **GPL-2.0 WITH
|
||||||
Linux-syscall-note** and are used within the scope of the Linux-syscall-note
|
Linux-syscall-note** and are used within the scope of the Linux-syscall-note
|
||||||
exception provisions
|
exception provisions
|
||||||
* the following sources are licensed under the **LGPL-2.0-or-later** license:
|
* the following sources are licensed under the **LGPL-2.0-or-later** license:
|
||||||
- src/basic/utf8.c
|
- src/basic/utf8.c
|
||||||
- src/shared/initreq.h
|
- src/shared/initreq.h
|
||||||
* the src/shared/linux/bpf_insn.h header is copied from the Linux kernel
|
* the src/basic/include/linux/bpf_insn.h header is copied from the Linux kernel
|
||||||
source tree and is licensed under either **BSD-2-Clause** or **GPL-2.0-only**,
|
source tree and is licensed under either **BSD-2-Clause** or **GPL-2.0-only**,
|
||||||
and thus is included in the systemd build under the BSD-2-Clause license.
|
and thus is included in the systemd build under the BSD-2-Clause license.
|
||||||
* The src/basic/linux/wireguard.h header is copied from the Linux kernel
|
* The src/basic/include/linux/wireguard.h header is copied from the Linux kernel
|
||||||
source tree and is licensed under either **MIT** or **GPL-2.0 WITH Linux-syscall-note**,
|
source tree and is licensed under either **MIT** or **GPL-2.0 WITH Linux-syscall-note**,
|
||||||
and thus is included in the systemd build under the MIT license.
|
and thus is included in the systemd build under the MIT license.
|
||||||
* the following sources are licensed under the **MIT** license (in case of our
|
* the following sources are licensed under the **MIT** license (in case of our
|
||||||
scripts, to facilitate copying and reuse of those helpers to other projects):
|
scripts, to facilitate copying and reuse of those helpers to other projects):
|
||||||
- hwdb.d/parse_hwdb.py
|
- hwdb.d/parse_hwdb.py
|
||||||
- src/basic/linux/batman_adv.h
|
- src/basic/include/linux/batman_adv.h
|
||||||
- src/basic/sparse-endian.h
|
- src/basic/sparse-endian.h
|
||||||
- tools/catalog-report.py
|
- tools/catalog-report.py
|
||||||
* the following sources are licensed under the **CC0-1.0** license:
|
* the following sources are licensed under the **CC0-1.0** license:
|
||||||
|
|
4
TODO
4
TODO
|
@ -735,10 +735,6 @@ Features:
|
||||||
* machined: optionally track nspawn unix-export/ runtime for each machined, and
|
* machined: optionally track nspawn unix-export/ runtime for each machined, and
|
||||||
then update systemd-ssh-proxy so that it can connect to that.
|
then update systemd-ssh-proxy so that it can connect to that.
|
||||||
|
|
||||||
* add a new ExecStart= flag that inserts the configured user's shell as first
|
|
||||||
word in the command line. (maybe use character '.'). Usecase: tool such as
|
|
||||||
run0 can use that to spawn the target user's default shell.
|
|
||||||
|
|
||||||
* introduce mntid_t, and make it 64bit, as apparently the kernel switched to
|
* introduce mntid_t, and make it 64bit, as apparently the kernel switched to
|
||||||
64bit mount ids
|
64bit mount ids
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@ set -e
|
||||||
# Exclude following paths from the Coccinelle transformations
|
# Exclude following paths from the Coccinelle transformations
|
||||||
EXCLUDED_PATHS=(
|
EXCLUDED_PATHS=(
|
||||||
"src/boot/efi/*"
|
"src/boot/efi/*"
|
||||||
"src/shared/linux/*"
|
"src/basic/include/linux/*"
|
||||||
"src/basic/linux/*"
|
|
||||||
# Symlinked to test-bus-vtable-cc.cc, which causes issues with the IN_SET macro
|
# Symlinked to test-bus-vtable-cc.cc, which causes issues with the IN_SET macro
|
||||||
"src/libsystemd/sd-bus/test-bus-vtable.c"
|
"src/libsystemd/sd-bus/test-bus-vtable.c"
|
||||||
"src/libsystemd/sd-journal/lookup3.c"
|
"src/libsystemd/sd-journal/lookup3.c"
|
||||||
|
|
|
@ -383,6 +383,7 @@ evdev:name:gpio-keys:phys:gpio-keys/input0:ev:3:dmi:bvn*:bvr*:bd*:svncube:pni1-T
|
||||||
###########################################################
|
###########################################################
|
||||||
|
|
||||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*:*
|
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*:*
|
||||||
|
KEYBOARD_KEY_68=prog2 # G-Mode (Dell-specific)
|
||||||
KEYBOARD_KEY_81=playpause # Play/Pause
|
KEYBOARD_KEY_81=playpause # Play/Pause
|
||||||
KEYBOARD_KEY_82=stopcd # Stop
|
KEYBOARD_KEY_82=stopcd # Stop
|
||||||
KEYBOARD_KEY_83=previoussong # Previous song
|
KEYBOARD_KEY_83=previoussong # Previous song
|
||||||
|
|
21
man/run0.xml
21
man/run0.xml
|
@ -167,6 +167,18 @@
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--login-environment</option></term>
|
||||||
|
<term><option>-i</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Invokes the target user's login shell and runs the specified command (if any) via it.
|
||||||
|
If <option>-D/--chdir=</option> is not specified, additionally switch to the target user's home directory
|
||||||
|
even for the root user.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v258"/>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--setenv=<replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
<term><option>--setenv=<replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||||
|
|
||||||
|
@ -290,9 +302,12 @@
|
||||||
|
|
||||||
<para>All command line arguments after the first non-option argument become part of the command line of
|
<para>All command line arguments after the first non-option argument become part of the command line of
|
||||||
the launched process. If no command line is specified an interactive shell is invoked. The shell to
|
the launched process. If no command line is specified an interactive shell is invoked. The shell to
|
||||||
invoke may be controlled via <option>--setenv=SHELL=…</option> and currently defaults to the
|
invoke may be controlled via <option>-i/--login-environment</option> - when specified the target user's shell
|
||||||
<emphasis>originating user's</emphasis> shell (i.e. not the target user's!) if operating locally, or
|
is used - or <option>--setenv=SHELL=…</option>. By default, the <emphasis>originating user's</emphasis> shell
|
||||||
<filename>/bin/sh</filename> when operating with <option>--machine=</option>.</para>
|
is executed if operating locally, or <filename>/bin/sh</filename> when operating with <option>--machine=</option>.</para>
|
||||||
|
|
||||||
|
<para>Note that unlike <command>sudo</command>, <command>run0</command> always spawns shells with login shell
|
||||||
|
semantics, regardless of <option>-i</option>.</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
Host unix/* vsock/* vsock-mux/*
|
Host unix/* unix,* vsock/* vsock,* vsock-mux/* vsock-mux,*
|
||||||
ProxyCommand /usr/lib/systemd/systemd-ssh-proxy %h %p
|
ProxyCommand /usr/lib/systemd/systemd-ssh-proxy %h %p
|
||||||
ProxyUseFdpass yes
|
ProxyUseFdpass yes
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
@ -46,7 +46,7 @@ Host unix/* vsock/* vsock-mux/*
|
||||||
configuration fragment like the following:</para>
|
configuration fragment like the following:</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
Host unix/* vsock/* vsock-mux/*
|
Host unix/* unix,* vsock/* vsock,* vsock-mux/* vsock-mux,*
|
||||||
ProxyCommand /usr/lib/systemd/systemd-ssh-proxy %h %p
|
ProxyCommand /usr/lib/systemd/systemd-ssh-proxy %h %p
|
||||||
ProxyUseFdpass yes
|
ProxyUseFdpass yes
|
||||||
CheckHostIP no
|
CheckHostIP no
|
||||||
|
@ -69,7 +69,9 @@ Host .host
|
||||||
direct <constant>AF_VSOCK</constant> communication between the host and guests, and provide their own
|
direct <constant>AF_VSOCK</constant> communication between the host and guests, and provide their own
|
||||||
multiplexer over <constant>AF_UNIX</constant> sockets. See
|
multiplexer over <constant>AF_UNIX</constant> sockets. See
|
||||||
<ulink url="https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/docs/vsock.md">cloud-hypervisor VSOCK support</ulink>
|
<ulink url="https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/docs/vsock.md">cloud-hypervisor VSOCK support</ulink>
|
||||||
and <ulink url="https://github.com/firecracker-microvm/firecracker/blob/main/docs/vsock.md">Using the Firecracker Virtio-vsock Device</ulink>.</para>
|
and <ulink url="https://github.com/firecracker-microvm/firecracker/blob/main/docs/vsock.md">Using the Firecracker Virtio-vsock Device</ulink>.
|
||||||
|
Note that <literal>,</literal> can be used as a separator instead of <literal>/</literal> to be
|
||||||
|
compatible with tools like <literal>scp</literal> and <literal>rsync</literal>.</para>
|
||||||
|
|
||||||
<para>Moreover, connecting to <literal>.host</literal> will connect to the local host via SSH, without
|
<para>Moreover, connecting to <literal>.host</literal> will connect to the local host via SSH, without
|
||||||
involving networking.</para>
|
involving networking.</para>
|
||||||
|
@ -113,6 +115,12 @@ Host .host
|
||||||
|
|
||||||
<programlisting>ssh unix/run/ssh-unix-local/socket</programlisting>
|
<programlisting>ssh unix/run/ssh-unix-local/socket</programlisting>
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>Copy local 'foo' file to a local VM with CID 1348</title>
|
||||||
|
|
||||||
|
<programlisting>scp foo vsock,1348:</programlisting>
|
||||||
|
</example>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|
|
@ -1397,7 +1397,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>@</literal></entry>
|
<entry><literal>@</literal></entry>
|
||||||
<entry>If the executable path is prefixed with <literal>@</literal>, the second specified token will be passed as <constant>argv[0]</constant> to the executed process (instead of the actual filename), followed by the further arguments specified.</entry>
|
<entry>If the executable path is prefixed with <literal>@</literal>, the second specified token will be passed as <constant>argv[0]</constant> to the executed process (instead of the actual filename), followed by the further arguments specified, unless <literal>|</literal> is also specified, in which case it enables login shell semantics for the shell spawned by prefixing <literal>-</literal> to <constant>argv[0]</constant>.</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
|
@ -1420,14 +1420,19 @@
|
||||||
|
|
||||||
<entry>Similar to the <literal>+</literal> character discussed above this permits invoking command lines with elevated privileges. However, unlike <literal>+</literal> the <literal>!</literal> character exclusively alters the effect of <varname>User=</varname>, <varname>Group=</varname> and <varname>SupplementaryGroups=</varname>, i.e. only the stanzas that affect user and group credentials. Note that this setting may be combined with <varname>DynamicUser=</varname>, in which case a dynamic user/group pair is allocated before the command is invoked, but credential changing is left to the executed process itself.</entry>
|
<entry>Similar to the <literal>+</literal> character discussed above this permits invoking command lines with elevated privileges. However, unlike <literal>+</literal> the <literal>!</literal> character exclusively alters the effect of <varname>User=</varname>, <varname>Group=</varname> and <varname>SupplementaryGroups=</varname>, i.e. only the stanzas that affect user and group credentials. Note that this setting may be combined with <varname>DynamicUser=</varname>, in which case a dynamic user/group pair is allocated before the command is invoked, but credential changing is left to the executed process itself.</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal>|</literal></entry>
|
||||||
|
|
||||||
|
<entry>If <literal>|</literal> is specified standalone as executable path, invoke the user's default shell. If specified as a prefix, use the shell (<literal>-c</literal>) to spawn the executable. When <literal>@</literal> is used in conjunction, <constant>argv[0]</constant> of shell will be prefixed with <literal>-</literal> to enable login shell semantics.</entry>
|
||||||
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<para><literal>@</literal>, <literal>-</literal>, <literal>:</literal>, and one of
|
<para><literal>@</literal>, <literal>|</literal>, <literal>-</literal>, <literal>:</literal>, and one of
|
||||||
<literal>+</literal>/<literal>!</literal>/<literal>!!</literal> may be used together and they can appear in any
|
<literal>+</literal>/<literal>!</literal> may be used together and they can appear in any order.
|
||||||
order. However, only one of <literal>+</literal>, <literal>!</literal>, <literal>!!</literal> may be used at a
|
However, <literal>+</literal> and <literal>!</literal> may not be specified at the same time.</para>
|
||||||
time.</para>
|
|
||||||
|
|
||||||
<para>For each command, the first argument must be either an absolute path to an executable or a simple
|
<para>For each command, the first argument must be either an absolute path to an executable or a simple
|
||||||
file name without any slashes. If the command is not a full (absolute) path, it will be resolved to a
|
file name without any slashes. If the command is not a full (absolute) path, it will be resolved to a
|
||||||
|
@ -1490,11 +1495,6 @@ ExecStart=/bin/echo $ONE $TWO $THREE</programlisting>
|
||||||
includes e.g. <varname>$USER</varname>, but not
|
includes e.g. <varname>$USER</varname>, but not
|
||||||
<varname>$TERM</varname>).</para>
|
<varname>$TERM</varname>).</para>
|
||||||
|
|
||||||
<para>Note that shell command lines are not directly supported. If
|
|
||||||
shell command lines are to be used, they need to be passed
|
|
||||||
explicitly to a shell implementation of some kind. Example:</para>
|
|
||||||
<programlisting>ExecStart=sh -c 'dmesg | tac'</programlisting>
|
|
||||||
|
|
||||||
<para>Example:</para>
|
<para>Example:</para>
|
||||||
|
|
||||||
<programlisting>ExecStart=echo one
|
<programlisting>ExecStart=echo one
|
||||||
|
|
11
meson.build
11
meson.build
|
@ -2053,11 +2053,18 @@ boot_stubs = []
|
||||||
|
|
||||||
build_dir_include = include_directories('.')
|
build_dir_include = include_directories('.')
|
||||||
|
|
||||||
basic_includes = include_directories(
|
basic_includes = [
|
||||||
|
include_directories(
|
||||||
'src/basic',
|
'src/basic',
|
||||||
'src/fundamental',
|
'src/fundamental',
|
||||||
'src/systemd',
|
'src/systemd',
|
||||||
'.')
|
'.',
|
||||||
|
),
|
||||||
|
include_directories(
|
||||||
|
'src/basic/include',
|
||||||
|
is_system : true,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
libsystemd_includes = [basic_includes, include_directories(
|
libsystemd_includes = [basic_includes, include_directories(
|
||||||
'src/libsystemd/sd-bus',
|
'src/libsystemd/sd-bus',
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "ansi-color.h"
|
#include "ansi-color.h"
|
||||||
#include "battery-util.h"
|
#include "battery-util.h"
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
|
#include "log.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "analyze-compare-versions.h"
|
#include "analyze-compare-versions.h"
|
||||||
#include "compare-operator.h"
|
#include "compare-operator.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "sd-bus.h"
|
#include "sd-bus.h"
|
||||||
|
|
||||||
|
#include "memory-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
#include "unit-def.h"
|
#include "unit-def.h"
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "memory-util.h"
|
|
||||||
|
|
||||||
void* memdup(const void *p, size_t l) {
|
void* memdup(const void *p, size_t l) {
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "assert-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "memory-util.h"
|
||||||
|
|
||||||
#if HAS_FEATURE_MEMORY_SANITIZER
|
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||||
# include <sanitizer/msan_interface.h>
|
# include <sanitizer/msan_interface.h>
|
||||||
|
@ -266,5 +268,3 @@ _alloc_(2) static inline void *realloc0(void *p, size_t new_size) {
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "memory-util.h"
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "argv-util.h"
|
#include "argv-util.h"
|
||||||
#include "capability-util.h"
|
#include "capability-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "missing_sched.h"
|
#include "missing_sched.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "assert-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
extern int saved_argc;
|
extern int saved_argc;
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "assert-util.h"
|
||||||
|
#include "errno-util.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
static bool assert_return_is_critical = BUILD_MODE_DEVELOPER;
|
||||||
|
|
||||||
|
/* Akin to glibc's __abort_msg; which is private and we hence cannot
|
||||||
|
* use here. */
|
||||||
|
static char *log_abort_msg = NULL;
|
||||||
|
|
||||||
|
void log_set_assert_return_is_critical(bool b) {
|
||||||
|
assert_return_is_critical = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool log_get_assert_return_is_critical(void) {
|
||||||
|
return assert_return_is_critical;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_assert(
|
||||||
|
int level,
|
||||||
|
const char *text,
|
||||||
|
const char *file,
|
||||||
|
int line,
|
||||||
|
const char *func,
|
||||||
|
const char *format) {
|
||||||
|
|
||||||
|
static char buffer[LINE_MAX];
|
||||||
|
|
||||||
|
if (_likely_(LOG_PRI(level) > log_get_max_level()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DISABLE_WARNING_FORMAT_NONLITERAL;
|
||||||
|
(void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
|
||||||
|
REENABLE_WARNING;
|
||||||
|
|
||||||
|
log_abort_msg = buffer;
|
||||||
|
|
||||||
|
log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
|
||||||
|
log_assert(LOG_CRIT, text, file, line, func,
|
||||||
|
"Assertion '%s' failed at %s:%u, function %s(). Aborting.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
_noreturn_ void log_assert_failed_unreachable(const char *file, int line, const char *func) {
|
||||||
|
log_assert(LOG_CRIT, "Code should not be reached", file, line, func,
|
||||||
|
"%s at %s:%u, function %s(). Aborting. 💥");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
|
||||||
|
|
||||||
|
if (assert_return_is_critical)
|
||||||
|
log_assert_failed(text, file, line, func);
|
||||||
|
|
||||||
|
PROTECT_ERRNO;
|
||||||
|
log_assert(LOG_DEBUG, text, file, line, func,
|
||||||
|
"Assertion '%s' failed at %s:%u, function %s(), ignoring.");
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "assert-fundamental.h"
|
||||||
|
#include "macro.h"
|
||||||
|
|
||||||
|
/* Logging for various assertions */
|
||||||
|
|
||||||
|
void log_set_assert_return_is_critical(bool b);
|
||||||
|
bool log_get_assert_return_is_critical(void) _pure_;
|
||||||
|
|
||||||
|
_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func);
|
||||||
|
_noreturn_ void log_assert_failed_unreachable(const char *file, int line, const char *func);
|
||||||
|
void log_assert_failed_return(const char *text, const char *file, int line, const char *func);
|
||||||
|
|
||||||
|
#ifdef __COVERITY__
|
||||||
|
|
||||||
|
/* Use special definitions of assertion macros in order to prevent
|
||||||
|
* false positives of ASSERT_SIDE_EFFECT on Coverity static analyzer
|
||||||
|
* for uses of assert_se() and assert_return().
|
||||||
|
*
|
||||||
|
* These definitions make expression go through a (trivial) function
|
||||||
|
* call to ensure they are not discarded. Also use ! or !! to ensure
|
||||||
|
* the boolean expressions are seen as such.
|
||||||
|
*
|
||||||
|
* This technique has been described and recommended in:
|
||||||
|
* https://community.synopsys.com/s/question/0D534000046Yuzb/suppressing-assertsideeffect-for-functions-that-allow-for-sideeffects
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern void __coverity_panic__(void);
|
||||||
|
|
||||||
|
static inline void __coverity_check__(int condition) {
|
||||||
|
if (!condition)
|
||||||
|
__coverity_panic__();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __coverity_check_and_return__(int condition) {
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define assert_message_se(expr, message) __coverity_check__(!!(expr))
|
||||||
|
|
||||||
|
#define assert_log(expr, message) __coverity_check_and_return__(!!(expr))
|
||||||
|
|
||||||
|
#else /* ! __COVERITY__ */
|
||||||
|
|
||||||
|
#define assert_message_se(expr, message) \
|
||||||
|
do { \
|
||||||
|
if (_unlikely_(!(expr))) \
|
||||||
|
log_assert_failed(message, PROJECT_FILE, __LINE__, __func__); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define assert_log(expr, message) ((_likely_(expr)) \
|
||||||
|
? (true) \
|
||||||
|
: (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false))
|
||||||
|
|
||||||
|
#endif /* __COVERITY__ */
|
||||||
|
|
||||||
|
#define assert_se(expr) assert_message_se(expr, #expr)
|
||||||
|
|
||||||
|
/* We override the glibc assert() here. */
|
||||||
|
#undef assert
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define assert(expr) ({ if (!(expr)) __builtin_unreachable(); })
|
||||||
|
#else
|
||||||
|
#define assert(expr) assert_message_se(expr, #expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define assert_not_reached() \
|
||||||
|
log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __func__)
|
||||||
|
|
||||||
|
#define assert_return(expr, r) \
|
||||||
|
do { \
|
||||||
|
if (!assert_log(expr, #expr)) \
|
||||||
|
return (r); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define assert_return_errno(expr, r, err) \
|
||||||
|
do { \
|
||||||
|
if (!assert_log(expr, #expr)) { \
|
||||||
|
errno = err; \
|
||||||
|
return (r); \
|
||||||
|
} \
|
||||||
|
} while (false)
|
|
@ -6,6 +6,7 @@
|
||||||
#include "ansi-color.h"
|
#include "ansi-color.h"
|
||||||
#include "build.h"
|
#include "build.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "capability-util.h"
|
#include "capability-util.h"
|
||||||
#include "cap-list.h"
|
#include "cap-list.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "pidref.h"
|
#include "pidref.h"
|
||||||
|
#include "process-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "sparse-endian.h"
|
#include "sparse-endian.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
#include "log.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include "dlfcn-util.h"
|
#include "dlfcn-util.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
static int dlsym_many_or_warnv(void *dl, int log_level, va_list ap) {
|
static int dlsym_many_or_warnv(void *dl, int log_level, va_list ap) {
|
||||||
void (**fn)(void);
|
void (**fn)(void);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include "assert-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
static inline void* safe_dlclose(void *dl) {
|
static inline void* safe_dlclose(void *dl) {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "missing_fs.h"
|
#include "missing_fs.h"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "tmpfile-util.h"
|
#include "tmpfile-util.h"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
@ -884,9 +885,12 @@ int replace_env_argv(
|
||||||
char ***ret_bad_variables) {
|
char ***ret_bad_variables) {
|
||||||
|
|
||||||
_cleanup_strv_free_ char **n = NULL, **unset_variables = NULL, **bad_variables = NULL;
|
_cleanup_strv_free_ char **n = NULL, **unset_variables = NULL, **bad_variables = NULL;
|
||||||
size_t k = 0, l = 0;
|
size_t k = 0, l;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(!strv_isempty(argv));
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
l = strv_length(argv);
|
l = strv_length(argv);
|
||||||
|
|
||||||
n = new(char*, l+1);
|
n = new(char*, l+1);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "assert-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
/* strerror(3) says that glibc uses a maximum length of 1024 bytes. */
|
/* strerror(3) says that glibc uses a maximum length of 1024 bytes. */
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "ether-addr-util.h"
|
#include "ether-addr-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "missing_fcntl.h"
|
#include "missing_fcntl.h"
|
||||||
#include "missing_fs.h"
|
#include "missing_fs.h"
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "memory-util.h"
|
||||||
#include "missing_fcntl.h"
|
#include "missing_fcntl.h"
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include "format-ifname.h"
|
#include "format-ifname.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "stdio-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
assert_cc(STRLEN("%") + DECIMAL_STR_MAX(int) <= IF_NAMESIZE);
|
assert_cc(STRLEN("%") + DECIMAL_STR_MAX(int) <= IF_NAMESIZE);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "gcrypt-util.h"
|
#include "gcrypt-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
static void *gcrypt_dl = NULL;
|
static void *gcrypt_dl = NULL;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "dlfcn-util.h"
|
#include "dlfcn-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "memory-util.h"
|
||||||
|
|
||||||
extern DLSYM_PROTOTYPE(gcry_md_close);
|
extern DLSYM_PROTOTYPE(gcry_md_close);
|
||||||
extern DLSYM_PROTOTYPE(gcry_md_copy);
|
extern DLSYM_PROTOTYPE(gcry_md_copy);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "dirent-util.h"
|
#include "dirent-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "glob-util.h"
|
#include "glob-util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
#include "log.h"
|
||||||
#include "logarithm.h"
|
#include "logarithm.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
|
@ -912,24 +913,20 @@ static void hashmap_free_no_clear(HashmapBase *h) {
|
||||||
free(h);
|
free(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
|
HashmapBase* _hashmap_free(HashmapBase *h) {
|
||||||
if (h) {
|
if (h) {
|
||||||
_hashmap_clear(h, default_free_key, default_free_value);
|
_hashmap_clear(h);
|
||||||
hashmap_free_no_clear(h);
|
hashmap_free_no_clear(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
|
void _hashmap_clear(HashmapBase *h) {
|
||||||
free_func_t free_key, free_value;
|
|
||||||
if (!h)
|
if (!h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
free_key = h->hash_ops->free_key ?: default_free_key;
|
if (h->hash_ops->free_key || h->hash_ops->free_value) {
|
||||||
free_value = h->hash_ops->free_value ?: default_free_value;
|
|
||||||
|
|
||||||
if (free_key || free_value) {
|
|
||||||
|
|
||||||
/* If destructor calls are defined, let's destroy things defensively: let's take the item out of the
|
/* If destructor calls are defined, let's destroy things defensively: let's take the item out of the
|
||||||
* hash table, and only then call the destructor functions. If these destructors then try to unregister
|
* hash table, and only then call the destructor functions. If these destructors then try to unregister
|
||||||
|
@ -941,11 +938,11 @@ void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t de
|
||||||
|
|
||||||
v = _hashmap_first_key_and_value(h, true, &k);
|
v = _hashmap_first_key_and_value(h, true, &k);
|
||||||
|
|
||||||
if (free_key)
|
if (h->hash_ops->free_key)
|
||||||
free_key(k);
|
h->hash_ops->free_key(k);
|
||||||
|
|
||||||
if (free_value)
|
if (h->hash_ops->free_value)
|
||||||
free_value(v);
|
h->hash_ops->free_value(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1780,7 +1777,7 @@ HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return _hashmap_free(copy, NULL, NULL);
|
return _hashmap_free(copy);
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,12 +93,12 @@ OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DE
|
||||||
#define ordered_hashmap_free_and_replace(a, b) \
|
#define ordered_hashmap_free_and_replace(a, b) \
|
||||||
free_and_replace_full(a, b, ordered_hashmap_free)
|
free_and_replace_full(a, b, ordered_hashmap_free)
|
||||||
|
|
||||||
HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
|
HashmapBase* _hashmap_free(HashmapBase *h);
|
||||||
static inline Hashmap* hashmap_free(Hashmap *h) {
|
static inline Hashmap* hashmap_free(Hashmap *h) {
|
||||||
return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
|
return (void*) _hashmap_free(HASHMAP_BASE(h));
|
||||||
}
|
}
|
||||||
static inline OrderedHashmap* ordered_hashmap_free(OrderedHashmap *h) {
|
static inline OrderedHashmap* ordered_hashmap_free(OrderedHashmap *h) {
|
||||||
return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
|
return (void*) _hashmap_free(HASHMAP_BASE(h));
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratedCache* iterated_cache_free(IteratedCache *cache);
|
IteratedCache* iterated_cache_free(IteratedCache *cache);
|
||||||
|
@ -266,12 +266,12 @@ static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void
|
||||||
return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
|
return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
|
void _hashmap_clear(HashmapBase *h);
|
||||||
static inline void hashmap_clear(Hashmap *h) {
|
static inline void hashmap_clear(Hashmap *h) {
|
||||||
_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
|
_hashmap_clear(HASHMAP_BASE(h));
|
||||||
}
|
}
|
||||||
static inline void ordered_hashmap_clear(OrderedHashmap *h) {
|
static inline void ordered_hashmap_clear(OrderedHashmap *h) {
|
||||||
_hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
|
_hashmap_clear(HASHMAP_BASE(h));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -331,27 +331,6 @@ static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
|
||||||
return _hashmap_first_key(HASHMAP_BASE(h), false);
|
return _hashmap_first_key(HASHMAP_BASE(h), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define hashmap_clear_with_destructor(h, f) \
|
|
||||||
({ \
|
|
||||||
Hashmap *_h = (h); \
|
|
||||||
void *_item; \
|
|
||||||
while ((_item = hashmap_steal_first(_h))) \
|
|
||||||
f(_item); \
|
|
||||||
_h; \
|
|
||||||
})
|
|
||||||
#define hashmap_free_with_destructor(h, f) \
|
|
||||||
hashmap_free(hashmap_clear_with_destructor(h, f))
|
|
||||||
#define ordered_hashmap_clear_with_destructor(h, f) \
|
|
||||||
({ \
|
|
||||||
OrderedHashmap *_h = (h); \
|
|
||||||
void *_item; \
|
|
||||||
while ((_item = ordered_hashmap_steal_first(_h))) \
|
|
||||||
f(_item); \
|
|
||||||
_h; \
|
|
||||||
})
|
|
||||||
#define ordered_hashmap_free_with_destructor(h, f) \
|
|
||||||
ordered_hashmap_free(ordered_hashmap_clear_with_destructor(h, f))
|
|
||||||
|
|
||||||
/* no hashmap_next */
|
/* no hashmap_next */
|
||||||
void* ordered_hashmap_next(OrderedHashmap *h, const void *key);
|
void* ordered_hashmap_next(OrderedHashmap *h, const void *key);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "env-file.h"
|
#include "env-file.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
|
#include "log.h"
|
||||||
#include "os-util.h"
|
#include "os-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue