Compare commits
12 Commits
48625dc437
...
23b13549fa
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | 23b13549fa | |
Zbigniew Jędrzejewski-Szmek | a1989bd84b | |
Zbigniew Jędrzejewski-Szmek | 32c3a623ce | |
Zbigniew Jędrzejewski-Szmek | 158b28313f | |
Zbigniew Jędrzejewski-Szmek | f1b823596f | |
Lennart Poettering | ddfde737b5 | |
Michal Sekletár | e1951c16a8 | |
Jonathan Lebon | e921ebb57e | |
Zbigniew Jędrzejewski-Szmek | 6bdcb72086 | |
Zbigniew Jędrzejewski-Szmek | d5816b6138 | |
Zbigniew Jędrzejewski-Szmek | c9e9a57fce | |
Zbigniew Jędrzejewski-Szmek | 9337945233 |
|
@ -41,7 +41,6 @@
|
|||
<filename>hybrid-sleep.target</filename>,
|
||||
<filename>suspend-then-hibernate.target</filename>,
|
||||
<filename>initrd.target</filename>,
|
||||
<filename>initrd-cryptsetup.target</filename>,
|
||||
<filename>initrd-fs.target</filename>,
|
||||
<filename>initrd-root-device.target</filename>,
|
||||
<filename>initrd-root-fs.target</filename>,
|
||||
|
@ -183,10 +182,8 @@
|
|||
<varlistentry>
|
||||
<term><filename>cryptsetup.target</filename></term>
|
||||
<listitem>
|
||||
<para>A target that pulls in setup services for local encrypted block devices.
|
||||
See <filename>remote-cryptsetup.target</filename> below for the equivalent target for remote
|
||||
volumes, and <filename>initrd-cryptsetup.target</filename> below for the equivalent target in the
|
||||
initrd.</para>
|
||||
<para>A target that pulls in setup services for all
|
||||
encrypted block devices.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
@ -355,20 +352,12 @@
|
|||
<varlistentry>
|
||||
<term><filename>initrd.target</filename></term>
|
||||
<listitem>
|
||||
<para>This is the default target in the initrd, similar to <filename>default.target</filename>
|
||||
<para>This is the default target in the initramfs, similar to <filename>default.target</filename>
|
||||
in the main system. It is used to mount the real root and transition to it. See
|
||||
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
more discussion.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>initrd-cryptsetup.target</filename></term>
|
||||
<listitem>
|
||||
<para>A target that pulls in setup services for all encrypted block devices. See
|
||||
<filename>cryptsetup.target</filename> and <filename>remote-cryptsetup.target</filename> for the
|
||||
equivalent targets in the real root.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>initrd-fs.target</filename></term>
|
||||
<listitem>
|
||||
|
@ -560,9 +549,7 @@
|
|||
<para>Similar to <filename>cryptsetup.target</filename>, but for encrypted
|
||||
devices which are accessed over the network. It is used for
|
||||
<citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
entries marked with <option>_netdev</option>.
|
||||
See <filename>cryptsetup.target</filename> for the equivalent target for local volumes, and
|
||||
<filename>initrd-cryptsetup.target</filename> for the equivalent target in the initrd.</para>
|
||||
entries marked with <option>_netdev</option>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
|
26
meson.build
26
meson.build
|
@ -1561,21 +1561,11 @@ meson_apply_m4 = find_program('tools/meson-apply-m4.sh')
|
|||
|
||||
includes = include_directories('src/basic',
|
||||
'src/boot',
|
||||
'src/core',
|
||||
'src/home',
|
||||
'src/shared',
|
||||
'src/systemd',
|
||||
'src/journal',
|
||||
'src/journal-remote',
|
||||
'src/nspawn',
|
||||
'src/resolve',
|
||||
'src/timesync',
|
||||
'src/time-wait-sync',
|
||||
'src/login',
|
||||
'src/udev',
|
||||
'src/libudev',
|
||||
'src/core',
|
||||
'src/shutdown',
|
||||
'src/xdg-autostart-generator',
|
||||
'src/libsystemd-network',
|
||||
'src/libsystemd/sd-bus',
|
||||
'src/libsystemd/sd-device',
|
||||
'src/libsystemd/sd-event',
|
||||
|
@ -1584,7 +1574,17 @@ includes = include_directories('src/basic',
|
|||
'src/libsystemd/sd-netlink',
|
||||
'src/libsystemd/sd-network',
|
||||
'src/libsystemd/sd-resolve',
|
||||
'src/libsystemd-network',
|
||||
'src/libudev',
|
||||
'src/login',
|
||||
'src/nspawn',
|
||||
'src/resolve',
|
||||
'src/shared',
|
||||
'src/shutdown',
|
||||
'src/systemd',
|
||||
'src/time-wait-sync',
|
||||
'src/timesync',
|
||||
'src/udev',
|
||||
'src/xdg-autostart-generator',
|
||||
'.')
|
||||
|
||||
add_project_arguments('-include', 'config.h', language : 'c')
|
||||
|
|
|
@ -455,16 +455,10 @@ static int create_disk(
|
|||
}
|
||||
}
|
||||
|
||||
const char *target;
|
||||
if (in_initrd())
|
||||
target = "initrd-cryptsetup.target";
|
||||
else if (netdev)
|
||||
target = "remote-cryptsetup.target";
|
||||
else
|
||||
target = "cryptsetup.target";
|
||||
|
||||
if (!nofail)
|
||||
fprintf(f, "Before=%s\n", target);
|
||||
fprintf(f,
|
||||
"Before=%s\n",
|
||||
netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
|
||||
|
||||
if (password && !keydev) {
|
||||
r = print_dependencies(f, password);
|
||||
|
@ -527,7 +521,8 @@ static int create_disk(
|
|||
return log_error_errno(r, "Failed to write unit file %s: %m", n);
|
||||
|
||||
if (!noauto) {
|
||||
r = generator_add_symlink(arg_dest, target,
|
||||
r = generator_add_symlink(arg_dest,
|
||||
netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
|
||||
nofail ? "wants" : "requires", n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#if HAVE_QRENCODE
|
||||
#include <qrencode.h>
|
||||
#include "qrcode-util.h"
|
||||
#endif
|
||||
|
||||
#include "dlfcn-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "homectl-recovery-key.h"
|
||||
#include "libcrypt-util.h"
|
||||
#include "locale-util.h"
|
||||
#include "memory-util.h"
|
||||
#include "modhex.h"
|
||||
#include "qrcode-util.h"
|
||||
#include "random-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
|
@ -140,48 +135,6 @@ static int add_secret(JsonVariant **v, const char *password) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int print_qr_code(const char *secret) {
|
||||
#if HAVE_QRENCODE
|
||||
QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
|
||||
void (*sym_QRcode_free)(QRcode *qrcode);
|
||||
_cleanup_(dlclosep) void *dl = NULL;
|
||||
QRcode* qr;
|
||||
int r;
|
||||
|
||||
/* If this is not an UTF-8 system or ANSI colors aren't supported/disabled don't print any QR
|
||||
* codes */
|
||||
if (!is_locale_utf8() || !colors_enabled())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
dl = dlopen("libqrencode.so.4", RTLD_LAZY);
|
||||
if (!dl)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"QRCODE support is not installed: %s", dlerror());
|
||||
|
||||
r = dlsym_many_and_warn(
|
||||
dl,
|
||||
LOG_DEBUG,
|
||||
&sym_QRcode_encodeString, "QRcode_encodeString",
|
||||
&sym_QRcode_free, "QRcode_free",
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
qr = sym_QRcode_encodeString(secret, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
|
||||
if (!qr)
|
||||
return -ENOMEM;
|
||||
|
||||
fprintf(stderr, "\nYou may optionally scan the recovery key off screen:\n\n");
|
||||
|
||||
write_qrcode(stderr, qr);
|
||||
|
||||
fputc('\n', stderr);
|
||||
|
||||
sym_QRcode_free(qr);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int identity_add_recovery_key(JsonVariant **v) {
|
||||
_cleanup_(erase_and_freep) char *password = NULL, *hashed = NULL;
|
||||
int r;
|
||||
|
@ -240,7 +193,7 @@ int identity_add_recovery_key(JsonVariant **v) {
|
|||
"whenever authentication is requested.\n", stderr);
|
||||
fflush(stderr);
|
||||
|
||||
print_qr_code(password);
|
||||
(void) print_qrcode(stderr, "You may optionally scan the recovery key off screen", password);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <errno.h>
|
||||
#include <qrencode.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dlfcn-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "journal-qrcode.h"
|
||||
#include "locale-util.h"
|
||||
#include "macro.h"
|
||||
#include "qrcode-util.h"
|
||||
#include "terminal-util.h"
|
||||
|
||||
int print_qr_code(
|
||||
FILE *output,
|
||||
const char *prefix_text,
|
||||
const void *seed,
|
||||
size_t seed_size,
|
||||
uint64_t start,
|
||||
uint64_t interval,
|
||||
const char *hn,
|
||||
sd_id128_t machine) {
|
||||
|
||||
QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
|
||||
void (*sym_QRcode_free)(QRcode *qrcode);
|
||||
_cleanup_(dlclosep) void *dl = NULL;
|
||||
_cleanup_free_ char *url = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
size_t url_size = 0;
|
||||
QRcode* qr;
|
||||
int r;
|
||||
|
||||
assert(seed);
|
||||
assert(seed_size > 0);
|
||||
|
||||
/* If this is not an UTF-8 system or ANSI colors aren't supported/disabled don't print any QR
|
||||
* codes */
|
||||
if (!is_locale_utf8() || !colors_enabled())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
dl = dlopen("libqrencode.so.4", RTLD_LAZY);
|
||||
if (!dl)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"QRCODE support is not installed: %s", dlerror());
|
||||
|
||||
r = dlsym_many_and_warn(
|
||||
dl,
|
||||
LOG_DEBUG,
|
||||
&sym_QRcode_encodeString, "QRcode_encodeString",
|
||||
&sym_QRcode_free, "QRcode_free",
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
f = open_memstream_unlocked(&url, &url_size);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
fputs("fss://", f);
|
||||
|
||||
for (size_t i = 0; i < seed_size; i++) {
|
||||
if (i > 0 && i % 3 == 0)
|
||||
fputc('-', f);
|
||||
fprintf(f, "%02x", ((uint8_t*) seed)[i]);
|
||||
}
|
||||
|
||||
fprintf(f, "/%"PRIx64"-%"PRIx64"?machine=" SD_ID128_FORMAT_STR,
|
||||
start,
|
||||
interval,
|
||||
SD_ID128_FORMAT_VAL(machine));
|
||||
|
||||
if (hn)
|
||||
fprintf(f, ";hostname=%s", hn);
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
f = safe_fclose(f);
|
||||
|
||||
qr = sym_QRcode_encodeString(url, 0, QR_ECLEVEL_L, QR_MODE_8, 1);
|
||||
if (!qr)
|
||||
return -ENOMEM;
|
||||
|
||||
if (prefix_text)
|
||||
fputs(prefix_text, output);
|
||||
|
||||
write_qrcode(output, qr);
|
||||
|
||||
sym_QRcode_free(qr);
|
||||
return 0;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
int print_qr_code(FILE *f, const char *prefix_text, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine);
|
|
@ -43,7 +43,6 @@
|
|||
#include "io-util.h"
|
||||
#include "journal-def.h"
|
||||
#include "journal-internal.h"
|
||||
#include "journal-qrcode.h"
|
||||
#include "journal-util.h"
|
||||
#include "journal-vacuum.h"
|
||||
#include "journal-verify.h"
|
||||
|
@ -60,6 +59,7 @@
|
|||
#include "path-util.h"
|
||||
#include "pcre2-dlopen.h"
|
||||
#include "pretty-print.h"
|
||||
#include "qrcode-util.h"
|
||||
#include "random-util.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "set.h"
|
||||
|
@ -1779,6 +1779,53 @@ static int add_syslog_identifier(sd_journal *j) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int format_journal_url(
|
||||
const void *seed,
|
||||
size_t seed_size,
|
||||
uint64_t start,
|
||||
uint64_t interval,
|
||||
const char *hn,
|
||||
sd_id128_t machine,
|
||||
bool full,
|
||||
char **ret_url) {
|
||||
_cleanup_free_ char *url = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
size_t url_size = 0;
|
||||
int r;
|
||||
|
||||
assert(seed);
|
||||
assert(seed_size > 0);
|
||||
|
||||
f = open_memstream_unlocked(&url, &url_size);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (full)
|
||||
fputs("fss://", f);
|
||||
|
||||
for (size_t i = 0; i < seed_size; i++) {
|
||||
if (i > 0 && i % 3 == 0)
|
||||
fputc('-', f);
|
||||
fprintf(f, "%02x", ((uint8_t*) seed)[i]);
|
||||
}
|
||||
|
||||
fprintf(f, "/%"PRIx64"-%"PRIx64, start, interval);
|
||||
|
||||
if (full) {
|
||||
fprintf(f, "?machine=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(machine));
|
||||
if (hn)
|
||||
fprintf(f, ";hostname=%s", hn);
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
f = safe_fclose(f);
|
||||
*ret_url = TAKE_PTR(url);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_keys(void) {
|
||||
#if HAVE_GCRYPT
|
||||
size_t mpk_size, seed_size, state_size;
|
||||
|
@ -1893,7 +1940,11 @@ static int setup_keys(void) {
|
|||
|
||||
k = mfree(k);
|
||||
|
||||
_cleanup_free_ char *hn = NULL;
|
||||
_cleanup_free_ char *hn = NULL, *key = NULL;
|
||||
|
||||
r = format_journal_url(seed, seed_size, n, arg_interval, hn, machine, false, &key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (on_tty()) {
|
||||
hn = gethostname_malloc();
|
||||
|
@ -1925,21 +1976,19 @@ static int setup_keys(void) {
|
|||
fflush(stderr);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < seed_size; i++) {
|
||||
if (i > 0 && i % 3 == 0)
|
||||
putchar('-');
|
||||
printf("%02x", ((uint8_t*) seed)[i]);
|
||||
}
|
||||
printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
|
||||
puts(key);
|
||||
|
||||
if (on_tty()) {
|
||||
fprintf(stderr, "%s", ansi_normal());
|
||||
#if HAVE_QRENCODE
|
||||
(void) print_qr_code(stderr,
|
||||
"\nTo transfer the verification key to your phone scan the QR code below:\n",
|
||||
seed, seed_size,
|
||||
n, arg_interval,
|
||||
hn, machine);
|
||||
_cleanup_free_ char *url = NULL;
|
||||
r = format_journal_url(seed, seed_size, n, arg_interval, hn, machine, true, &url);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) print_qrcode(stderr,
|
||||
"To transfer the verification key to your phone scan the QR code below",
|
||||
url);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -107,11 +107,6 @@ journalctl_sources = files('''
|
|||
pcre2-dlopen.h
|
||||
'''.split())
|
||||
|
||||
if conf.get('HAVE_QRENCODE') == 1
|
||||
journalctl_sources += files('journal-qrcode.c',
|
||||
'journal-qrcode.h')
|
||||
endif
|
||||
|
||||
install_data('journald.conf',
|
||||
install_dir : pkgsysconfdir)
|
||||
|
||||
|
|
|
@ -701,6 +701,33 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
|
|||
event_unmask_signal_data(e, d, sig);
|
||||
}
|
||||
|
||||
static void event_source_pp_prioq_reshuffle(sd_event_source *s) {
|
||||
assert(s);
|
||||
|
||||
/* Reshuffles the pending + prepare prioqs. Called whenever the dispatch order changes, i.e. when
|
||||
* they are enabled/disabled or marked pending and such. */
|
||||
|
||||
if (s->pending)
|
||||
prioq_reshuffle(s->event->pending, s, &s->pending_index);
|
||||
|
||||
if (s->prepare)
|
||||
prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
|
||||
}
|
||||
|
||||
static void event_source_time_prioq_reshuffle(sd_event_source *s) {
|
||||
struct clock_data *d;
|
||||
|
||||
assert(s);
|
||||
assert(EVENT_SOURCE_IS_TIME(s->type));
|
||||
|
||||
/* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy,
|
||||
* pending, enable state. Makes sure the two prioq's are ordered properly again. */
|
||||
assert_se(d = event_get_clock_data(s->event, s->type));
|
||||
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
}
|
||||
|
||||
static void source_disconnect(sd_event_source *s) {
|
||||
sd_event *event;
|
||||
|
||||
|
@ -907,16 +934,8 @@ static int source_set_pending(sd_event_source *s, bool b) {
|
|||
} else
|
||||
assert_se(prioq_remove(s->event->pending, s, &s->pending_index));
|
||||
|
||||
if (EVENT_SOURCE_IS_TIME(s->type)) {
|
||||
struct clock_data *d;
|
||||
|
||||
d = event_get_clock_data(s->event, s->type);
|
||||
assert(d);
|
||||
|
||||
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
}
|
||||
if (EVENT_SOURCE_IS_TIME(s->type))
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
|
||||
if (s->type == SOURCE_SIGNAL && !b) {
|
||||
struct signal_data *d;
|
||||
|
@ -2207,11 +2226,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
|
|||
} else
|
||||
s->priority = priority;
|
||||
|
||||
if (s->pending)
|
||||
prioq_reshuffle(s->event->pending, s, &s->pending_index);
|
||||
|
||||
if (s->prepare)
|
||||
prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
|
||||
event_source_pp_prioq_reshuffle(s);
|
||||
|
||||
if (s->type == SOURCE_EXIT)
|
||||
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
|
||||
|
@ -2237,6 +2252,152 @@ _public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
|
|||
return s->enabled != SD_EVENT_OFF;
|
||||
}
|
||||
|
||||
static int event_source_disable(sd_event_source *s) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->enabled != SD_EVENT_OFF);
|
||||
|
||||
/* Unset the pending flag when this event source is disabled */
|
||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
r = source_set_pending(s, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
case SOURCE_IO:
|
||||
source_io_unregister(s);
|
||||
break;
|
||||
|
||||
case SOURCE_TIME_REALTIME:
|
||||
case SOURCE_TIME_BOOTTIME:
|
||||
case SOURCE_TIME_MONOTONIC:
|
||||
case SOURCE_TIME_REALTIME_ALARM:
|
||||
case SOURCE_TIME_BOOTTIME_ALARM:
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
break;
|
||||
|
||||
case SOURCE_SIGNAL:
|
||||
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
|
||||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
assert(s->event->n_enabled_child_sources > 0);
|
||||
s->event->n_enabled_child_sources--;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
source_child_pidfd_unregister(s);
|
||||
else
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
break;
|
||||
|
||||
case SOURCE_EXIT:
|
||||
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
|
||||
break;
|
||||
|
||||
case SOURCE_DEFER:
|
||||
case SOURCE_POST:
|
||||
case SOURCE_INOTIFY:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Wut? I shouldn't exist.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int event_source_enable(sd_event_source *s, int m) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(IN_SET(m, SD_EVENT_ON, SD_EVENT_ONESHOT));
|
||||
assert(s->enabled == SD_EVENT_OFF);
|
||||
|
||||
/* Unset the pending flag when this event source is enabled */
|
||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
r = source_set_pending(s, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
s->enabled = m;
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
case SOURCE_IO:
|
||||
r = source_io_register(s, m, s->io.events);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
return r;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_TIME_REALTIME:
|
||||
case SOURCE_TIME_BOOTTIME:
|
||||
case SOURCE_TIME_MONOTONIC:
|
||||
case SOURCE_TIME_REALTIME_ALARM:
|
||||
case SOURCE_TIME_BOOTTIME_ALARM:
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
break;
|
||||
|
||||
case SOURCE_SIGNAL:
|
||||
r = event_make_signal_data(s->event, s->signal.sig, NULL);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
|
||||
return r;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
s->event->n_enabled_child_sources++;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* yes, we have pidfd */
|
||||
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
s->event->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* no pidfd, or something other to watch for than WEXITED */
|
||||
|
||||
r = event_make_signal_data(s->event, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
s->event->n_enabled_child_sources--;
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_EXIT:
|
||||
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
|
||||
break;
|
||||
|
||||
case SOURCE_DEFER:
|
||||
case SOURCE_POST:
|
||||
case SOURCE_INOTIFY:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Wut? I shouldn't exist.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||
int r;
|
||||
|
||||
|
@ -2244,182 +2405,29 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
|||
assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
|
||||
/* If we are dead anyway, we are fine with turning off
|
||||
* sources, but everything else needs to fail. */
|
||||
/* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */
|
||||
if (s->event->state == SD_EVENT_FINISHED)
|
||||
return m == SD_EVENT_OFF ? 0 : -ESTALE;
|
||||
|
||||
if (s->enabled == m)
|
||||
if (s->enabled == m) /* No change? */
|
||||
return 0;
|
||||
|
||||
if (m == SD_EVENT_OFF) {
|
||||
|
||||
/* Unset the pending flag when this event source is disabled */
|
||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
r = source_set_pending(s, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (m == SD_EVENT_OFF)
|
||||
r = event_source_disable(s);
|
||||
else {
|
||||
if (s->enabled != SD_EVENT_OFF) {
|
||||
/* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the
|
||||
* event source is already enabled after all. */
|
||||
s->enabled = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
case SOURCE_IO:
|
||||
source_io_unregister(s);
|
||||
s->enabled = m;
|
||||
break;
|
||||
|
||||
case SOURCE_TIME_REALTIME:
|
||||
case SOURCE_TIME_BOOTTIME:
|
||||
case SOURCE_TIME_MONOTONIC:
|
||||
case SOURCE_TIME_REALTIME_ALARM:
|
||||
case SOURCE_TIME_BOOTTIME_ALARM: {
|
||||
struct clock_data *d;
|
||||
|
||||
s->enabled = m;
|
||||
d = event_get_clock_data(s->event, s->type);
|
||||
assert(d);
|
||||
|
||||
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SOURCE_SIGNAL:
|
||||
s->enabled = m;
|
||||
|
||||
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
|
||||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
s->enabled = m;
|
||||
|
||||
assert(s->event->n_enabled_child_sources > 0);
|
||||
s->event->n_enabled_child_sources--;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
source_child_pidfd_unregister(s);
|
||||
else
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_EXIT:
|
||||
s->enabled = m;
|
||||
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
|
||||
break;
|
||||
|
||||
case SOURCE_DEFER:
|
||||
case SOURCE_POST:
|
||||
case SOURCE_INOTIFY:
|
||||
s->enabled = m;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Wut? I shouldn't exist.");
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Unset the pending flag when this event source is enabled */
|
||||
if (s->enabled == SD_EVENT_OFF && !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||
r = source_set_pending(s, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
case SOURCE_IO:
|
||||
r = source_io_register(s, m, s->io.events);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
s->enabled = m;
|
||||
break;
|
||||
|
||||
case SOURCE_TIME_REALTIME:
|
||||
case SOURCE_TIME_BOOTTIME:
|
||||
case SOURCE_TIME_MONOTONIC:
|
||||
case SOURCE_TIME_REALTIME_ALARM:
|
||||
case SOURCE_TIME_BOOTTIME_ALARM: {
|
||||
struct clock_data *d;
|
||||
|
||||
s->enabled = m;
|
||||
d = event_get_clock_data(s->event, s->type);
|
||||
assert(d);
|
||||
|
||||
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SOURCE_SIGNAL:
|
||||
|
||||
s->enabled = m;
|
||||
|
||||
r = event_make_signal_data(s->event, s->signal.sig, NULL);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
|
||||
return r;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
|
||||
if (s->enabled == SD_EVENT_OFF)
|
||||
s->event->n_enabled_child_sources++;
|
||||
|
||||
s->enabled = m;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* yes, we have pidfd */
|
||||
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
s->event->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* no pidfd, or something other to watch for than WEXITED */
|
||||
|
||||
r = event_make_signal_data(s->event, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
s->event->n_enabled_child_sources--;
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_EXIT:
|
||||
s->enabled = m;
|
||||
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
|
||||
break;
|
||||
|
||||
case SOURCE_DEFER:
|
||||
case SOURCE_POST:
|
||||
case SOURCE_INOTIFY:
|
||||
s->enabled = m;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Wut? I shouldn't exist.");
|
||||
}
|
||||
r = event_source_enable(s, m);
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (s->pending)
|
||||
prioq_reshuffle(s->event->pending, s, &s->pending_index);
|
||||
|
||||
if (s->prepare)
|
||||
prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
|
||||
|
||||
event_source_pp_prioq_reshuffle(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2434,7 +2442,6 @@ _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) {
|
|||
}
|
||||
|
||||
_public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
|
||||
struct clock_data *d;
|
||||
int r;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
|
@ -2448,13 +2455,7 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
|
|||
|
||||
s->time.next = usec;
|
||||
|
||||
d = event_get_clock_data(s->event, s->type);
|
||||
assert(d);
|
||||
|
||||
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2486,7 +2487,6 @@ _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *use
|
|||
}
|
||||
|
||||
_public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) {
|
||||
struct clock_data *d;
|
||||
int r;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
|
@ -2504,12 +2504,7 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec
|
|||
|
||||
s->time.accuracy = usec;
|
||||
|
||||
d = event_get_clock_data(s->event, s->type);
|
||||
assert(d);
|
||||
|
||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2888,9 +2883,7 @@ static int process_timer(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
|
||||
prioq_reshuffle(d->latest, s, &s->time.latest_index);
|
||||
d->needs_rearm = true;
|
||||
event_source_time_prioq_reshuffle(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -195,6 +195,8 @@ shared_sources = files('''
|
|||
ptyfwd.h
|
||||
pwquality-util.c
|
||||
pwquality-util.h
|
||||
qrcode-util.c
|
||||
qrcode-util.h
|
||||
reboot-util.c
|
||||
reboot-util.h
|
||||
resize-fs.c
|
||||
|
@ -304,13 +306,6 @@ if conf.get('HAVE_PAM') == 1
|
|||
'''.split())
|
||||
endif
|
||||
|
||||
if conf.get('HAVE_QRENCODE') == 1
|
||||
shared_sources += files('''
|
||||
qrcode-util.c
|
||||
qrcode-util.h
|
||||
'''.split())
|
||||
endif
|
||||
|
||||
generate_ip_protocol_list = find_program('generate-ip-protocol-list.sh')
|
||||
ip_protocol_list_txt = custom_target(
|
||||
'ip-protocol-list.txt',
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
#include "qrcode-util.h"
|
||||
|
||||
#if HAVE_QRENCODE
|
||||
#include <qrencode.h>
|
||||
|
||||
#include "dlfcn-util.h"
|
||||
#include "locale-util.h"
|
||||
#include "terminal-util.h"
|
||||
|
||||
#define ANSI_WHITE_ON_BLACK "\033[40;37;1m"
|
||||
|
||||
static void print_border(FILE *output, unsigned width) {
|
||||
unsigned x, y;
|
||||
|
||||
/* Four rows of border */
|
||||
for (y = 0; y < 4; y += 2) {
|
||||
for (unsigned y = 0; y < 4; y += 2) {
|
||||
fputs(ANSI_WHITE_ON_BLACK, output);
|
||||
|
||||
for (x = 0; x < 4 + width + 4; x++)
|
||||
for (unsigned x = 0; x < 4 + width + 4; x++)
|
||||
fputs("\342\226\210", output);
|
||||
|
||||
fputs(ANSI_NORMAL "\n", output);
|
||||
}
|
||||
}
|
||||
|
||||
void write_qrcode(FILE *output, QRcode *qr) {
|
||||
unsigned x, y;
|
||||
|
||||
static void write_qrcode(FILE *output, QRcode *qr) {
|
||||
assert(qr);
|
||||
|
||||
if (!output)
|
||||
|
@ -27,17 +29,15 @@ void write_qrcode(FILE *output, QRcode *qr) {
|
|||
|
||||
print_border(output, qr->width);
|
||||
|
||||
for (y = 0; y < (unsigned) qr->width; y += 2) {
|
||||
const uint8_t *row1, *row2;
|
||||
|
||||
row1 = qr->data + qr->width * y;
|
||||
row2 = row1 + qr->width;
|
||||
for (unsigned y = 0; y < (unsigned) qr->width; y += 2) {
|
||||
const uint8_t *row1 = qr->data + qr->width * y;
|
||||
const uint8_t *row2 = row1 + qr->width;
|
||||
|
||||
fputs(ANSI_WHITE_ON_BLACK, output);
|
||||
for (x = 0; x < 4; x++)
|
||||
for (unsigned x = 0; x < 4; x++)
|
||||
fputs("\342\226\210", output);
|
||||
|
||||
for (x = 0; x < (unsigned) qr->width; x ++) {
|
||||
for (unsigned x = 0; x < (unsigned) qr->width; x++) {
|
||||
bool a, b;
|
||||
|
||||
a = row1[x] & 1;
|
||||
|
@ -53,7 +53,7 @@ void write_qrcode(FILE *output, QRcode *qr) {
|
|||
fputs("\342\226\210", output);
|
||||
}
|
||||
|
||||
for (x = 0; x < 4; x++)
|
||||
for (unsigned x = 0; x < 4; x++)
|
||||
fputs("\342\226\210", output);
|
||||
fputs(ANSI_NORMAL "\n", output);
|
||||
}
|
||||
|
@ -61,3 +61,45 @@ void write_qrcode(FILE *output, QRcode *qr) {
|
|||
print_border(output, qr->width);
|
||||
fflush(output);
|
||||
}
|
||||
|
||||
int print_qrcode(FILE *out, const char *header, const char *string) {
|
||||
QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
|
||||
void (*sym_QRcode_free)(QRcode *qrcode);
|
||||
_cleanup_(dlclosep) void *dl = NULL;
|
||||
QRcode* qr;
|
||||
int r;
|
||||
|
||||
/* If this is not an UTF-8 system or ANSI colors aren't supported/disabled don't print any QR
|
||||
* codes */
|
||||
if (!is_locale_utf8() || !colors_enabled())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
dl = dlopen("libqrencode.so.4", RTLD_LAZY);
|
||||
if (!dl)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"QRCODE support is not installed: %s", dlerror());
|
||||
|
||||
r = dlsym_many_and_warn(
|
||||
dl,
|
||||
LOG_DEBUG,
|
||||
&sym_QRcode_encodeString, "QRcode_encodeString",
|
||||
&sym_QRcode_free, "QRcode_free",
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
qr = sym_QRcode_encodeString(string, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
|
||||
if (!qr)
|
||||
return -ENOMEM;
|
||||
|
||||
if (header)
|
||||
fprintf(out, "\n%s:\n\n", header);
|
||||
|
||||
write_qrcode(out, qr);
|
||||
|
||||
fputc('\n', out);
|
||||
|
||||
sym_QRcode_free(qr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if HAVE_QRENCODE
|
||||
#include <qrencode.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void write_qrcode(FILE *output, QRcode *qr);
|
||||
int print_qrcode(FILE *out, const char *header, const char *string);
|
||||
#else
|
||||
static inline int print_qrcode(FILE *out, const char *header, const char *string) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -819,6 +819,10 @@ tests += [
|
|||
[['src/test/test-psi-util.c'],
|
||||
[],
|
||||
[]],
|
||||
|
||||
[['src/test/test-qrcode-util.c'],
|
||||
[libshared],
|
||||
[libdl]],
|
||||
]
|
||||
|
||||
############################################################
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "locale-util.h"
|
||||
#include "main-func.h"
|
||||
#include "qrcode-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
static int run(int argc, char **argv) {
|
||||
int r;
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
assert_se(setenv("SYSTEMD_COLORS", "1", 1) == 0); /* Force the qrcode to be printed */
|
||||
|
||||
r = print_qrcode(stdout, "This should say \"TEST\"", "TEST");
|
||||
if (r == -EOPNOTSUPP)
|
||||
return log_tests_skipped("not supported");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to print QR code: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
|
@ -1,17 +0,0 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1+
|
||||
#
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Initrd Encrypted Volumes
|
||||
Documentation=man:systemd.special(7)
|
||||
OnFailure=emergency.target
|
||||
OnFailureJobMode=replace-irreversibly
|
||||
AssertPathExists=/etc/initrd-release
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
|
@ -22,14 +22,12 @@ units = [
|
|||
'multi-user.target.wants/'],
|
||||
['getty-pre.target', ''],
|
||||
['graphical.target', '',
|
||||
(with_runlevels ? 'runlevel5.target default.target' : 'default.target')],
|
||||
'default.target' + (with_runlevels ? ' runlevel5.target' : '')],
|
||||
['halt.target', ''],
|
||||
['hibernate.target', 'ENABLE_HIBERNATE'],
|
||||
['hybrid-sleep.target', 'ENABLE_HIBERNATE'],
|
||||
['suspend-then-hibernate.target', 'ENABLE_HIBERNATE'],
|
||||
['initrd-cleanup.service', 'ENABLE_INITRD'],
|
||||
['initrd-cryptsetup.target', 'HAVE_LIBCRYPTSETUP ENABLE_INITRD',
|
||||
'sysinit.target.wants/'],
|
||||
['initrd-fs.target', 'ENABLE_INITRD'],
|
||||
['initrd-parse-etc.service', 'ENABLE_INITRD'],
|
||||
['initrd-root-device.target', 'ENABLE_INITRD'],
|
||||
|
@ -61,8 +59,9 @@ units = [
|
|||
'sysinit.target.wants/'],
|
||||
['proc-sys-fs-binfmt_misc.mount', 'ENABLE_BINFMT'],
|
||||
['reboot.target', '',
|
||||
(with_runlevels ? 'runlevel6.target ctrl-alt-del.target' : 'ctrl-alt-del.target')],
|
||||
['remote-cryptsetup.target', 'HAVE_LIBCRYPTSETUP'],
|
||||
'ctrl-alt-del.target' + (with_runlevels ? ' runlevel6.target' : '')],
|
||||
['remote-cryptsetup.target', 'HAVE_LIBCRYPTSETUP',
|
||||
'initrd-root-device.target.wants/'],
|
||||
['remote-fs-pre.target', ''],
|
||||
['remote-fs.target', ''],
|
||||
['rescue.target', '',
|
||||
|
|
Loading…
Reference in New Issue