Compare commits

...

10 Commits

Author SHA1 Message Date
Yu Watanabe 7a182f1034 udev: do not use exact match of file permission
This partially reverts 25de7aa7b9.

Fixes #14473.
2020-01-07 15:16:52 +01:00
Lennart Poettering 983ffdb0bf
Merge pull request #14481 from yuwata/virt-string-table
virt: use string table to detect VM or container
2020-01-07 15:16:31 +01:00
Yu Watanabe 6b50cb5ca9 nspawn: set original ifname as alternative if it is truncated 2020-01-07 15:15:59 +01:00
Yu Watanabe b6cea5496a man: drop unnecessary white space 2020-01-07 13:25:13 +01:00
Lennart Poettering 67861acdf3 locale-util: extend comments on unicode glyph use, and drop mdash (that actually was an ndash)
Let's add the actual unicode names of the glyphs we use. Let's also add
in comments what the width expectations of these glyphs are on the
console.

Also, remove the "mdash" definition. First of all it wasn't used, but
what's worse the glyph encoded was actually an "ndash"...

Fixes: #14075
2020-01-07 13:21:22 +01:00
Lennart Poettering a2a64d3ac9
Merge pull request #14420 from DaanDeMeyer/nspawn-fix-read-only-overlay-rootfs
nspawn: Don't mount read-only if we have a custom mount on root.
2020-01-07 12:14:24 +01:00
Yu Watanabe 25454a0c34 virt: drop trailing white spaces 2020-01-07 11:50:36 +09:00
Yu Watanabe 735ea55f5c virt: use string table to detect VM or container 2020-01-07 11:50:36 +09:00
Daan De Meyer 2436ea761b nspawn: Make a custom mount on root imply --read-only. 2020-01-03 14:06:38 +01:00
Daan De Meyer bbd407ea2b nspawn: Don't mount read-only if we have a custom mount on root. 2020-01-03 14:06:38 +01:00
12 changed files with 182 additions and 77 deletions

View File

@ -97,7 +97,7 @@
</varlistentry>
<varlistentry>
<term><option>--timeout=</option> <replaceable>SECS</replaceable></term>
<term><option>--timeout=</option><replaceable>SECS</replaceable></term>
<listitem><para>Fail the service if the network is not online
by the time the timeout elapses. A timeout of 0 disables the

View File

@ -342,12 +342,11 @@ const char *special_glyph(SpecialGlyph code) {
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">",
[SPECIAL_GLYPH_BLACK_CIRCLE] = "*",
[SPECIAL_GLYPH_BULLET] = "*",
[SPECIAL_GLYPH_ARROW] = "->",
[SPECIAL_GLYPH_MDASH] = "-",
[SPECIAL_GLYPH_ELLIPSIS] = "...",
[SPECIAL_GLYPH_MU] = "u",
[SPECIAL_GLYPH_CHECK_MARK] = "+",
[SPECIAL_GLYPH_CROSS_MARK] = "-",
[SPECIAL_GLYPH_ARROW] = "->",
[SPECIAL_GLYPH_ELLIPSIS] = "...",
[SPECIAL_GLYPH_ECSTATIC_SMILEY] = ":-]",
[SPECIAL_GLYPH_HAPPY_SMILEY] = ":-}",
[SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = ":-)",
@ -359,26 +358,34 @@ const char *special_glyph(SpecialGlyph code) {
/* UTF-8 */
[true] = {
/* The following are multiple glyphs in both ASCII and in UNICODE */
[SPECIAL_GLYPH_TREE_VERTICAL] = "\342\224\202 ", /* │ */
[SPECIAL_GLYPH_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
[SPECIAL_GLYPH_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
[SPECIAL_GLYPH_TREE_SPACE] = " ", /* */
/* Single glyphs in both cases */
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
[SPECIAL_GLYPH_BLACK_CIRCLE] = "\342\227\217", /* ● */
[SPECIAL_GLYPH_BULLET] = "\342\200\242", /* • */
[SPECIAL_GLYPH_ARROW] = "\342\206\222", /* → */
[SPECIAL_GLYPH_MDASH] = "\342\200\223", /* */
[SPECIAL_GLYPH_ELLIPSIS] = "\342\200\246", /* … */
[SPECIAL_GLYPH_MU] = "\316\274", /* μ */
[SPECIAL_GLYPH_MU] = "\316\274", /* μ (actually called: GREEK SMALL LETTER MU) */
[SPECIAL_GLYPH_CHECK_MARK] = "\342\234\223", /* ✓ */
[SPECIAL_GLYPH_CROSS_MARK] = "\342\234\227", /* ✗ */
[SPECIAL_GLYPH_ECSTATIC_SMILEY] = "\360\237\230\207", /* 😇 */
[SPECIAL_GLYPH_HAPPY_SMILEY] = "\360\237\230\200", /* 😀 */
[SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = "\360\237\231\202", /* 🙂 */
[SPECIAL_GLYPH_NEUTRAL_SMILEY] = "\360\237\230\220", /* 😐 */
[SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = "\360\237\231\201", /* 🙁 */
[SPECIAL_GLYPH_UNHAPPY_SMILEY] = "\360\237\230\250", /* 😨 */
[SPECIAL_GLYPH_DEPRESSED_SMILEY] = "\360\237\244\242", /* 🤢 */
[SPECIAL_GLYPH_CROSS_MARK] = "\342\234\227", /* ✗ (actually called: BALLOT X) */
/* Single glyph in Unicode, two in ASCII */
[SPECIAL_GLYPH_ARROW] = "\342\206\222", /* → (actually called: RIGHTWARDS ARROW) */
/* Single glyph in Unicode, three in ASCII */
[SPECIAL_GLYPH_ELLIPSIS] = "\342\200\246", /* … (actually called: HORIZONTAL ELLIPSIS) */
/* These smileys are a single glyph in Unicode, and three in ASCII */
[SPECIAL_GLYPH_ECSTATIC_SMILEY] = "\360\237\230\207", /* 😇 (actually called: SMILING FACE WITH HALO) */
[SPECIAL_GLYPH_HAPPY_SMILEY] = "\360\237\230\200", /* 😀 (actually called: GRINNING FACE) */
[SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = "\360\237\231\202", /* 🙂 (actually called: SLIGHTLY SMILING FACE) */
[SPECIAL_GLYPH_NEUTRAL_SMILEY] = "\360\237\230\220", /* 😐 (actually called: NEUTRAL FACE) */
[SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = "\360\237\231\201", /* 🙁 (actually called: SLIGHTLY FROWNING FACE) */
[SPECIAL_GLYPH_UNHAPPY_SMILEY] = "\360\237\230\250", /* 😨 (actually called: FEARFUL FACE) */
[SPECIAL_GLYPH_DEPRESSED_SMILEY] = "\360\237\244\242", /* 🤢 (actually called: NAUSEATED FACE) */
},
};

View File

@ -46,12 +46,11 @@ typedef enum {
SPECIAL_GLYPH_TRIANGULAR_BULLET,
SPECIAL_GLYPH_BLACK_CIRCLE,
SPECIAL_GLYPH_BULLET,
SPECIAL_GLYPH_ARROW,
SPECIAL_GLYPH_MDASH,
SPECIAL_GLYPH_ELLIPSIS,
SPECIAL_GLYPH_MU,
SPECIAL_GLYPH_CHECK_MARK,
SPECIAL_GLYPH_CROSS_MARK,
SPECIAL_GLYPH_ARROW,
SPECIAL_GLYPH_ELLIPSIS,
_SPECIAL_GLYPH_FIRST_SMILEY,
SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_SMILEY,
SPECIAL_GLYPH_HAPPY_SMILEY,

View File

@ -20,29 +20,28 @@
#include "string-util.h"
#include "virt.h"
static const char *const vm_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_XEN] = "XenVMMXenVMM",
[VIRTUALIZATION_KVM] = "KVMKVMKVM",
[VIRTUALIZATION_QEMU] = "TCGTCGTCGTCG",
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
[VIRTUALIZATION_VMWARE] = "VMwareVMware",
/* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
[VIRTUALIZATION_MICROSOFT] = "Microsoft Hv",
/* https://wiki.freebsd.org/bhyve */
[VIRTUALIZATION_BHYVE] = "bhyve bhyve ",
[VIRTUALIZATION_QNX] = "QNXQVMBSQG",
/* https://projectacrn.org */
[VIRTUALIZATION_ACRN] = "ACRNACRNACRN",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(vm, int);
static int detect_vm_cpuid(void) {
/* CPUID is an x86 specific interface. */
#if defined(__i386__) || defined(__x86_64__)
static const struct {
const char *cpuid;
int id;
} cpuid_vendor_table[] = {
{ "XenVMMXenVMM", VIRTUALIZATION_XEN },
{ "KVMKVMKVM", VIRTUALIZATION_KVM },
{ "TCGTCGTCGTCG", VIRTUALIZATION_QEMU },
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
{ "VMwareVMware", VIRTUALIZATION_VMWARE },
/* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
{ "Microsoft Hv", VIRTUALIZATION_MICROSOFT },
/* https://wiki.freebsd.org/bhyve */
{ "bhyve bhyve ", VIRTUALIZATION_BHYVE },
{ "QNXQVMBSQG", VIRTUALIZATION_QNX },
/* https://projectacrn.org */
{ "ACRNACRNACRN", VIRTUALIZATION_ACRN },
};
uint32_t eax, ebx, ecx, edx;
bool hypervisor;
@ -59,7 +58,7 @@ static int detect_vm_cpuid(void) {
uint32_t sig32[3];
char text[13];
} sig = {};
unsigned j;
int v;
/* There is a hypervisor, see what it is */
__cpuid(0x40000000U, eax, ebx, ecx, edx);
@ -70,11 +69,11 @@ static int detect_vm_cpuid(void) {
log_debug("Virtualization found, CPUID=%s", sig.text);
for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++)
if (streq(sig.text, cpuid_vendor_table[j].cpuid))
return cpuid_vendor_table[j].id;
v = vm_from_string(sig.text);
if (v < 0)
return VIRTUALIZATION_VM_OTHER;
return VIRTUALIZATION_VM_OTHER;
return v;
}
#endif
log_debug("No virtualization found in CPUID");
@ -142,7 +141,7 @@ static int detect_vm_dmi(void) {
int id;
} dmi_vendor_table[] = {
{ "KVM", VIRTUALIZATION_KVM },
{ "QEMU", VIRTUALIZATION_QEMU },
{ "QEMU", VIRTUALIZATION_QEMU },
{ "VMware", VIRTUALIZATION_VMWARE }, /* https://kb.vmware.com/s/article/1009458 */
{ "VMW", VIRTUALIZATION_VMWARE },
{ "innotek GmbH", VIRTUALIZATION_ORACLE },
@ -432,25 +431,23 @@ finish:
return r;
}
int detect_container(void) {
static const struct {
const char *value;
int id;
} value_table[] = {
{ "lxc", VIRTUALIZATION_LXC },
{ "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT },
{ "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
{ "docker", VIRTUALIZATION_DOCKER },
{ "podman", VIRTUALIZATION_PODMAN },
{ "rkt", VIRTUALIZATION_RKT },
{ "wsl", VIRTUALIZATION_WSL },
};
static const char *const container_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_LXC] = "lxc",
[VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt",
[VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
[VIRTUALIZATION_DOCKER] = "docker",
[VIRTUALIZATION_PODMAN] = "podman",
[VIRTUALIZATION_RKT] = "rkt",
[VIRTUALIZATION_WSL] = "wsl",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(container, int);
int detect_container(void) {
static thread_local int cached_found = _VIRTUALIZATION_INVALID;
_cleanup_free_ char *m = NULL;
_cleanup_free_ char *o = NULL;
const char *e = NULL;
unsigned j;
int r;
if (cached_found >= 0)
@ -532,13 +529,9 @@ int detect_container(void) {
goto finish;
translate_name:
for (j = 0; j < ELEMENTSOF(value_table); j++)
if (streq(e, value_table[j].value)) {
r = value_table[j].id;
goto finish;
}
r = VIRTUALIZATION_CONTAINER_OTHER;
r = container_from_string(e);
if (r < 0)
r = VIRTUALIZATION_CONTAINER_OTHER;
finish:
log_debug("Found container virtualization %s.", virtualization_to_string(r));

View File

@ -124,6 +124,49 @@ int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const
return 0;
}
int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char * const *alternative_names) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
int r;
assert(rtnl);
assert(ifname);
if (strv_isempty(alternative_names))
return 0;
if (!*rtnl) {
r = sd_netlink_open(rtnl);
if (r < 0)
return r;
}
r = sd_rtnl_message_new_link(*rtnl, &message, RTM_NEWLINKPROP, 0);
if (r < 0)
return r;
r = sd_netlink_message_append_string(message, IFLA_IFNAME, ifname);
if (r < 0)
return r;
r = sd_netlink_message_open_container(message, IFLA_PROP_LIST);
if (r < 0)
return r;
r = sd_netlink_message_append_strv(message, IFLA_ALT_IFNAME, alternative_names);
if (r < 0)
return r;
r = sd_netlink_message_close_container(message);
if (r < 0)
return r;
r = sd_netlink_call(*rtnl, message, 0, NULL);
if (r < 0)
return r;
return 0;
}
int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, int *ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
int r;

View File

@ -50,6 +50,7 @@ static inline bool rtnl_message_type_is_qdisc(uint16_t type) {
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, uint32_t mtu);
int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names);
int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char * const *alternative_names);
int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, int *ret);
int rtnl_log_parse_error(int r);

View File

@ -989,6 +989,19 @@ int mount_custom(
return 0;
}
bool has_custom_root_mount(const CustomMount *mounts, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
const CustomMount *m = mounts + i;
if (path_equal(m->destination, "/"))
return true;
}
return false;
}
static int setup_volatile_state(const char *directory, uid_t uid_shift, const char *selinux_apifs_context) {
_cleanup_free_ char *buf = NULL;

View File

@ -55,6 +55,7 @@ int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shif
int mount_sysfs(const char *dest, MountSettingsMask mount_settings);
int mount_custom(const char *dest, CustomMount *mounts, size_t n, uid_t uid_shift, const char *selinux_apifs_context, MountSettingsMask mount_settings);
bool has_custom_root_mount(const CustomMount *mounts, size_t n);
int setup_volatile_mode(const char *directory, VolatileMode mode, uid_t uid_shift, const char *selinux_apifs_context);

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <net/if.h>
#include <linux/if.h>
#include <linux/veth.h>
#include <sys/file.h>
@ -99,10 +101,34 @@ static int generate_mac(
return 0;
}
static int set_alternative_ifname(sd_netlink *rtnl, const char *ifname, const char *altifname) {
int r;
assert(rtnl);
assert(ifname);
if (!altifname)
return 0;
if (strlen(altifname) >= ALTIFNAMSIZ)
return log_warning_errno(SYNTHETIC_ERRNO(ERANGE),
"Alternative interface name '%s' for '%s' is too long, ignoring",
altifname, ifname);
r = rtnl_set_link_alternative_names_by_ifname(&rtnl, ifname, STRV_MAKE(altifname));
if (r < 0)
return log_warning_errno(r,
"Failed to set alternative interface name '%s' to '%s', ignoring: %m",
altifname, ifname);
return 0;
}
static int add_veth(
sd_netlink *rtnl,
pid_t pid,
const char *ifname_host,
const char *altifname_host,
const struct ether_addr *mac_host,
const char *ifname_container,
const struct ether_addr *mac_container) {
@ -168,6 +194,8 @@ static int add_veth(
if (r < 0)
return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container);
(void) set_alternative_ifname(rtnl, ifname_host, altifname_host);
return 0;
}
@ -181,13 +209,13 @@ static char urlsafe_base64char(int x) {
return table[x & 63];
}
static void shorten_ifname(char *ifname) {
static int shorten_ifname(char *ifname) {
char new_ifname[IFNAMSIZ];
assert(ifname);
if (strlen(ifname) < IFNAMSIZ) /* Name is short enough */
return;
return 0;
if (naming_scheme_has(NAMING_NSPAWN_LONG_HASH)) {
uint64_t h;
@ -211,6 +239,7 @@ static void shorten_ifname(char *ifname) {
log_warning("Network interface name '%s' has been changed to '%s' to fit length constraints.", ifname, new_ifname);
strcpy(ifname, new_ifname);
return 1;
}
int setup_veth(const char *machine_name,
@ -221,7 +250,7 @@ int setup_veth(const char *machine_name,
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
struct ether_addr mac_host, mac_container;
unsigned u;
char *n;
char *n, *a = NULL;
int r;
assert(machine_name);
@ -231,7 +260,9 @@ int setup_veth(const char *machine_name,
/* Use two different interface name prefixes depending whether
* we are in bridge mode or not. */
n = strjoina(bridge ? "vb-" : "ve-", machine_name);
shorten_ifname(n);
r = shorten_ifname(n);
if (r > 0)
a = strjoina(bridge ? "vb-" : "ve-", machine_name);
r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
if (r < 0)
@ -245,7 +276,7 @@ int setup_veth(const char *machine_name,
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
r = add_veth(rtnl, pid, n, &mac_host, "host0", &mac_container);
r = add_veth(rtnl, pid, n, a, &mac_host, "host0", &mac_container);
if (r < 0)
return r;
@ -288,7 +319,7 @@ int setup_veth_extra(
if (r < 0)
return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
r = add_veth(rtnl, pid, *a, &mac_host, *b, &mac_container);
r = add_veth(rtnl, pid, *a, NULL, &mac_host, *b, &mac_container);
if (r < 0)
return r;
@ -536,7 +567,7 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
STRV_FOREACH(i, ifaces) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
_cleanup_free_ char *n = NULL;
_cleanup_free_ char *n = NULL, *a = NULL;
struct ether_addr mac;
int ifi;
@ -560,7 +591,12 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
if (!n)
return log_oom();
shorten_ifname(n);
r = shorten_ifname(n);
if (r > 0) {
a = strjoin("mv-", *i);
if (!a)
return log_oom();
}
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
if (r < 0)
@ -597,6 +633,8 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
r = sd_netlink_call(rtnl, m, 0, NULL);
if (r < 0)
return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
(void) set_alternative_ifname(rtnl, n, a);
}
return 0;
@ -616,7 +654,7 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
STRV_FOREACH(i, ifaces) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
_cleanup_free_ char *n = NULL;
_cleanup_free_ char *n = NULL, *a = NULL;
int ifi;
ifi = parse_interface(*i);
@ -635,7 +673,12 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
if (!n)
return log_oom();
shorten_ifname(n);
r = shorten_ifname(n);
if (r > 0) {
a = strjoin("iv-", *i);
if (!a)
return log_oom();
}
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
if (r < 0)
@ -668,6 +711,8 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
r = sd_netlink_call(rtnl, m, 0, NULL);
if (r < 0)
return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
(void) set_alternative_ifname(rtnl, n, a);
}
return 0;

View File

@ -1541,6 +1541,9 @@ static int verify_arguments(void) {
if (arg_volatile_mode != VOLATILE_NO) /* Make sure all file systems contained in the image are mounted read-only if we are in volatile mode */
arg_read_only = true;
if (has_custom_root_mount(arg_custom_mounts, arg_n_custom_mounts))
arg_read_only = true;
if (arg_keep_unit && arg_register && cg_pid_get_owner_uid(0, NULL) >= 0)
/* Save the user from accidentally registering either user-$SESSION.scope or user@.service.
* The latter is not technically a user session, but we don't need to labour the point. */
@ -3438,7 +3441,8 @@ static int outer_child(
if (r < 0)
return r;
if (arg_read_only && arg_volatile_mode == VOLATILE_NO) {
if (arg_read_only && arg_volatile_mode == VOLATILE_NO &&
!has_custom_root_mount(arg_custom_mounts, arg_n_custom_mounts)) {
r = bind_remount_recursive(directory, MS_RDONLY, MS_RDONLY, NULL);
if (r < 0)
return log_error_errno(r, "Failed to make tree read-only: %m");

View File

@ -81,7 +81,6 @@ static void dump_special_glyphs(void) {
dump_glyph(SPECIAL_GLYPH_BLACK_CIRCLE);
dump_glyph(SPECIAL_GLYPH_BULLET);
dump_glyph(SPECIAL_GLYPH_ARROW);
dump_glyph(SPECIAL_GLYPH_MDASH);
dump_glyph(SPECIAL_GLYPH_ELLIPSIS);
dump_glyph(SPECIAL_GLYPH_MU);
dump_glyph(SPECIAL_GLYPH_CHECK_MARK);

View File

@ -1654,7 +1654,7 @@ static int udev_rule_apply_token_to_event(
if (mode == MODE_INVALID)
return token->op == OP_MATCH;
match = (((statbuf.st_mode ^ mode) & 07777) == 0);
match = (statbuf.st_mode & mode) > 0;
return token->op == (match ? OP_MATCH : OP_NOMATCH);
}
case TK_M_PROGRAM: {