diff options
Diffstat (limited to '')
126 files changed, 2485 insertions, 957 deletions
diff --git a/sys-utils/Makemodule.am b/sys-utils/Makemodule.am index 7c8d582..209b656 100644 --- a/sys-utils/Makemodule.am +++ b/sys-utils/Makemodule.am @@ -113,6 +113,13 @@ rfkill_LDADD = $(LDADD) libcommon.la libsmartcols.la rfkill_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir) endif +if BUILD_SETPGID +usrbin_exec_PROGRAMS += setpgid +MANPAGES += sys-utils/setpgid.1 +dist_noinst_DATA += sys-utils/setpgid.1.adoc +setpgid_SOURCES = sys-utils/setpgid.c +endif + if BUILD_SETSID usrbin_exec_PROGRAMS += setsid MANPAGES += sys-utils/setsid.1 @@ -524,7 +531,8 @@ if BUILD_NSENTER usrbin_exec_PROGRAMS += nsenter MANPAGES += sys-utils/nsenter.1 dist_noinst_DATA += sys-utils/nsenter.1.adoc -nsenter_SOURCES = sys-utils/nsenter.c lib/exec_shell.c +nsenter_SOURCES = sys-utils/nsenter.c lib/exec_shell.c \ + lib/caputils.c nsenter_LDADD = $(LDADD) libcommon.la $(SELINUX_LIBS) if HAVE_STATIC_NSENTER @@ -573,5 +581,9 @@ MANPAGES += sys-utils/setpriv.1 dist_noinst_DATA += sys-utils/setpriv.1.adoc setpriv_SOURCES = sys-utils/setpriv.c \ lib/caputils.c +dist_noinst_HEADERS += sys-utils/setpriv-landlock.h +if HAVE_LINUX_LANDLOCK_H +setpriv_SOURCES += sys-utils/setpriv-landlock.c +endif setpriv_LDADD = $(LDADD) -lcap-ng libcommon.la endif diff --git a/sys-utils/adjtime_config.5 b/sys-utils/adjtime_config.5 index d1bc519..e6e6edf 100644 --- a/sys-utils/adjtime_config.5 +++ b/sys-utils/adjtime_config.5 @@ -2,12 +2,12 @@ .\" Title: adjtime_config .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: File formats -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "ADJTIME_CONFIG" "5" "2023-10-23" "util\-linux 2.39.3" "File formats" +.TH "ADJTIME_CONFIG" "5" "2024-01-31" "util\-linux 2.40" "File formats" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/blkdiscard.8 b/sys-utils/blkdiscard.8 index 2bd5c2f..62a9630 100644 --- a/sys-utils/blkdiscard.8 +++ b/sys-utils/blkdiscard.8 @@ -2,12 +2,12 @@ .\" Title: blkdiscard .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "BLKDISCARD" "8" "2023-11-21" "util\-linux 2.39.3" "System Administration" +.TH "BLKDISCARD" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/blkdiscard.c b/sys-utils/blkdiscard.c index ed8d6a0..16c32e6 100644 --- a/sys-utils/blkdiscard.c +++ b/sys-utils/blkdiscard.c @@ -105,12 +105,12 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -z, --zeroout zero-fill rather than discard\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(21)); + fprintf(out, USAGE_HELP_OPTIONS(21)); fputs(USAGE_ARGUMENTS, out); - printf(USAGE_ARG_SIZE(_("<num>"))); + fprintf(out, USAGE_ARG_SIZE(_("<num>"))); - printf(USAGE_MAN_TAIL("blkdiscard(8)")); + fprintf(out, USAGE_MAN_TAIL("blkdiscard(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/blkpr.8 b/sys-utils/blkpr.8 index 9299392..f284183 100644 --- a/sys-utils/blkpr.8 +++ b/sys-utils/blkpr.8 @@ -2,12 +2,12 @@ .\" Title: blkpr .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "BLKPR" "8" "2023-11-21" "util\-linux 2.39.3" "System Administration" +.TH "BLKPR" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/blkpr.c b/sys-utils/blkpr.c index 90763db..7f88eba 100644 --- a/sys-utils/blkpr.c +++ b/sys-utils/blkpr.c @@ -223,7 +223,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -t, --type <type> command type\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(26)); + fprintf(out, USAGE_HELP_OPTIONS(26)); fputs(USAGE_ARGUMENTS, out); @@ -236,7 +236,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" <type> is a command type, available types:\n"), out); print_pr_type(out); - printf(USAGE_MAN_TAIL("blkpr(8)")); + fprintf(out, USAGE_MAN_TAIL("blkpr(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/blkzone.8 b/sys-utils/blkzone.8 index f2be426..2a933e9 100644 --- a/sys-utils/blkzone.8 +++ b/sys-utils/blkzone.8 @@ -2,12 +2,12 @@ .\" Title: blkzone .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "BLKZONE" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "BLKZONE" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/blkzone.c b/sys-utils/blkzone.c index 81191e1..9706d61 100644 --- a/sys-utils/blkzone.c +++ b/sys-utils/blkzone.c @@ -402,12 +402,12 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -f, --force enforce on block devices used by the system\n"), out); fputs(_(" -v, --verbose display more details\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_HELP_OPTIONS(24)); fputs(USAGE_ARGUMENTS, out); - printf(USAGE_ARG_SIZE(_("<sector> and <sectors>"))); + fprintf(out, USAGE_ARG_SIZE(_("<sector> and <sectors>"))); - printf(USAGE_MAN_TAIL("blkzone(8)")); + fprintf(out, USAGE_MAN_TAIL("blkzone(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/chcpu.8 b/sys-utils/chcpu.8 index b8a02bf..25e1801 100644 --- a/sys-utils/chcpu.8 +++ b/sys-utils/chcpu.8 @@ -2,12 +2,12 @@ .\" Title: chcpu .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-03-20 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "CHCPU" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "CHCPU" "8" "2024-03-20" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -61,6 +61,8 @@ Enable the specified CPUs. Enabling a CPU means that the kernel sets it online. \fB\-g\fP, \fB\-\-deconfigure\fP \fIcpu\-list\fP .RS 4 Deconfigure the specified CPUs. Deconfiguring a CPU means that the hypervisor removes the CPU from the virtual hardware on which the Linux instance runs and returns it to the CPU pool. A CPU must be offline, see \fB\-d\fP, before it can be deconfigured. +.sp +\fBchcpu \-g\fP is not supported on IBM z/VM, CPUs are always in a configured. .RE .sp \fB\-p\fP, \fB\-\-dispatch\fP \fImode\fP diff --git a/sys-utils/chcpu.8.adoc b/sys-utils/chcpu.8.adoc index c5797df..80dfc5f 100644 --- a/sys-utils/chcpu.8.adoc +++ b/sys-utils/chcpu.8.adoc @@ -37,6 +37,8 @@ Enable the specified CPUs. Enabling a CPU means that the kernel sets it online. *-g*, *--deconfigure* _cpu-list_:: Deconfigure the specified CPUs. Deconfiguring a CPU means that the hypervisor removes the CPU from the virtual hardware on which the Linux instance runs and returns it to the CPU pool. A CPU must be offline, see *-d*, before it can be deconfigured. ++ +*chcpu -g* is not supported on IBM z/VM, CPUs are always in a configured. *-p*, *--dispatch* _mode_:: Set the CPU dispatching _mode_ (polarization). This option has an effect only if your hardware architecture and hypervisor support CPU polarization. Available _modes_ are: diff --git a/sys-utils/chcpu.c b/sys-utils/chcpu.c index 527bce5..ab765a6 100644 --- a/sys-utils/chcpu.c +++ b/sys-utils/chcpu.c @@ -253,9 +253,9 @@ static void __attribute__((__noreturn__)) usage(void) " -p, --dispatch <mode> set dispatching mode\n" " -r, --rescan trigger rescan of cpus\n" ), stdout); - printf(USAGE_HELP_OPTIONS(31)); + fprintf(stdout, USAGE_HELP_OPTIONS(31)); - printf(USAGE_MAN_TAIL("chcpu(8)")); + fprintf(stdout, USAGE_MAN_TAIL("chcpu(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/chmem.8 b/sys-utils/chmem.8 index 793e51c..79eccc4 100644 --- a/sys-utils/chmem.8 +++ b/sys-utils/chmem.8 @@ -2,12 +2,12 @@ .\" Title: chmem .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "CHMEM" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "CHMEM" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/chmem.c b/sys-utils/chmem.c index 09d0af6..4e79859 100644 --- a/sys-utils/chmem.c +++ b/sys-utils/chmem.c @@ -348,13 +348,13 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -b, --blocks use memory blocks\n"), out); fputs(_(" -z, --zone <name> select memory zone (see below)\n"), out); fputs(_(" -v, --verbose verbose output\n"), out); - printf(USAGE_HELP_OPTIONS(20)); + fprintf(out, USAGE_HELP_OPTIONS(20)); fputs(_("\nSupported zones:\n"), out); for (i = 0; i < ARRAY_SIZE(zone_names); i++) fprintf(out, " %s\n", zone_names[i]); - printf(USAGE_MAN_TAIL("chmem(8)")); + fprintf(out, USAGE_MAN_TAIL("chmem(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/choom.1 b/sys-utils/choom.1 index 9645f75..11b1ff3 100644 --- a/sys-utils/choom.1 +++ b/sys-utils/choom.1 @@ -2,12 +2,12 @@ .\" Title: choom .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "CHOOM" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "CHOOM" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/choom.c b/sys-utils/choom.c index b3d3e4d..4bf746b 100644 --- a/sys-utils/choom.c +++ b/sys-utils/choom.c @@ -47,8 +47,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -n, --adjust <num> specify the adjust score value\n"), out); fputs(_(" -p, --pid <num> process ID\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(24)); - printf(USAGE_MAN_TAIL("choom(1)")); + fprintf(out, USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_MAN_TAIL("choom(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/ctrlaltdel.8 b/sys-utils/ctrlaltdel.8 index bc4825a..fb1e64e 100644 --- a/sys-utils/ctrlaltdel.8 +++ b/sys-utils/ctrlaltdel.8 @@ -2,12 +2,12 @@ .\" Title: ctrlaltdel .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "CTRLALTDEL" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "CTRLALTDEL" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/ctrlaltdel.c b/sys-utils/ctrlaltdel.c index 303d2dc..1601154 100644 --- a/sys-utils/ctrlaltdel.c +++ b/sys-utils/ctrlaltdel.c @@ -1,10 +1,16 @@ /* - * ctrlaltdel.c - Set the function of the Ctrl-Alt-Del combination - * Created 4-Jul-92 by Peter Orbaek <poe@daimi.aau.dk> - * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL> - * - added Native Language Support + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 1992 Peter Orbaek <poe@daimi.aau.dk> + * Copyright (C) 1992-1993 Rickard E. Faith <faith@cs.unc.edu> + * + * Set the function of the Ctrl-Alt-Del combination */ - #include <getopt.h> #include <stdio.h> #include <stdlib.h> @@ -31,8 +37,8 @@ static void __attribute__((__noreturn__)) usage(void) fprintf(out, _("Set the function of the Ctrl-Alt-Del combination.\n")); fputs(USAGE_OPTIONS, out); - printf(USAGE_HELP_OPTIONS(16)); - printf(USAGE_MAN_TAIL("ctrlaltdel(8)")); + fprintf(out, USAGE_HELP_OPTIONS(16)); + fprintf(out, USAGE_MAN_TAIL("ctrlaltdel(8)")); exit(EXIT_SUCCESS); } @@ -62,10 +68,6 @@ static int set_cad(const char *arg) { unsigned int cmd; - if (geteuid()) { - warnx(_("You must be root to set the Ctrl-Alt-Del behavior")); - return EXIT_FAILURE; - } if (!strcmp("hard", arg)) cmd = LINUX_REBOOT_CMD_CAD_ON; else if (!strcmp("soft", arg)) diff --git a/sys-utils/dmesg.1 b/sys-utils/dmesg.1 index f70633c..a66cf99 100644 --- a/sys-utils/dmesg.1 +++ b/sys-utils/dmesg.1 @@ -2,12 +2,12 @@ .\" Title: dmesg .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-23 +.\" Date: 2024-03-20 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "DMESG" "1" "2023-11-23" "util\-linux 2.39.3" "User Commands" +.TH "DMESG" "1" "2024-03-20" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -83,7 +83,7 @@ Display the local time and the delta in human\-readable format. Be aware that co .sp \fB\-F\fP, \fB\-\-file\fP \fIfile\fP .RS 4 -Read the syslog messages from the given \fIfile\fP. Note that \fB\-F\fP does not support messages in kmsg format. The old syslog format is supported only. +Read the syslog messages from the given \fIfile\fP. Note that \fB\-F\fP does not support messages in kmsg format. See \fB\-K\fP instead. .RE .sp \fB\-f\fP, \fB\-\-facility\fP \fIlist\fP @@ -105,6 +105,11 @@ Enable human\-readable output. See also \fB\-\-color\fP, \fB\-\-reltime\fP and \ Use JSON output format. The time output format is in "sec.usec" format only, log priority level is not decoded by default (use \fB\-\-decode\fP to split into facility and priority), the other options to control the output format or time format are silently ignored. .RE .sp +\fB\-K\fP, \fB\-\-kmsg\-file\fP \fIfile\fP +.RS 4 +Read the /dev/kmsg messages from the given \fIfile\fP. Different record as expected to be separated by a NULL byte. +.RE +.sp \fB\-k\fP, \fB\-\-kernel\fP .RS 4 Print kernel messages. @@ -195,9 +200,13 @@ Do not print kernel\(cqs timestamps. .sp \fB\-\-time\-format\fP \fIformat\fP .RS 4 -Print timestamps using the given \fIformat\fP, which can be \fBctime\fP, \fBreltime\fP, \fBdelta\fP or \fBiso\fP. The first three formats are aliases of the time\-format\-specific options. The \fBiso\fP format is a \fBdmesg\fP implementation of the ISO\-8601 timestamp format. The purpose of this format is to make the comparing of timestamps between two systems, and any other parsing, easy. The definition of the \fBiso\fP timestamp is: YYYY\-MM\-DD<T>HH:MM:SS,<microseconds>\(<-+><timezone offset from UTC>. +Print timestamps using the given \fIformat\fP, which can be \fBctime\fP, \fBreltime\fP, \fBdelta\fP, \fBiso\fP or \fBraw\fP. The first three formats are aliases of the time\-format\-specific options. The \fBraw\fP format uses the default timestamp format showing seconds since boot. The \fBiso\fP format is a \fBdmesg\fP implementation of the ISO\-8601 timestamp format. The purpose of this format is to make the comparing of timestamps between two systems, and any other parsing, easy. The definition of the \fBiso\fP timestamp is: YYYY\-MM\-DD<T>HH:MM:SS,<microseconds>\(<-+><timezone offset from UTC>. .sp The \fBiso\fP format has the same issue as \fBctime\fP: the time may be inaccurate when a system is suspended and resumed. +.sp +\fB\-\-time\-format\fP may be used multiple times with different values for \fIformat\fP to output each specified format. +.sp +The \fBdelta\fP always follows \fBctime\fP or \fBraw\fP if specified together. .RE .sp \fB\-u\fP, \fB\-\-userspace\fP diff --git a/sys-utils/dmesg.1.adoc b/sys-utils/dmesg.1.adoc index 6f4941e..ccdeefa 100644 --- a/sys-utils/dmesg.1.adoc +++ b/sys-utils/dmesg.1.adoc @@ -57,7 +57,7 @@ Enable printing messages to the console. Display the local time and the delta in human-readable format. Be aware that conversion to the local time could be inaccurate (see *-T* for more details). *-F*, *--file* _file_:: -Read the syslog messages from the given _file_. Note that *-F* does not support messages in kmsg format. The old syslog format is supported only. +Read the syslog messages from the given _file_. Note that *-F* does not support messages in kmsg format. See *-K* instead. *-f*, *--facility* _list_:: Restrict output to the given (comma-separated) _list_ of facilities. For example: @@ -72,6 +72,9 @@ Enable human-readable output. See also *--color*, *--reltime* and *--nopager*. *-J*, *--json*:: Use JSON output format. The time output format is in "sec.usec" format only, log priority level is not decoded by default (use *--decode* to split into facility and priority), the other options to control the output format or time format are silently ignored. +*-K*, *--kmsg-file* _file_:: +Read the /dev/kmsg messages from the given _file_. Different record as expected to be separated by a NULL byte. + *-k*, *--kernel*:: Print kernel messages. @@ -133,9 +136,13 @@ Display record until the specified time. Supported is the subsecond granularity. Do not print kernel's timestamps. *--time-format* _format_:: -Print timestamps using the given _format_, which can be *ctime*, *reltime*, *delta* or *iso*. The first three formats are aliases of the time-format-specific options. The *iso* format is a *dmesg* implementation of the ISO-8601 timestamp format. The purpose of this format is to make the comparing of timestamps between two systems, and any other parsing, easy. The definition of the *iso* timestamp is: YYYY-MM-DD<T>HH:MM:SS,<microseconds><-+><timezone offset from UTC>. +Print timestamps using the given _format_, which can be *ctime*, *reltime*, *delta*, *iso* or *raw*. The first three formats are aliases of the time-format-specific options. The *raw* format uses the default timestamp format showing seconds since boot. The *iso* format is a *dmesg* implementation of the ISO-8601 timestamp format. The purpose of this format is to make the comparing of timestamps between two systems, and any other parsing, easy. The definition of the *iso* timestamp is: YYYY-MM-DD<T>HH:MM:SS,<microseconds><-+><timezone offset from UTC>. + The *iso* format has the same issue as *ctime*: the time may be inaccurate when a system is suspended and resumed. ++ +*--time-format* may be used multiple times with different values for _format_ to output each specified format. ++ +The *delta* always follows *ctime* or *raw* if specified together. *-u*, *--userspace*:: Print userspace messages. diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c index 717cc58..25c674b 100644 --- a/sys-utils/dmesg.c +++ b/sys-utils/dmesg.c @@ -1,14 +1,21 @@ /* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * * dmesg.c -- Print out the contents of the kernel ring buffer * * Copyright (C) 1993 Theodore Ts'o <tytso@athena.mit.edu> - * Copyright (C) 2011 Karel Zak <kzak@redhat.com> - * - * This program comes with ABSOLUTELY NO WARRANTY. + * Copyright (C) 2011-2023 Karel Zak <kzak@redhat.com> */ #include <stdio.h> #include <getopt.h> +#include <stdbool.h> #include <stdlib.h> +#include <string.h> #include <sys/klog.h> #include <sys/syslog.h> #include <sys/time.h> @@ -36,6 +43,7 @@ #include "mangle.h" #include "pager.h" #include "jsonwrt.h" +#include "pathnames.h" /* Close the log. Currently a NOP. */ #define SYSLOG_ACTION_CLOSE 0 @@ -60,6 +68,12 @@ /* Return size of the log buffer */ #define SYSLOG_ACTION_SIZE_BUFFER 10 +#define PID_CHARS_MAX sizeof(stringify_value(LONG_MAX)) +#define PID_CHARS_DEFAULT sizeof(stringify_value(INT_MAX)) +#define SYSLOG_DEFAULT_CALLER_ID_CHARS sizeof(stringify_value(SHRT_MAX))-1 +#define DMESG_CALLER_PREFIX "caller=" +#define DMESG_CALLER_PREFIXSZ (sizeof(DMESG_CALLER_PREFIX)-1) + /* * Color scheme */ @@ -125,6 +139,7 @@ static const struct dmesg_name level_names[] = * shifted code :-) */ #define FAC_BASE(f) ((f) >> 3) +#define LOG_RAW_FAC_PRI(fac, pri) ((fac << 3) | pri) static const struct dmesg_name facility_names[] = { @@ -140,6 +155,18 @@ static const struct dmesg_name facility_names[] = [FAC_BASE(LOG_CRON)] = { "cron", N_("clock daemon") }, [FAC_BASE(LOG_AUTHPRIV)] = { "authpriv", N_("security/authorization messages (private)") }, [FAC_BASE(LOG_FTP)] = { "ftp", N_("FTP daemon") }, + [FAC_BASE(LOG_FTP) + 1] = { "res0", N_("reserved 0") }, + [FAC_BASE(LOG_FTP) + 2] = { "res1", N_("reserved 1") }, + [FAC_BASE(LOG_FTP) + 3] = { "res2", N_("reserved 2") }, + [FAC_BASE(LOG_FTP) + 4] = { "res3", N_("reserved 3") }, + [FAC_BASE(LOG_LOCAL0)] = { "local0", N_("local use 0") }, + [FAC_BASE(LOG_LOCAL1)] = { "local1", N_("local use 1") }, + [FAC_BASE(LOG_LOCAL2)] = { "local2", N_("local use 2") }, + [FAC_BASE(LOG_LOCAL3)] = { "local3", N_("local use 3") }, + [FAC_BASE(LOG_LOCAL4)] = { "local4", N_("local use 4") }, + [FAC_BASE(LOG_LOCAL5)] = { "local5", N_("local use 5") }, + [FAC_BASE(LOG_LOCAL6)] = { "local6", N_("local use 6") }, + [FAC_BASE(LOG_LOCAL7)] = { "local7", N_("local use 7") }, }; /* supported methods to read message buffer @@ -158,9 +185,12 @@ enum { DMESG_TIMEFTM_RELTIME, /* [relative] */ DMESG_TIMEFTM_TIME, /* [time] */ DMESG_TIMEFTM_TIME_DELTA, /* [time <delta>] */ - DMESG_TIMEFTM_ISO8601 /* 2013-06-13T22:11:00,123456+0100 */ + DMESG_TIMEFTM_ISO8601, /* 2013-06-13T22:11:00,123456+0100 */ + + __DMESG_TIMEFTM_COUNT }; -#define is_timefmt(c, f) ((c)->time_fmt == (DMESG_TIMEFTM_ ##f)) + +#define DMESG_TIMEFTM_DEFAULT DMESG_TIMEFTM_TIME struct dmesg_control { /* bit arrays -- see include/bitops.h */ @@ -198,7 +228,8 @@ struct dmesg_control { char *filename; char *mmap_buff; size_t pagesize; - unsigned int time_fmt; /* time format */ + size_t ntime_fmts; + unsigned int time_fmts[2 * __DMESG_TIMEFTM_COUNT]; /* time format */ struct ul_jsonwrt jfmt; /* -J formatting */ @@ -215,6 +246,7 @@ struct dmesg_control { force_prefix:1; /* force timestamp and decode prefix on each line */ int indent; /* due to timestamps if newline */ + size_t caller_id_size; /* PRINTK_CALLERID max field size */ }; struct dmesg_record { @@ -224,6 +256,7 @@ struct dmesg_record { int level; int facility; struct timeval tv; + char caller_id[PID_CHARS_MAX]; const char *next; /* buffer with next unparsed record */ size_t next_size; /* size of the next buffer */ @@ -236,9 +269,11 @@ struct dmesg_record { (_r)->level = -1; \ (_r)->tv.tv_sec = 0; \ (_r)->tv.tv_usec = 0; \ + (_r)->caller_id[0] = 0; \ } while (0) -static int read_kmsg(struct dmesg_control *ctl); +static int process_kmsg(struct dmesg_control *ctl); +static int process_kmsg_file(struct dmesg_control *ctl, char **buf); static int set_level_color(int log_level, const char *mesg, size_t mesgsz) { @@ -290,6 +325,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -D, --console-off disable printing messages to console\n"), out); fputs(_(" -E, --console-on enable printing messages to console\n"), out); fputs(_(" -F, --file <file> use the file instead of the kernel log buffer\n"), out); + fputs(_(" -K, --kmsg-file <file> use the file in kmsg format\n"), out); fputs(_(" -f, --facility <list> restrict output to defined facilities\n"), out); fputs(_(" -H, --human human readable output\n"), out); fputs(_(" -J, --json use JSON output format\n"), out); @@ -315,15 +351,15 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -T, --ctime show human-readable timestamp (may be inaccurate!)\n"), out); fputs(_(" -t, --notime don't show any timestamp with messages\n"), out); fputs(_(" --time-format <format> show timestamp using the given format:\n" - " [delta|reltime|ctime|notime|iso]\n" + " [delta|reltime|ctime|notime|iso|raw]\n" "Suspending/resume will make ctime and iso timestamps inaccurate.\n"), out); fputs(_(" --since <time> display the lines since the specified time\n"), out); fputs(_(" --until <time> display the lines until the specified time\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(29)); + fprintf(out, USAGE_HELP_OPTIONS(29)); fputs(_("\nSupported log facilities:\n"), out); - for (i = 0; i < ARRAY_SIZE(level_names); i++) + for (i = 0; i < ARRAY_SIZE(facility_names); i++) fprintf(out, " %7s - %s\n", facility_names[i].name, _(facility_names[i].help)); @@ -334,10 +370,58 @@ static void __attribute__((__noreturn__)) usage(void) level_names[i].name, _(level_names[i].help)); - printf(USAGE_MAN_TAIL("dmesg(1)")); + fprintf(out, USAGE_MAN_TAIL("dmesg(1)")); exit(EXIT_SUCCESS); } +static void reset_time_fmts(struct dmesg_control *ctl) +{ + memset(ctl->time_fmts, 0, + __DMESG_TIMEFTM_COUNT * sizeof(*(ctl->time_fmts))); + ctl->time_fmts[0] = DMESG_TIMEFTM_DEFAULT; +} + +static int is_time_fmt_set(struct dmesg_control *ctl, unsigned int time_format) +{ + size_t i; + + if (ctl->ntime_fmts == 0) + return time_format == DMESG_TIMEFTM_DEFAULT; + + for (i = 0; i < ctl->ntime_fmts; i++) { + if (ctl->time_fmts[i] == time_format) + return 1; + } + return 0; +} + +static void include_time_fmt(struct dmesg_control *ctl, unsigned int time_format) +{ + if (ctl->ntime_fmts > 0 && is_time_fmt_set(ctl, time_format)) + return; + + if (ctl->ntime_fmts < __DMESG_TIMEFTM_COUNT) + ctl->time_fmts[ctl->ntime_fmts++] = time_format; +} + +static void exclude_time_fmt(struct dmesg_control *ctl, unsigned int time_format) +{ + size_t idx = 0; + + while (idx < ctl->ntime_fmts && ctl->time_fmts[idx] != time_format) + idx++; + + if (idx < ctl->ntime_fmts && ctl->time_fmts[idx] == time_format) { + while (idx + 1 < ctl->ntime_fmts) { + ctl->time_fmts[idx] = ctl->time_fmts[idx+1]; + idx++; + } + ctl->ntime_fmts--; + if (ctl->ntime_fmts == 0) + reset_time_fmts(ctl); + } +} + /* * LEVEL ::= <number> | <name> * <number> ::= @len is set: number in range <0..N>, where N < ARRAY_SIZE(level_names) @@ -510,18 +594,17 @@ static const char *parse_kmsg_timestamp(const char *str0, struct timeval *tv) usec = strtoumax(str, &end, 10); if (!errno && end && (*end == ';' || *end == ',')) { - tv->tv_usec = usec % 1000000; - tv->tv_sec = usec / 1000000; + tv->tv_usec = usec % USEC_PER_SEC; + tv->tv_sec = usec / USEC_PER_SEC; } else return str0; return end + 1; /* skip separator */ } - static double time_diff(struct timeval *a, struct timeval *b) { - return (a->tv_sec - b->tv_sec) + (a->tv_usec - b->tv_usec) / 1E6; + return (a->tv_sec - b->tv_sec) + (a->tv_usec - b->tv_usec) / (double) USEC_PER_SEC; } static int get_syslog_buffer_size(void) @@ -532,6 +615,47 @@ static int get_syslog_buffer_size(void) } /* + * Get the number of characters needed to hold the maximum number + * of tasks this system supports. This size of string could hold + * a thread id large enough for the highest thread id. + * This is needed to determine the number of characters reserved for + * the PRINTK_CALLER field if it has been configured in the Linux Kernel. + * + * The number of digits sets the max value since the value can't exceed + * a value of that size. The /proc field defined by _PATH_PROC_PIDMAX + * holds the maximum number of PID values that may be ussed by the system, + * so 0 to that value minus one. + * + * For determining the size of the PRINTK_CALLER field, we make the safe + * assumption that the number of threads >= number of cpus. This because + * the PRINTK_CALLER field can hold either a thread id or a CPU id value. + * + * If we can't access the pid max kernel proc entry we assign a default + * field size of 5 characters as that is what the old syslog interface + * uses as the reserved field size. This is justified because 32-bit Linux + * systems are limited to PID values between (0-32767). + * + */ +static size_t max_threads_id_size(void) +{ + char taskmax[PID_CHARS_MAX] = {'\0'}; + ssize_t rdsize; + int fd; + + fd = open(_PATH_PROC_PIDMAX, O_RDONLY); + if (fd == -1) + return PID_CHARS_DEFAULT; + + rdsize = read(fd, taskmax, sizeof(taskmax)); + close(fd); + + if (rdsize == -1) + return PID_CHARS_DEFAULT; + + return strnlen(taskmax, sizeof(taskmax)); +} + +/* * Reads messages from regular file by mmap */ static ssize_t mmap_file_buffer(struct dmesg_control *ctl, char **buf) @@ -589,9 +713,9 @@ static ssize_t read_syslog_buffer(struct dmesg_control *ctl, char **buf) } /* - * Top level function to read messages + * Top level function to read (and print in case of kmesg) messages */ -static ssize_t read_buffer(struct dmesg_control *ctl, char **buf) +static ssize_t process_buffer(struct dmesg_control *ctl, char **buf) { ssize_t n = -1; @@ -604,12 +728,17 @@ static ssize_t read_buffer(struct dmesg_control *ctl, char **buf) ctl->bufsize = get_syslog_buffer_size(); n = read_syslog_buffer(ctl, buf); + /* Set number of PID characters for caller_id spacing */ + ctl->caller_id_size = SYSLOG_DEFAULT_CALLER_ID_CHARS; break; case DMESG_METHOD_KMSG: - /* - * Since kernel 3.5.0 - */ - n = read_kmsg(ctl); + if (ctl->filename) + n = process_kmsg_file(ctl, buf); + else + /* + * Since kernel 3.5.0 + */ + n = process_kmsg(ctl); break; default: abort(); /* impossible method -> drop core */ @@ -706,6 +835,39 @@ static const char *skip_item(const char *begin, const char *end, const char *sep } /* + * Checks to see if the caller (caller id) field is present in the kmsg record. + * This is true if the PRINTK_CALLER config option has been set in the kernel. + * + * If the caller_id is found in the kmsg buffer then return the id and id type + * to the caller in dmesg caller_id. Returns string pointer to next value. + * + */ +static const char *parse_callerid(const char *p_str, const char *end, + struct dmesg_record *p_drec) +{ + const char *p_after; + const char *p_next; + size_t cid_size; + char *p_scn; + char *p_cid; + + /* Check for PRINTK_CALLER prefix, must be before msg text */ + p_cid = strstr(p_str, DMESG_CALLER_PREFIX); + p_scn = strchr(p_str, ';'); + if (p_cid != NULL && p_drec != NULL && p_scn != NULL && p_cid < p_scn) { + p_next = p_cid + DMESG_CALLER_PREFIXSZ; + p_after = skip_item(p_next, end, ",;"); + cid_size = p_after - p_next; + if (cid_size < sizeof(p_drec->caller_id)) + xstrncpy(p_drec->caller_id, p_next, cid_size); + else + return p_str; + return p_after; + } + return p_str; +} + +/* * Parses one record from syslog(2) buffer */ static int get_next_syslog_record(struct dmesg_control *ctl, @@ -763,7 +925,7 @@ static int get_next_syslog_record(struct dmesg_control *ctl, if (*begin == '[' && (*(begin + 1) == ' ' || isdigit(*(begin + 1)))) { - if (!is_timefmt(ctl, NONE)) + if (!is_time_fmt_set(ctl, DMESG_TIMEFTM_NONE)) begin = parse_syslog_timestamp(begin + 1, &rec->tv); else begin = skip_item(begin, end, "]"); @@ -772,8 +934,26 @@ static int get_next_syslog_record(struct dmesg_control *ctl, begin++; } - rec->mesg = begin; - rec->mesg_size = end - begin; + if (*begin == '[' && (*(begin + 1) == ' ' || + (*(begin + 1) == 'T' || *(begin + 1) == 'C'))) { + const char *start = begin + 1; + size_t id_size; + + while (start < end && *start == ' ') + start++; + + begin = skip_item(begin, end, "]"); + id_size = begin - start; + + if (id_size < sizeof(rec->caller_id)) + xstrncpy(rec->caller_id, start, id_size); + + rec->mesg = begin < end ? begin + 1 : NULL; + rec->mesg_size = begin < end ? end - begin - 1 : 0; + } else { + rec->mesg = begin; + rec->mesg_size = end - begin; + } /* Don't count \n from the last message to the message size */ if (*end != '\n' && *(end - 1) == '\n') @@ -938,13 +1118,20 @@ static void print_record(struct dmesg_control *ctl, char buf[128]; char fpbuf[32] = "\0"; char tsbuf[64] = "\0"; + char full_tsbuf[64 * __DMESG_TIMEFTM_COUNT] = "\0"; size_t mesg_size = rec->mesg_size; int timebreak = 0; char *mesg_copy = NULL; const char *line = NULL; + double delta = 0; + size_t format_iter = 0; - if (!accept_record(ctl, rec)) + if (!accept_record(ctl, rec)) { + /* remember time of the rejected record to not affect delta for + * the following records */ + ctl->lasttime = rec->tv; return; + } if (!rec->mesg_size) { if (!ctl->json) @@ -952,6 +1139,8 @@ static void print_record(struct dmesg_control *ctl, return; } + delta = record_count_delta(ctl, rec); + if (ctl->json) { if (!ul_jsonwrt_is_ready(&ctl->jfmt)) { ul_jsonwrt_init(&ctl->jfmt, stdout, 0); @@ -966,9 +1155,9 @@ static void print_record(struct dmesg_control *ctl, * backward compatibility with syslog(2) buffers only */ if (ctl->raw) { - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), + ctl->indent = snprintf(full_tsbuf, sizeof(full_tsbuf), "<%d>[%5ld.%06ld] ", - LOG_MAKEPRI(rec->facility, rec->level), + LOG_RAW_FAC_PRI(rec->facility, rec->level), (long) rec->tv.tv_sec, (long) rec->tv.tv_usec); goto full_output; @@ -981,64 +1170,72 @@ static void print_record(struct dmesg_control *ctl, level_names[rec->level].name); /* Store the timestamp in a buffer */ - switch (ctl->time_fmt) { - double delta; - struct tm cur; - case DMESG_TIMEFTM_NONE: - ctl->indent = 0; - break; - case DMESG_TIMEFTM_CTIME: - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[%s] ", - record_ctime(ctl, rec, buf, sizeof(buf))); - break; - case DMESG_TIMEFTM_CTIME_DELTA: - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[%s <%12.06f>] ", - record_ctime(ctl, rec, buf, sizeof(buf)), - record_count_delta(ctl, rec)); - break; - case DMESG_TIMEFTM_DELTA: - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[<%12.06f>] ", - record_count_delta(ctl, rec)); - break; - case DMESG_TIMEFTM_RELTIME: - record_localtime(ctl, rec, &cur); - delta = record_count_delta(ctl, rec); - if (cur.tm_min != ctl->lasttm.tm_min || - cur.tm_hour != ctl->lasttm.tm_hour || - cur.tm_yday != ctl->lasttm.tm_yday) { - timebreak = 1; + for (format_iter = 0; + format_iter < (ctl->ntime_fmts > 0 ? ctl->ntime_fmts : 1); + format_iter++) { + switch (ctl->time_fmts[format_iter]) { + struct tm cur; + case DMESG_TIMEFTM_NONE: + ctl->indent = 0; + break; + case DMESG_TIMEFTM_CTIME: ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[%s] ", - short_ctime(&cur, buf, - sizeof(buf))); - } else { - if (delta < 10) - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), - "[ %+8.06f] ", delta); - else - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), - "[ %+9.06f] ", delta); + record_ctime(ctl, rec, buf, sizeof(buf))); + break; + case DMESG_TIMEFTM_CTIME_DELTA: + ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[%s <%12.06f>] ", + record_ctime(ctl, rec, buf, sizeof(buf)), + delta); + break; + case DMESG_TIMEFTM_DELTA: + ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[<%12.06f>] ", + delta); + break; + case DMESG_TIMEFTM_RELTIME: + record_localtime(ctl, rec, &cur); + if (cur.tm_min != ctl->lasttm.tm_min || + cur.tm_hour != ctl->lasttm.tm_hour || + cur.tm_yday != ctl->lasttm.tm_yday) { + timebreak = 1; + ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[%s] ", + short_ctime(&cur, buf, + sizeof(buf))); + } else { + if (delta < 10) + ctl->indent = snprintf(tsbuf, sizeof(tsbuf), + "[ %+8.06f] ", delta); + else + ctl->indent = snprintf(tsbuf, sizeof(tsbuf), + "[ %+9.06f] ", delta); + } + ctl->lasttm = cur; + break; + case DMESG_TIMEFTM_TIME: + ctl->indent = snprintf(tsbuf, sizeof(tsbuf), + ctl->json ? "%5ld.%06ld" : "[%5ld.%06ld] ", + (long)rec->tv.tv_sec, + (long)rec->tv.tv_usec); + break; + case DMESG_TIMEFTM_TIME_DELTA: + ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[%5ld.%06ld <%12.06f>] ", + (long)rec->tv.tv_sec, + (long)rec->tv.tv_usec, + delta); + break; + case DMESG_TIMEFTM_ISO8601: + ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "%s ", + iso_8601_time(ctl, rec, buf, + sizeof(buf))); + break; + default: + abort(); } - ctl->lasttm = cur; - break; - case DMESG_TIMEFTM_TIME: - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), - ctl->json ? "%5ld.%06ld" : "[%5ld.%06ld] ", - (long)rec->tv.tv_sec, - (long)rec->tv.tv_usec); - break; - case DMESG_TIMEFTM_TIME_DELTA: - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "[%5ld.%06ld <%12.06f>] ", - (long)rec->tv.tv_sec, - (long)rec->tv.tv_usec, - record_count_delta(ctl, rec)); - break; - case DMESG_TIMEFTM_ISO8601: - ctl->indent = snprintf(tsbuf, sizeof(tsbuf), "%s ", - iso_8601_time(ctl, rec, buf, - sizeof(buf))); - break; - default: - abort(); + + if (is_time_fmt_set(ctl, DMESG_TIMEFTM_NONE)) + break; + else if (*tsbuf) + strcat(full_tsbuf, tsbuf); + } ctl->indent += strlen(fpbuf); @@ -1052,32 +1249,45 @@ full_output: ul_jsonwrt_value_s(&ctl->jfmt, "fac", facility_names[rec->facility].name); ul_jsonwrt_value_s(&ctl->jfmt, "pri", level_names[rec->level].name); } else - ul_jsonwrt_value_u64(&ctl->jfmt, "pri", LOG_MAKEPRI(rec->facility, rec->level)); + ul_jsonwrt_value_u64(&ctl->jfmt, "pri", LOG_RAW_FAC_PRI(rec->facility, rec->level)); } /* Output the timestamp buffer */ - if (*tsbuf) { + if (*full_tsbuf) { /* Colorize the timestamp */ if (ctl->color) dmesg_enable_color(timebreak ? DMESG_COLOR_TIMEBREAK : DMESG_COLOR_TIME); - if (ctl->time_fmt != DMESG_TIMEFTM_RELTIME) { + if (!is_time_fmt_set(ctl, DMESG_TIMEFTM_RELTIME)) { if (ctl->json) - ul_jsonwrt_value_raw(&ctl->jfmt, "time", tsbuf); + ul_jsonwrt_value_raw(&ctl->jfmt, "time", full_tsbuf); else - fputs(tsbuf, stdout); + fputs(full_tsbuf, stdout); } else { /* * For relative timestamping, the first line's * timestamp is the offset and all other lines will * report an offset of 0.000000. */ - fputs(!line ? tsbuf : "[ +0.000000] ", stdout); + fputs(!line ? full_tsbuf : "[ +0.000000] ", stdout); } if (ctl->color) color_disable(); } + if (*rec->caller_id) { + if (ctl->json) { + ul_jsonwrt_value_s(&ctl->jfmt, "caller", rec->caller_id); + } else { + char cidbuf[PID_CHARS_MAX+3] = {'\0'}; + + sprintf(cidbuf, "[%*s] ", + (char)ctl->caller_id_size, rec->caller_id); + ctl->indent += strnlen(cidbuf, sizeof(cidbuf)); + fputs(cidbuf, stdout); + } + } + /* * A kernel message may contain several lines of output, separated * by '\n'. If the timestamp and decode outputs are forced then each @@ -1117,7 +1327,7 @@ full_output: color_disable(); } else { if (ctl->json) - ul_jsonwrt_value_s(&ctl->jfmt, "msg", line); + ul_jsonwrt_value_s_sized(&ctl->jfmt, "msg", line, mesg_size); else safe_fwrite(ctl, line, mesg_size, ctl->indent, stdout); } @@ -1197,7 +1407,7 @@ static int init_kmsg(struct dmesg_control *ctl) * but read() returns -EINVAL :-((( * * Let's try to read the first record. The record is later processed in - * read_kmsg(). + * process_kmsg(). */ ctl->kmsg_first_read = read_kmsg_one(ctl); if (ctl->kmsg_first_read < 0) { @@ -1253,7 +1463,7 @@ static int parse_kmsg_record(struct dmesg_control *ctl, goto mesg; /* C) timestamp */ - if (is_timefmt(ctl, NONE)) + if (is_time_fmt_set(ctl, DMESG_TIMEFTM_NONE)) p = skip_item(p, end, ",;"); else p = parse_kmsg_timestamp(p, &rec->tv); @@ -1261,7 +1471,10 @@ static int parse_kmsg_record(struct dmesg_control *ctl, goto mesg; /* D) optional fields (ignore) */ - p = skip_item(p, end, ";"); + p = skip_item(p, end, ",;"); + + /* Include optional PRINTK_CALLER field if it is present */ + p = parse_callerid(p, end, rec); mesg: /* E) message text */ @@ -1305,7 +1518,7 @@ mesg: * * Returns 0 on success, -1 on error. */ -static int read_kmsg(struct dmesg_control *ctl) +static int process_kmsg(struct dmesg_control *ctl) { struct dmesg_record rec; ssize_t sz; @@ -1313,6 +1526,9 @@ static int read_kmsg(struct dmesg_control *ctl) if (ctl->method != DMESG_METHOD_KMSG || ctl->kmsg < 0) return -1; + /* Determine number of PID characters for caller_id spacing */ + ctl->caller_id_size = max_threads_id_size(); + /* * The very first read() call is done in kmsg_init() where we test * /dev/kmsg usability. The return code from the initial read() is @@ -1333,6 +1549,40 @@ static int read_kmsg(struct dmesg_control *ctl) return 0; } +static int process_kmsg_file(struct dmesg_control *ctl, char **buf) +{ + char str[sizeof(ctl->kmsg_buf)]; + struct dmesg_record rec; + ssize_t sz; + size_t len; + + if (ctl->method != DMESG_METHOD_KMSG || !ctl->filename) + return -1; + + sz = mmap_file_buffer(ctl, buf); + if (sz == -1) + return -1; + + while (sz > 0) { + len = strnlen(ctl->mmap_buff, sz); + if (len > sizeof(str)) + errx(EXIT_FAILURE, _("record too large")); + + memcpy(str, ctl->mmap_buff, len); + + if (parse_kmsg_record(ctl, &rec, str, len) == 0) + print_record(ctl, &rec); + + if (len < (size_t)sz) + len++; + + sz -= len; + ctl->mmap_buff += len; + } + + return 0; +} + static int which_time_format(const char *s) { if (!strcmp(s, "notime")) @@ -1345,6 +1595,8 @@ static int which_time_format(const char *s) return DMESG_TIMEFTM_RELTIME; if (!strcmp(s, "iso")) return DMESG_TIMEFTM_ISO8601; + if (!strcmp(s, "raw")) + return DMESG_TIMEFTM_TIME; errx(EXIT_FAILURE, _("unknown time format: %s"), s); } @@ -1387,8 +1639,9 @@ int main(int argc, char *argv[]) .action = SYSLOG_ACTION_READ_ALL, .method = DMESG_METHOD_KMSG, .kmsg = -1, - .time_fmt = DMESG_TIMEFTM_TIME, + .ntime_fmts = 0, .indent = 0, + .caller_id_size = 0, }; int colormode = UL_COLORMODE_UNDEF; enum { @@ -1414,6 +1667,7 @@ int main(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "json", no_argument, NULL, 'J' }, { "kernel", no_argument, NULL, 'k' }, + { "kmsg-file", required_argument, NULL, 'K' }, { "level", required_argument, NULL, 'l' }, { "since", required_argument, NULL, OPT_SINCE }, { "syslog", no_argument, NULL, 'S' }, @@ -1435,6 +1689,7 @@ int main(int argc, char *argv[]) static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ { 'C','D','E','c','n','r' }, /* clear,off,on,read-clear,level,raw*/ + { 'F','K' }, /* file, kmsg-file */ { 'H','r' }, /* human, raw */ { 'L','r' }, /* color, raw */ { 'S','w' }, /* syslog,follow */ @@ -1452,7 +1707,9 @@ int main(int argc, char *argv[]) textdomain(PACKAGE); close_stdout_atexit(); - while ((c = getopt_long(argc, argv, "CcDdEeF:f:HhJkL::l:n:iPprSs:TtuVWwx", + ctl.time_fmts[0] = DMESG_TIMEFTM_DEFAULT; + + while ((c = getopt_long(argc, argv, "CcDdEeF:f:HhJK:kL::l:n:iPprSs:TtuVWwx", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -1474,11 +1731,17 @@ int main(int argc, char *argv[]) ctl.action = SYSLOG_ACTION_CONSOLE_ON; break; case 'e': - ctl.time_fmt = DMESG_TIMEFTM_RELTIME; + include_time_fmt(&ctl, DMESG_TIMEFTM_RELTIME); break; case 'F': ctl.filename = optarg; ctl.method = DMESG_METHOD_MMAP; + ctl.caller_id_size = SYSLOG_DEFAULT_CALLER_ID_CHARS; + break; + case 'K': + ctl.filename = optarg; + ctl.method = DMESG_METHOD_KMSG; + ctl.caller_id_size = max_threads_id_size(); break; case 'f': ctl.fltr_fac = 1; @@ -1487,7 +1750,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; break; case 'H': - ctl.time_fmt = DMESG_TIMEFTM_RELTIME; + include_time_fmt(&ctl, DMESG_TIMEFTM_RELTIME); colormode = UL_COLORMODE_AUTO; ctl.pager = 1; break; @@ -1534,10 +1797,11 @@ int main(int argc, char *argv[]) ctl.bufsize = 4096; break; case 'T': - ctl.time_fmt = DMESG_TIMEFTM_CTIME; + include_time_fmt(&ctl, DMESG_TIMEFTM_CTIME); break; case 't': - ctl.time_fmt = DMESG_TIMEFTM_NONE; + reset_time_fmts(&ctl); + include_time_fmt(&ctl, DMESG_TIMEFTM_NONE); break; case 'u': ctl.fltr_fac = 1; @@ -1555,7 +1819,7 @@ int main(int argc, char *argv[]) ctl.decode = 1; break; case OPT_TIME_FORMAT: - ctl.time_fmt = which_time_format(optarg); + include_time_fmt(&ctl, which_time_format(optarg)); break; case OPT_NOESC: ctl.noesc = 1; @@ -1587,7 +1851,8 @@ int main(int argc, char *argv[]) } if (ctl.json) { - ctl.time_fmt = DMESG_TIMEFTM_TIME; + reset_time_fmts(&ctl); + ctl.ntime_fmts = 0; delta = 0; ctl.force_prefix = 0; ctl.raw = 0; @@ -1595,45 +1860,53 @@ int main(int argc, char *argv[]) nopager = 1; } - if ((is_timefmt(&ctl, RELTIME) || - is_timefmt(&ctl, CTIME) || - is_timefmt(&ctl, ISO8601)) || + if ((is_time_fmt_set(&ctl, DMESG_TIMEFTM_RELTIME) || + is_time_fmt_set(&ctl, DMESG_TIMEFTM_CTIME) || + is_time_fmt_set(&ctl, DMESG_TIMEFTM_ISO8601)) || ctl.since || ctl.until) { if (dmesg_get_boot_time(&ctl.boot_time) != 0) - ctl.time_fmt = DMESG_TIMEFTM_NONE; + include_time_fmt(&ctl, DMESG_TIMEFTM_NONE); else ctl.suspended_time = dmesg_get_suspended_time(); } - if (delta) - switch (ctl.time_fmt) { - case DMESG_TIMEFTM_CTIME: - ctl.time_fmt = DMESG_TIMEFTM_CTIME_DELTA; - break; - case DMESG_TIMEFTM_TIME: - ctl.time_fmt = DMESG_TIMEFTM_TIME_DELTA; - break; - case DMESG_TIMEFTM_ISO8601: - warnx(_("--show-delta is ignored when used together with iso8601 time format")); - break; - default: - ctl.time_fmt = DMESG_TIMEFTM_DELTA; + if (delta || is_time_fmt_set(&ctl, DMESG_TIMEFTM_DELTA)) { + if (is_time_fmt_set(&ctl, DMESG_TIMEFTM_TIME)) { + if (ctl.ntime_fmts == 0) { + ctl.time_fmts[ctl.ntime_fmts++] = DMESG_TIMEFTM_TIME_DELTA; + } else { + exclude_time_fmt(&ctl, DMESG_TIMEFTM_DELTA); + for (n = 0; (size_t) n < ctl.ntime_fmts; n++) { + if (ctl.time_fmts[n] == DMESG_TIMEFTM_TIME) { + ctl.time_fmts[n] = DMESG_TIMEFTM_TIME_DELTA; + break; + } + } + } + } else if (is_time_fmt_set(&ctl, DMESG_TIMEFTM_CTIME)) { + exclude_time_fmt(&ctl, DMESG_TIMEFTM_DELTA); + for (n = 0; (size_t) n < ctl.ntime_fmts; n++) { + if (ctl.time_fmts[n] == DMESG_TIMEFTM_CTIME) { + ctl.time_fmts[n] = DMESG_TIMEFTM_CTIME_DELTA; + break; + } + } + } else { + include_time_fmt(&ctl, DMESG_TIMEFTM_DELTA); } - + } if (!ctl.json) ctl.color = colors_init(colormode, "dmesg") ? 1 : 0; if (ctl.follow) nopager = 1; ctl.pager = nopager ? 0 : ctl.pager; - if (ctl.pager) - pager_redirect(); switch (ctl.action) { case SYSLOG_ACTION_READ_ALL: case SYSLOG_ACTION_READ_CLEAR: - if (ctl.method == DMESG_METHOD_KMSG && init_kmsg(&ctl) != 0) + if (ctl.method == DMESG_METHOD_KMSG && !ctl.filename && init_kmsg(&ctl) != 0) ctl.method = DMESG_METHOD_SYSLOG; if (ctl.raw @@ -1642,12 +1915,11 @@ int main(int argc, char *argv[]) errx(EXIT_FAILURE, _("--raw can be used together with --level or " "--facility only when reading messages from /dev/kmsg")); - /* only kmsg supports multi-line messages */ if (ctl.force_prefix && ctl.method != DMESG_METHOD_KMSG) - ctl.force_prefix = 0; + errx(EXIT_FAILURE, _("only kmsg supports multi-line messages")); if (ctl.pager) pager_redirect(); - n = read_buffer(&ctl, &buf); + n = process_buffer(&ctl, &buf); if (n > 0) print_buffer(&ctl, buf, n); if (!ctl.mmap_buff) diff --git a/sys-utils/eject.1 b/sys-utils/eject.1 index 8260baf..4e79ccc 100644 --- a/sys-utils/eject.1 +++ b/sys-utils/eject.1 @@ -2,12 +2,12 @@ .\" Title: eject .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "EJECT" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "EJECT" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/eject.c b/sys-utils/eject.c index 6037ddc..166d591 100644 --- a/sys-utils/eject.c +++ b/sys-utils/eject.c @@ -164,10 +164,10 @@ static void __attribute__((__noreturn__)) usage(void) out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(29)); + fprintf(out, USAGE_HELP_OPTIONS(29)); fputs(_("\nBy default tries -r, -s, -f, and -q in order until success.\n"), out); - printf(USAGE_MAN_TAIL("eject(1)")); + fprintf(out, USAGE_MAN_TAIL("eject(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/fallocate.1 b/sys-utils/fallocate.1 index 9bd8196..f48c496 100644 --- a/sys-utils/fallocate.1 +++ b/sys-utils/fallocate.1 @@ -2,12 +2,12 @@ .\" Title: fallocate .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "FALLOCATE" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "FALLOCATE" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/fallocate.c b/sys-utils/fallocate.c index 307fbd8..ac7c687 100644 --- a/sys-utils/fallocate.c +++ b/sys-utils/fallocate.c @@ -101,12 +101,12 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -v, --verbose verbose mode\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(22)); + fprintf(out, USAGE_HELP_OPTIONS(22)); fputs(USAGE_ARGUMENTS, out); - printf(USAGE_ARG_SIZE(_("<num>"))); + fprintf(out, USAGE_ARG_SIZE(_("<num>"))); - printf(USAGE_MAN_TAIL("fallocate(1)")); + fprintf(out, USAGE_MAN_TAIL("fallocate(1)")); exit(EXIT_SUCCESS); } @@ -144,8 +144,8 @@ static void xfallocate(int fd, int mode, off_t offset, off_t length) #ifdef HAVE_POSIX_FALLOCATE static void xposix_fallocate(int fd, off_t offset, off_t length) { - int error = posix_fallocate(fd, offset, length); - if (error < 0) { + errno = posix_fallocate(fd, offset, length); + if (errno != 0) { err(EXIT_FAILURE, _("fallocate failed")); } } @@ -290,7 +290,9 @@ int main(int argc, char **argv) int fd; int mode = 0; int dig = 0; - int posix = 0; +#ifdef HAVE_POSIX_FALLOCATE + int posix = 0; +#endif loff_t length = -2LL; loff_t offset = 0; diff --git a/sys-utils/flock.1 b/sys-utils/flock.1 index 8c1ba2f..4ed8c6f 100644 --- a/sys-utils/flock.1 +++ b/sys-utils/flock.1 @@ -2,12 +2,12 @@ .\" Title: flock .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "FLOCK" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "FLOCK" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/flock.c b/sys-utils/flock.c index 6079920..fed29d7 100644 --- a/sys-utils/flock.c +++ b/sys-utils/flock.c @@ -49,7 +49,7 @@ static void __attribute__((__noreturn__)) usage(void) { fputs(USAGE_HEADER, stdout); - printf( + fprintf(stdout, _(" %1$s [options] <file>|<directory> <command> [<argument>...]\n" " %1$s [options] <file>|<directory> -c <command>\n" " %1$s [options] <file descriptor number>\n"), @@ -70,8 +70,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_( " -F, --no-fork execute command without forking\n"), stdout); fputs(_( " --verbose increase verbosity\n"), stdout); fputs(USAGE_SEPARATOR, stdout); - printf(USAGE_HELP_OPTIONS(26)); - printf(USAGE_MAN_TAIL("flock(1)")); + fprintf(stdout, USAGE_HELP_OPTIONS(26)); + fprintf(stdout, USAGE_MAN_TAIL("flock(1)")); exit(EXIT_SUCCESS); } @@ -138,7 +138,7 @@ int main(int argc, char *argv[]) int no_fork = 0; int status; int verbose = 0; - struct timeval time_start, time_done; + struct timeval time_start = { 0 }, time_done = { 0 }; /* * The default exit code for lock conflict or timeout * is specified in man flock.1 @@ -327,7 +327,7 @@ int main(int argc, char *argv[]) if (have_timeout) cancel_timer(&timer); if (verbose) { - struct timeval delta; + struct timeval delta = { 0 }; gettime_monotonic(&time_done); timersub(&time_done, &time_start, &delta); diff --git a/sys-utils/fsfreeze.8 b/sys-utils/fsfreeze.8 index 7a92f64..a34525d 100644 --- a/sys-utils/fsfreeze.8 +++ b/sys-utils/fsfreeze.8 @@ -2,12 +2,12 @@ .\" Title: fsfreeze .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "FSFREEZE" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "FSFREEZE" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/fsfreeze.c b/sys-utils/fsfreeze.c index cd2bb47..d2d9402 100644 --- a/sys-utils/fsfreeze.c +++ b/sys-utils/fsfreeze.c @@ -47,8 +47,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -f, --freeze freeze the filesystem\n"), out); fputs(_(" -u, --unfreeze unfreeze the filesystem\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(19)); - printf(USAGE_MAN_TAIL("fsfreeze(8)")); + fprintf(out, USAGE_HELP_OPTIONS(19)); + fprintf(out, USAGE_MAN_TAIL("fsfreeze(8)")); exit(EXIT_SUCCESS); } @@ -147,4 +147,3 @@ done: close(fd); return rc; } - diff --git a/sys-utils/fstab.5 b/sys-utils/fstab.5 index 011df53..77c388c 100644 --- a/sys-utils/fstab.5 +++ b/sys-utils/fstab.5 @@ -2,12 +2,12 @@ .\" Title: fstab .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-12-01 +.\" Date: 2024-03-20 .\" Manual: File formats -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "FSTAB" "5" "2023-12-01" "util\-linux 2.39.3" "File formats" +.TH "FSTAB" "5" "2024-03-20" "util\-linux 2.40" "File formats" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -36,6 +36,8 @@ fstab \- static information about the filesystems .sp The file \fBfstab\fP contains descriptive information about the filesystems the system can mount. \fBfstab\fP is only read by programs, and not written; it is the duty of the system administrator to properly create and maintain this file. The order of records in \fBfstab\fP is important because \fBfsck\fP(8), \fBmount\fP(8), and \fBumount\fP(8) sequentially iterate through \fBfstab\fP doing their thing. .sp +The file is not read by \fBmount\fP(8) only but often is used by many other tools and daemons, and proper functionality may require additional steps. For example, on systemd\-based systems, it\(cqs recommended to use \fBsystemctl daemon\-reload\fP after \fBfstab\fP modification. +.sp Each filesystem is described on a separate line. Fields on each line are separated by tabs or spaces. Lines starting with \*(Aq#\*(Aq are comments. Blank lines are ignored. .sp The following is a typical example of an \fBfstab\fP entry: @@ -126,6 +128,8 @@ This field is used by \fBfsck\fP(8) to determine the order in which filesystem c The proper way to read records from \fBfstab\fP is to use the routines \fBgetmntent\fP(3) or \fBlibmount\fP. .sp The keyword \fBignore\fP as a filesystem type (3rd field) is no longer supported by the pure libmount based mount utility (since util\-linux v2.22). +.sp +This document describes handling of \fBfstab\fP by \fButil\-linux\fP and \fBlibmount\fP. For \fBsystemd\fP, read \fBsystemd\fP documentation. There are slight differences. .SH "HISTORY" .sp The ancestor of this \fBfstab\fP file format appeared in 4.0BSD. diff --git a/sys-utils/fstab.5.adoc b/sys-utils/fstab.5.adoc index ad1318f..0f12560 100644 --- a/sys-utils/fstab.5.adoc +++ b/sys-utils/fstab.5.adoc @@ -52,6 +52,8 @@ _/etc/fstab_ The file *fstab* contains descriptive information about the filesystems the system can mount. *fstab* is only read by programs, and not written; it is the duty of the system administrator to properly create and maintain this file. The order of records in *fstab* is important because *fsck*(8), *mount*(8), and *umount*(8) sequentially iterate through *fstab* doing their thing. +The file is not read by *mount*(8) only but often is used by many other tools and daemons, and proper functionality may require additional steps. For example, on systemd-based systems, it's recommended to use *systemctl daemon-reload* after *fstab* modification. + Each filesystem is described on a separate line. Fields on each line are separated by tabs or spaces. Lines starting with '#' are comments. Blank lines are ignored. The following is a typical example of an *fstab* entry: @@ -130,6 +132,8 @@ The proper way to read records from *fstab* is to use the routines *getmntent*(3 The keyword *ignore* as a filesystem type (3rd field) is no longer supported by the pure libmount based mount utility (since util-linux v2.22). +This document describes handling of *fstab* by *util-linux* and *libmount*. For *systemd*, read *systemd* documentation. There are slight differences. + == HISTORY The ancestor of this *fstab* file format appeared in 4.0BSD. diff --git a/sys-utils/fstrim.8 b/sys-utils/fstrim.8 index 60b8c69..b00d322 100644 --- a/sys-utils/fstrim.8 +++ b/sys-utils/fstrim.8 @@ -2,12 +2,12 @@ .\" Title: fstrim .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "FSTRIM" "8" "2023-11-21" "util\-linux 2.39.3" "System Administration" +.TH "FSTRIM" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/fstrim.c b/sys-utils/fstrim.c index 96b7d2d..446217e 100644 --- a/sys-utils/fstrim.c +++ b/sys-utils/fstrim.c @@ -469,12 +469,12 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -n, --dry-run does everything, but trim\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(21)); + fprintf(out, USAGE_HELP_OPTIONS(21)); fputs(USAGE_ARGUMENTS, out); - printf(USAGE_ARG_SIZE(_("<num>"))); + fprintf(out, USAGE_ARG_SIZE(_("<num>"))); - printf(USAGE_MAN_TAIL("fstrim(8)")); + fprintf(out, USAGE_MAN_TAIL("fstrim(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/hwclock-cmos.c b/sys-utils/hwclock-cmos.c index d3173fe..5f59090 100644 --- a/sys-utils/hwclock-cmos.c +++ b/sys-utils/hwclock-cmos.c @@ -1,6 +1,12 @@ /* * SPDX-License-Identifier: GPL-2.0-or-later * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * * i386 CMOS starts out with 14 bytes clock data alpha has something * similar, but with details depending on the machine type. * diff --git a/sys-utils/hwclock-rtc.c b/sys-utils/hwclock-rtc.c index 7094cd0..113d4e8 100644 --- a/sys-utils/hwclock-rtc.c +++ b/sys-utils/hwclock-rtc.c @@ -1,6 +1,11 @@ /* * SPDX-License-Identifier: GPL-2.0-or-later * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * * rtc.c - Use /dev/rtc for clock access */ #include <asm/ioctl.h> @@ -424,7 +429,7 @@ static int resolve_rtc_param_alias(const char *alias, __u64 *value) /* kernel uapi __u64 can be defined differently than uint64_t */ static int strtoku64(const char *str, __u64 *num, int base) { - return ul_strtou64(str, (uint64_t *) &num, base); + return ul_strtou64(str, (uint64_t *) num, base); } /* @@ -518,3 +523,89 @@ done: free(opt); return rc; } + +#ifndef RTC_VL_DATA_INVALID +#define RTC_VL_DATA_INVALID 0x1 +#endif +#ifndef RTC_VL_BACKUP_LOW +#define RTC_VL_BACKUP_LOW 0x2 +#endif +#ifndef RTC_VL_BACKUP_EMPTY +#define RTC_VL_BACKUP_EMPTY 0x4 +#endif +#ifndef RTC_VL_ACCURACY_LOW +#define RTC_VL_ACCURACY_LOW 0x8 +#endif +#ifndef RTC_VL_BACKUP_SWITCH +#define RTC_VL_BACKUP_SWITCH 0x10 +#endif + +int rtc_vl_read(const struct hwclock_control *ctl) +{ + unsigned int vl; + int rtc_fd; + size_t i; + static const struct vl_bit { + unsigned int bit; + const char *desc; + } vl_bits[] = { + { RTC_VL_DATA_INVALID, N_("Voltage too low, RTC data is invalid") }, + { RTC_VL_BACKUP_LOW, N_("Backup voltage is low") }, + { RTC_VL_BACKUP_EMPTY, N_("Backup empty or not present") }, + { RTC_VL_ACCURACY_LOW, N_("Voltage is low, RTC accuracy is reduced") }, + { RTC_VL_BACKUP_SWITCH, N_("Backup switchover happened") }, + }; + + rtc_fd = open_rtc(ctl); + if (rtc_fd < 0) { + warnx(_("cannot open %s"), rtc_dev_name); + return 1; + } + + if (ioctl(rtc_fd, RTC_VL_READ, &vl) == -1) { + warn(_("ioctl(%d, RTC_VL_READ) on %s failed"), + rtc_fd, rtc_dev_name); + return 1; + } + + if (ctl->verbose) { + printf(_("ioctl(%d, RTC_VL_READ) on %s returned 0x%x\n"), + rtc_fd, rtc_dev_name, vl); + } + + for (i = 0; i < ARRAY_SIZE(vl_bits); ++i) { + const struct vl_bit *vlb = &vl_bits[i]; + + if (vl & vlb->bit) { + printf("0x%02x - %s\n", vlb->bit, vlb->desc); + vl &= ~vlb->bit; + } + } + if (vl) + printf("0x%02x - unknown bit(s)\n", vl); + + return 0; +} + +int rtc_vl_clear(const struct hwclock_control *ctl) +{ + int rtc_fd; + + rtc_fd = open_rtc(ctl); + if (rtc_fd < 0) { + warnx(_("cannot open %s"), rtc_dev_name); + return 1; + } + + if (ioctl(rtc_fd, RTC_VL_CLR) == -1) { + warn(_("ioctl(%d, RTC_VL_CLEAR) on %s failed"), + rtc_fd, rtc_dev_name); + return 1; + } + + if (ctl->verbose) + printf(_("ioctl(%d, RTC_VL_CLEAR) on %s succeeded.\n"), + rtc_fd, rtc_dev_name); + + return 0; +} diff --git a/sys-utils/hwclock.8 b/sys-utils/hwclock.8 index 070db51..425d967 100644 --- a/sys-utils/hwclock.8 +++ b/sys-utils/hwclock.8 @@ -2,12 +2,12 @@ .\" Title: hwclock .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-12-01 +.\" Date: 2024-03-20 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "HWCLOCK" "8" "2023-12-01" "util\-linux 2.39.3" "System Administration" +.TH "HWCLOCK" "8" "2024-03-20" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -157,6 +157,13 @@ The first two are only available on the first call of \fBsettimeofday\fP(2) afte Set the Hardware Clock from the System Clock, and update the timestamps in \fI/etc/adjtime\fP. With the \fB\-\-update\-drift\fP option also (re)calculate the drift factor. Try it without the option if \fB\-\-systohc\fP fails. See \fB\-\-update\-drift\fP below. .RE .sp +\fB\-\-vl\-read\fP, \fB\-\-vl\-clear\fP +.RS 4 +Some RTC devices are able to monitor the voltage of the backup battery and thus provide a way for the user to know that the battery should be replaced. The \fB\-\-vl\-read\fP function retrieves the Voltage Low information and decodes the result into human\-readable form. The \fB\-\-vl\-clear\fP function resets the Voltage Low information, which is necessary for some RTC devices after a battery replacement. +.sp +See the Kernel\(cqs \fIinclude/uapi/linux/rtc.h\fP for details on which pieces of information may be returned. Note that not all RTC devices have this monitoring capability, nor do all drivers necessarily support reading the information. +.RE +.sp \fB\-h\fP, \fB\-\-help\fP .RS 4 Display help text and exit. diff --git a/sys-utils/hwclock.8.adoc b/sys-utils/hwclock.8.adoc index 3e181ed..0b23a37 100644 --- a/sys-utils/hwclock.8.adoc +++ b/sys-utils/hwclock.8.adoc @@ -101,6 +101,11 @@ The first two are only available on the first call of *settimeofday*(2) after bo *-w*, *--systohc*:: Set the Hardware Clock from the System Clock, and update the timestamps in _{ADJTIME_PATH}_. With the *--update-drift* option also (re)calculate the drift factor. Try it without the option if *--systohc* fails. See *--update-drift* below. +*--vl-read*, *--vl-clear*:: +Some RTC devices are able to monitor the voltage of the backup battery and thus provide a way for the user to know that the battery should be replaced. The *--vl-read* function retrieves the Voltage Low information and decodes the result into human-readable form. The *--vl-clear* function resets the Voltage Low information, which is necessary for some RTC devices after a battery replacement. ++ +See the Kernel's _include/uapi/linux/rtc.h_ for details on which pieces of information may be returned. Note that not all RTC devices have this monitoring capability, nor do all drivers necessarily support reading the information. + include::man-common/help-version.adoc[] == OPTIONS diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c index 2a18443..ca851a4 100644 --- a/sys-utils/hwclock.c +++ b/sys-utils/hwclock.c @@ -1,15 +1,22 @@ /* * SPDX-License-Identifier: GPL-2.0-or-later * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * * Since 7a3000f7ba548cf7d74ac77cc63fe8de228a669e (v2.30) hwclock is linked * with parse_date.y from gnullib. This gnulib code is distributed with GPLv3. * Use --disable-hwclock-gplv3 to exclude this code. * + * Copyright (C) 1992 Charles Hedrick, hedrick@cs.rutgers.edu + * Rob Hooft <hooft@chem.ruu.nl> + * Harald Koenig <koenig@nova.tat.physik.uni-tuebingen.de> + * Alan Modra <alan@spri.levels.unisa.edu.au> * - * clock.c was written by Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992 - * Modified for clock adjustments - Rob Hooft <hooft@chem.ruu.nl>, Nov 1992 - * Improvements by Harald Koenig <koenig@nova.tat.physik.uni-tuebingen.de> - * and Alan Modra <alan@spri.levels.unisa.edu.au>. + * Copyright (C) 2007-2023 Karel Zak <kzak@redhat.com> * * Major rewrite by Bryan Henderson <bryanh@giraffe-data.com>, 96.09.19. * The new program is called hwclock. New features: @@ -617,7 +624,7 @@ set_hardware_clock_exact(const struct hwclock_control *ctl, } newhwtime = sethwtime - + ceil(time_diff(nowsystime, refsystime) + + round(time_diff(nowsystime, refsystime) - delay /* don't count this */); if (ctl->verbose) printf(_("%"PRId64".%06"PRId64" is close enough to %"PRId64".%06"PRId64" (%.6f < %.6f)\n" @@ -1180,6 +1187,20 @@ manipulate_rtc_param(const struct hwclock_control *ctl) return 1; } + +static int +manipulate_rtc_voltage_low(const struct hwclock_control *ctl) +{ + if (ctl->vl_read) { + if (rtc_vl_read(ctl)) + return 1; + } + if (ctl->vl_clear) { + if (rtc_vl_clear(ctl)) + return 1; + } + return 0; +} #endif static void out_version(void) @@ -1215,6 +1236,8 @@ usage(void) #ifdef __linux__ puts(_(" --param-get <param> display the RTC parameter")); puts(_(" --param-set <param>=<value> set the RTC parameter")); + puts(_(" --vl-read read voltage low information")); + puts(_(" --vl-clear clear voltage low information")); #endif puts(_(" --predict predict the drifted RTC time according to --date")); fputs(USAGE_OPTIONS, stdout); @@ -1240,22 +1263,22 @@ usage(void) puts(_(" -v, --verbose display more details")); fputs(USAGE_SEPARATOR, stdout); - printf(USAGE_HELP_OPTIONS(33)); + fprintf(stdout, USAGE_HELP_OPTIONS(33)); #ifdef __linux__ fputs(USAGE_ARGUMENTS, stdout); - puts(_(" <param> is either a numeric RTC parameter value or one of these aliases:")); + fputsln(_(" <param> is either a numeric RTC parameter value or one of these aliases:"), stdout); while (param->name) { - printf(_(" - %1$s: %2$s (0x%3$x)\n"), param->name, param->help, param->id); + fprintf(stdout, _(" - %1$s: %2$s (0x%3$x)\n"), param->name, param->help, param->id); param++; } - puts(_(" See Kernel's include/uapi/linux/rtc.h for parameters and values.")); + fputsln(_(" See Kernel's include/uapi/linux/rtc.h for parameters and values."), stdout); fputs(USAGE_ARG_SEPARATOR, stdout); - puts(_(" <param> and <value> accept hexadecimal values if prefixed with 0x, otherwise decimal.")); + fputsln(_(" <param> and <value> accept hexadecimal values if prefixed with 0x, otherwise decimal."), stdout); #endif - printf(USAGE_MAN_TAIL("hwclock(8)")); + fprintf(stdout, USAGE_MAN_TAIL("hwclock(8)")); exit(EXIT_SUCCESS); } @@ -1286,6 +1309,8 @@ int main(int argc, char **argv) OPT_NOADJFILE, OPT_PARAM_GET, OPT_PARAM_SET, + OPT_VL_READ, + OPT_VL_CLEAR, OPT_PREDICT, OPT_SET, OPT_SETEPOCH, @@ -1315,6 +1340,8 @@ int main(int argc, char **argv) #ifdef __linux__ { "param-get", required_argument, NULL, OPT_PARAM_GET }, { "param-set", required_argument, NULL, OPT_PARAM_SET }, + { "vl-read", no_argument, NULL, OPT_VL_READ }, + { "vl-clear", no_argument, NULL, OPT_VL_CLEAR }, #endif { "noadjfile", no_argument, NULL, OPT_NOADJFILE }, { "directisa", no_argument, NULL, OPT_DIRECTISA }, @@ -1439,6 +1466,14 @@ int main(int argc, char **argv) ctl.show = 0; ctl.hwaudit_on = 1; break; + case OPT_VL_READ: + ctl.vl_read = 1; + ctl.show = 0; + break; + case OPT_VL_CLEAR: + ctl.vl_clear = 1; + ctl.show = 0; + break; #endif case OPT_NOADJFILE: ctl.noadjfile = 1; @@ -1491,7 +1526,7 @@ int main(int argc, char **argv) } if (argc -= optind) { - warnx(_("%d too many arguments given"), argc); + warnx(_("too many arguments")); errtryhelp(EXIT_FAILURE); } @@ -1540,6 +1575,13 @@ int main(int argc, char **argv) hwclock_exit(&ctl, EXIT_SUCCESS); } + + if (ctl.vl_read || ctl.vl_clear) { + if (manipulate_rtc_voltage_low(&ctl)) + hwclock_exit(&ctl, EXIT_FAILURE); + + hwclock_exit(&ctl, EXIT_SUCCESS); + } #endif #if defined(__linux__) && defined(__alpha__) @@ -1581,10 +1623,14 @@ hwclock_exit(const struct hwclock_control *ctl , int status) { #ifdef HAVE_LIBAUDIT + int ret; + if (ctl->hwaudit_on && !ctl->testing) { - audit_log_user_message(hwaudit_fd, AUDIT_USYS_CONFIG, - "op=change-system-time", NULL, NULL, NULL, - status == EXIT_SUCCESS ? 1 : 0); + ret = audit_log_user_message(hwaudit_fd, AUDIT_USYS_CONFIG, + "op=change-system-time", NULL, NULL, NULL, + status == EXIT_SUCCESS ? 1 : 0); + if (ret == -1) + warn(_("could not send audit message")); } close(hwaudit_fd); #endif diff --git a/sys-utils/hwclock.h b/sys-utils/hwclock.h index b5b72d4..91b10a7 100644 --- a/sys-utils/hwclock.h +++ b/sys-utils/hwclock.h @@ -1,3 +1,11 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ #ifndef HWCLOCK_CLOCK_H #define HWCLOCK_CLOCK_H @@ -53,6 +61,8 @@ struct hwclock_control { set:1, update:1, universal:1, /* will store hw_clock_is_utc() return value */ + vl_read:1, + vl_clear:1, verbose:1; }; @@ -88,6 +98,9 @@ extern int get_param_rtc(const struct hwclock_control *ctl, const char *name, uint64_t *id, uint64_t *value); extern int set_param_rtc(const struct hwclock_control *ctl, const char *name); +extern int rtc_vl_read(const struct hwclock_control *ctl); +extern int rtc_vl_clear(const struct hwclock_control *ctl); + extern void __attribute__((__noreturn__)) hwclock_exit(const struct hwclock_control *ctl, int status); diff --git a/sys-utils/ipcmk.1 b/sys-utils/ipcmk.1 index a32bcea..401f351 100644 --- a/sys-utils/ipcmk.1 +++ b/sys-utils/ipcmk.1 @@ -2,12 +2,12 @@ .\" Title: ipcmk .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "IPCMK" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "IPCMK" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/ipcmk.c b/sys-utils/ipcmk.c index 9c1f608..67a7637 100644 --- a/sys-utils/ipcmk.c +++ b/sys-utils/ipcmk.c @@ -76,12 +76,12 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -p, --mode <mode> permission for the resource (default is 0644)\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(26)); + fprintf(out, USAGE_HELP_OPTIONS(26)); fputs(USAGE_ARGUMENTS, out); - printf(USAGE_ARG_SIZE(_("<size>"))); + fprintf(out, USAGE_ARG_SIZE(_("<size>"))); - printf(USAGE_MAN_TAIL("ipcmk(1)")); + fprintf(out, USAGE_MAN_TAIL("ipcmk(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/ipcrm.1 b/sys-utils/ipcrm.1 index f193c8a..907fcbc 100644 --- a/sys-utils/ipcrm.1 +++ b/sys-utils/ipcrm.1 @@ -2,12 +2,12 @@ .\" Title: ipcrm .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "IPCRM" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "IPCRM" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/ipcrm.c b/sys-utils/ipcrm.c index 52768a2..d417c55 100644 --- a/sys-utils/ipcrm.c +++ b/sys-utils/ipcrm.c @@ -1,14 +1,19 @@ /* - * krishna balasubramanian 1993 + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 1993 rishna balasubramanian * * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL> * - added Native Language Support * * 1999-04-02 frank zago * - can now remove several id's in the same call - * */ - #include <errno.h> #include <getopt.h> #include <stdio.h> @@ -65,8 +70,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -v, --verbose explain what is being done\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(28)); - printf(USAGE_MAN_TAIL("ipcrm(1)")); + fprintf(out, USAGE_HELP_OPTIONS(28)); + fprintf(out, USAGE_MAN_TAIL("ipcrm(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/ipcs.1 b/sys-utils/ipcs.1 index 0710f5e..19923cb 100644 --- a/sys-utils/ipcs.1 +++ b/sys-utils/ipcs.1 @@ -2,12 +2,12 @@ .\" Title: ipcs .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "IPCS" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "IPCS" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c index 9380d98..e77a657 100644 --- a/sys-utils/ipcs.c +++ b/sys-utils/ipcs.c @@ -1,6 +1,17 @@ -/* Original author unknown, may be "krishna balasub@cis.ohio-state.edu" */ /* - * Modified Sat Oct 9 10:55:28 1993 for 0.99.13 + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Original author unknown, may be "krishna balasub@cis.ohio-state.edu" + * + * Copyright (C) 1995 ike Jagdis <jaggy@purplet.demon.co.uk> + * 1996 janl@math.uio.no + * Copyright (C) 2006-2023 Karel Zak <kzak@redhat.com> + * * * Patches from Mike Jagdis (jaggy@purplet.demon.co.uk) applied Wed Feb 8 * 12:12:21 1995 by faith@cs.unc.edu to print numeric uids if no passwd file @@ -14,7 +25,6 @@ * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL> * - added Native Language Support */ - #include <errno.h> #include <getopt.h> @@ -66,7 +76,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(USAGE_OPTIONS, out); fputs(_(" -i, --id <id> print details on resource identified by <id>\n"), out); - printf(USAGE_HELP_OPTIONS(16)); + fprintf(out, USAGE_HELP_OPTIONS(16)); fputs(USAGE_SEPARATOR, out); fputs(_("Resource options:\n"), out); @@ -84,7 +94,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -u, --summary show status summary\n"), out); fputs(_(" --human show sizes in human-readable format\n"), out); fputs(_(" -b, --bytes show sizes in bytes\n"), out); - printf(USAGE_MAN_TAIL("ipcs(1)")); + fprintf(out, USAGE_MAN_TAIL("ipcs(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/ipcutils.c b/sys-utils/ipcutils.c index 305ddd7..4d4bebb 100644 --- a/sys-utils/ipcutils.c +++ b/sys-utils/ipcutils.c @@ -1,3 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi> + * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com> + */ #include <inttypes.h> #include "c.h" diff --git a/sys-utils/ipcutils.h b/sys-utils/ipcutils.h index db85f57..0234465 100644 --- a/sys-utils/ipcutils.h +++ b/sys-utils/ipcutils.h @@ -1,3 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi> + * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com> + */ #ifndef UTIL_LINUX_IPCUTILS_H #define UTIL_LINUX_IPCUTILS_H diff --git a/sys-utils/irq-common.c b/sys-utils/irq-common.c index 2d736a0..54af551 100644 --- a/sys-utils/irq-common.c +++ b/sys-utils/irq-common.c @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: GPL-2.1-or-later + * * irq-common.c - functions to display kernel interrupt information. * * Copyright (C) 2019 zhenwei pi <pizhenwei@bytedance.com> @@ -8,17 +10,7 @@ * 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. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - #include <ctype.h> #include <errno.h> #include <limits.h> @@ -328,8 +320,8 @@ static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpus if (stat->nr_irq == stat->nr_irq_info) { stat->nr_irq_info *= 2; - stat->irq_info = xrealloc(stat->irq_info, - sizeof(*stat->irq_info) * stat->nr_irq_info); + stat->irq_info = xreallocarray(stat->irq_info, stat->nr_irq_info, + sizeof(*stat->irq_info)); } } fclose(irqfile); @@ -369,18 +361,29 @@ static inline int cmp_name(const struct irq_info *a, return strcoll(a->name, b->name); } +static inline int cmp_ulong_descending(unsigned long a, + unsigned long b) +{ + if (a == b) + return 0; + if (a < b) + return 1; + else + return -1; +} + static inline int cmp_total(const struct irq_info *a, const struct irq_info *b) { - return a->total < b->total; + int cmp = cmp_ulong_descending(a->total, b->total); + return cmp ? cmp : cmp_name(a, b); } static inline int cmp_delta(const struct irq_info *a, const struct irq_info *b) { - if (a->delta != b->delta) - return a->delta < b->delta; - return cmp_name(a, b); + int cmp = cmp_ulong_descending(a->delta, b->delta); + return cmp ? cmp : cmp_name(a, b); } static inline int cmp_interrupts(const struct irq_info *a, diff --git a/sys-utils/irq-common.h b/sys-utils/irq-common.h index 04c4320..6db252d 100644 --- a/sys-utils/irq-common.h +++ b/sys-utils/irq-common.h @@ -1,3 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.1-or-later + * + * This library 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. + * + * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi> + * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com> + */ #ifndef UTIL_LINUX_H_IRQ_COMMON #define UTIL_LINUX_H_IRQ_COMMON diff --git a/sys-utils/irqtop.1 b/sys-utils/irqtop.1 index d3d9065..8e9c9db 100644 --- a/sys-utils/irqtop.1 +++ b/sys-utils/irqtop.1 @@ -2,12 +2,12 @@ .\" Title: irqtop .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-12-01 +.\" Date: 2024-03-20 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "IRQTOP" "1" "2023-12-01" "util\-linux 2.39.3" "User Commands" +.TH "IRQTOP" "1" "2024-03-20" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -46,7 +46,7 @@ Specify which output columns to print. Use \fB\-\-help\fP to get a list of all s .sp \fB\-c\fP, \fB\-\-cpu\-stat\fP \fImode\fP .RS 4 -Show per\-cpu statistics by specified mode. Available modes are: \fBauto\fP, \fBenable\fP, \fBdisable\fP. The default option \fBauto\fP detects the width of window, then shows the per\-cpu statistics if the width of window is large enouth to show a full line of statistics. +Show per\-cpu statistics by specified mode. Available modes are: \fBauto\fP, \fBenable\fP, \fBdisable\fP. The default option \fBauto\fP detects the width of window, then shows the per\-cpu statistics if the width of window is large enough to show a full line of statistics. .RE .sp \fB\-C\fP, \fB\-\-cpu\-list\fP \fIlist\fP diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc index a310ded..dc6f8db 100644 --- a/sys-utils/irqtop.1.adoc +++ b/sys-utils/irqtop.1.adoc @@ -26,7 +26,7 @@ The default output is subject to change. So whenever possible, you should avoid Specify which output columns to print. Use *--help* to get a list of all supported columns. The default list of columns may be extended if list is specified in the format _+list_. *-c*, *--cpu-stat* _mode_:: -Show per-cpu statistics by specified mode. Available modes are: *auto*, *enable*, *disable*. The default option *auto* detects the width of window, then shows the per-cpu statistics if the width of window is large enouth to show a full line of statistics. +Show per-cpu statistics by specified mode. Available modes are: *auto*, *enable*, *disable*. The default option *auto* detects the width of window, then shows the per-cpu statistics if the width of window is large enough to show a full line of statistics. *-C*, *--cpu-list* _list_:: Specify cpus in list format to show. diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c index eb0e6bc..7baa47b 100644 --- a/sys-utils/irqtop.c +++ b/sys-utils/irqtop.c @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: GPL-2.1-or-later + * * irqtop.c - utility to display kernel interrupt information. * * Copyright (C) 2019 zhenwei pi <pizhenwei@bytedance.com> @@ -8,15 +10,6 @@ * 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. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <ctype.h> #include <errno.h> @@ -272,7 +265,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -s, --sort <column> specify sort column\n"), stdout); fputs(_(" -S, --softirq show softirqs instead of interrupts\n"), stdout); fputs(USAGE_SEPARATOR, stdout); - printf(USAGE_HELP_OPTIONS(22)); + fprintf(stdout, USAGE_HELP_OPTIONS(22)); fputs(_("\nThe following interactive key commands are valid:\n"), stdout); fputs(_(" i sort by IRQ\n"), stdout); @@ -284,7 +277,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(USAGE_COLUMNS, stdout); irq_print_columns(stdout, 0); - printf(USAGE_MAN_TAIL("irqtop(1)")); + fprintf(stdout, USAGE_MAN_TAIL("irqtop(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/ldattach.8 b/sys-utils/ldattach.8 index c6276dc..650996b 100644 --- a/sys-utils/ldattach.8 +++ b/sys-utils/ldattach.8 @@ -2,12 +2,12 @@ .\" Title: ldattach .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "LDATTACH" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "LDATTACH" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/ldattach.c b/sys-utils/ldattach.c index 9c67eee..2a24b3d 100644 --- a/sys-utils/ldattach.c +++ b/sys-utils/ldattach.c @@ -1,17 +1,14 @@ -/* line discipline loading daemon - * open a serial device and attach a line discipline on it +/* + * SPDX-License-Identifier: GPL-2.0-or-later * - * Usage: - * ldattach GIGASET_M101 /dev/ttyS0 + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== + * Line discipline loading daemon open a serial device and attach a line + * discipline on it. */ - #include <errno.h> #include <fcntl.h> #include <getopt.h> @@ -217,7 +214,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -i, --iflag [-]<iflag> set input mode flag\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(25)); + fprintf(out, USAGE_HELP_OPTIONS(25)); fputs(_("\nKnown <ldisc> names:\n"), out); print_table(out, ld_discs); @@ -226,7 +223,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_("\nKnown <iflag> names:\n"), out); print_table(out, ld_iflags); - printf(USAGE_MAN_TAIL("ldattach(8)")); + fprintf(out, USAGE_MAN_TAIL("ldattach(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/losetup.8 b/sys-utils/losetup.8 index aaec4aa..a3a551f 100644 --- a/sys-utils/losetup.8 +++ b/sys-utils/losetup.8 @@ -2,12 +2,12 @@ .\" Title: losetup .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-12-01 +.\" Date: 2024-03-20 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "LOSETUP" "8" "2023-12-01" "util\-linux 2.39.3" "System Administration" +.TH "LOSETUP" "8" "2024-03-20" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -49,7 +49,7 @@ Detach all associated loop devices: .sp Set up a loop device: .sp -\fBlosetup\fP [\fB\-o\fP \fIoffset\fP] [\fB\-\-sizelimit\fP \fIsize\fP] [\fB\-\-sector\-size\fP \fIsize\fP] [\fB\-Pr\fP] [\fB\-\-show\fP] \fB\-f\fP|\fIloopdev file\fP +\fBlosetup\fP [\fB\-o\fP \fIoffset\fP] [\fB\-\-sizelimit\fP \fIsize\fP] [\fB\-\-sector\-size\fP \fIsize\fP] [\fB\-\-loop\-ref\fP \fIname\fP] [\fB\-Pr\fP] [\fB\-\-show\fP] \fB\-f\fP|\fIloopdev file\fP .sp Resize a loop device: .sp @@ -107,6 +107,11 @@ Show the status of all loop devices associated with the given \fIfile\fP. The data start is moved \fIoffset\fP bytes into the specified file or device. The \fIoffset\fP may be followed by the multiplicative suffixes; see above. .RE .sp +\fB\-\-loop\-ref\fP \fIstring\fP +.RS 4 +Set reference string. The backwardly compatible default is to use the backing filename as a reference in loop setup ioctl (aka lo_file_name). This option can overwrite this default behavior and set the reference to the \fIstring\fP. The reference may be used by udevd in /dev/loop/by\-ref. Linux kernel does not use the reference at all, but it could be used by some old utils that cannot read the backing file from sysfs. The reference is readable only for the root user (see \fB\-\-output\fP +REF) and it is restricted to 64 bytes. +.RE +.sp \fB\-\-sizelimit\fP \fIsize\fP .RS 4 The data end is set to no more than \fIsize\fP bytes after the data start. The \fIsize\fP may be followed by the multiplicative suffixes; see above. diff --git a/sys-utils/losetup.8.adoc b/sys-utils/losetup.8.adoc index 94e8e7b..0d4ad74 100644 --- a/sys-utils/losetup.8.adoc +++ b/sys-utils/losetup.8.adoc @@ -30,7 +30,7 @@ Detach all associated loop devices: Set up a loop device: -*losetup* [*-o* _offset_] [*--sizelimit* _size_] [*--sector-size* _size_] [*-Pr*] [*--show*] *-f*|_loopdev file_ +*losetup* [*-o* _offset_] [*--sizelimit* _size_] [*--sector-size* _size_] [*--loop-ref* _name_] [*-Pr*] [*--show*] *-f*|_loopdev file_ Resize a loop device: @@ -74,6 +74,9 @@ Show the status of all loop devices associated with the given _file_. *-o*, *--offset* _offset_:: The data start is moved _offset_ bytes into the specified file or device. The _offset_ may be followed by the multiplicative suffixes; see above. +*--loop-ref* _string_:: +Set reference string. The backwardly compatible default is to use the backing filename as a reference in loop setup ioctl (aka lo_file_name). This option can overwrite this default behavior and set the reference to the _string_. The reference may be used by udevd in /dev/loop/by-ref. Linux kernel does not use the reference at all, but it could be used by some old utils that cannot read the backing file from sysfs. The reference is readable only for the root user (see *--output* +REF) and it is restricted to 64 bytes. + *--sizelimit* _size_:: The data end is set to no more than _size_ bytes after the data start. The _size_ may be followed by the multiplicative suffixes; see above. diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c index 1705379..7134542 100644 --- a/sys-utils/losetup.c +++ b/sys-utils/losetup.c @@ -1,6 +1,14 @@ /* - * Copyright (C) 2011 Karel Zak <kzak@redhat.com> - * Originally from Ted's losetup.c + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Original implementation from Ted Ts'o; losetup was part of mount. + * + * Copyright (C) 2011-2023 Karel Zak <kzak@redhat.com> * * losetup.c - setup and control loop devices */ @@ -45,9 +53,14 @@ enum { COL_BACK_FILE, COL_BACK_INO, COL_BACK_MAJMIN, + COL_BACK_MAJ, + COL_BACK_MIN, COL_MAJMIN, + COL_MAJ, + COL_MIN, COL_OFFSET, COL_PARTSCAN, + COL_REF, COL_RO, COL_SIZELIMIT, COL_DIO, @@ -60,7 +73,7 @@ static int raw; static int json; struct colinfo { - const char *name; + const char * const name; double whint; int flags; const char *help; @@ -68,17 +81,22 @@ struct colinfo { int json_type; /* default is string */ }; -static struct colinfo infos[] = { +static const struct colinfo infos[] = { [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set"), SCOLS_JSON_BOOLEAN}, [COL_BACK_FILE] = { "BACK-FILE", 0.3, SCOLS_FL_NOEXTREMES, N_("device backing file")}, [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number"), SCOLS_JSON_NUMBER}, [COL_BACK_MAJMIN] = { "BACK-MAJ:MIN", 6, 0, N_("backing file major:minor device number")}, + [COL_BACK_MAJ] = { "BACK-MAJ", 6, 0, N_("backing file major device number")}, + [COL_BACK_MIN] = { "BACK-MIN", 6, 0, N_("backing file minor device number")}, [COL_NAME] = { "NAME", 0.25, 0, N_("loop device name")}, [COL_OFFSET] = { "OFFSET", 5, SCOLS_FL_RIGHT, N_("offset from the beginning"), SCOLS_JSON_NUMBER}, [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set"), SCOLS_JSON_BOOLEAN}, + [COL_REF] = { "REF", 0.1, 0, N_("loop device reference string")}, [COL_RO] = { "RO", 1, SCOLS_FL_RIGHT, N_("read-only device"), SCOLS_JSON_BOOLEAN}, [COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes"), SCOLS_JSON_NUMBER}, [COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("loop device major:minor number")}, + [COL_MAJ] = { "MAJ", 1, SCOLS_FL_RIGHT, N_("loop device major number"), SCOLS_JSON_NUMBER}, + [COL_MIN] = { "MIN", 1, SCOLS_FL_RIGHT, N_("loop device minor number"), SCOLS_JSON_NUMBER}, [COL_DIO] = { "DIO", 1, SCOLS_FL_RIGHT, N_("access backing file with direct-io"), SCOLS_JSON_BOOLEAN}, [COL_LOGSEC] = { "LOG-SEC", 4, SCOLS_FL_RIGHT, N_("logical sector size in bytes"), SCOLS_JSON_NUMBER}, }; @@ -94,7 +112,7 @@ static int get_column_id(int num) return columns[num]; } -static struct colinfo *get_column_info(int num) +static const struct colinfo *get_column_info(int num) { return &infos[ get_column_id(num) ]; } @@ -133,23 +151,26 @@ static int printf_loopdev(struct loopdev_cxt *lc) * Probably non-root user (no permissions to * call LOOP_GET_STATUS ioctls). */ - printf("%s: []: (%s)", - loopcxt_get_device(lc), fname); + printf("%s%s: []: (%s)", + loopcxt_get_device(lc), + loopcxt_is_lost(lc) ? " (lost)" : "", + fname); if (loopcxt_get_offset(lc, &x) == 0 && x) printf(_(", offset %ju"), x); - if (loopcxt_get_sizelimit(lc, &x) == 0 && x) printf(_(", sizelimit %ju"), x); + goto done; } - printf("%s: [%04jd]:%ju (%s)", - loopcxt_get_device(lc), (intmax_t) dev, (uintmax_t) ino, fname); + printf("%s%s: [%04jd]:%ju (%s)", + loopcxt_get_device(lc), + loopcxt_is_lost(lc) ? " (lost)" : "", + (intmax_t) dev, (uintmax_t) ino, fname); if (loopcxt_get_offset(lc, &x) == 0 && x) printf(_(", offset %ju"), x); - if (loopcxt_get_sizelimit(lc, &x) == 0 && x) printf(_(", sizelimit %ju"), x); @@ -200,11 +221,24 @@ static int show_all_loops(struct loopdev_cxt *lc, const char *file, return 0; } +static void warn_lost(struct loopdev_cxt *lc) +{ + dev_t devno = loopcxt_get_devno(lc); + + if (devno <= 0) + return; + + warnx(("device node %s (%u:%u) is lost. You may use mknod(1) to recover it."), + loopcxt_get_device(lc), major(devno), minor(devno)); +} + static int delete_loop(struct loopdev_cxt *lc) { - if (loopcxt_delete_device(lc)) + if (loopcxt_delete_device(lc)) { warn(_("%s: detach failed"), loopcxt_get_device(lc)); - else + if (loopcxt_is_lost(lc)) + warn_lost(lc); + } else return 0; return -1; @@ -237,6 +271,10 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) switch(get_column_id(i)) { case COL_NAME: p = loopcxt_get_device(lc); + if (loopcxt_is_lost(lc)) { + xasprintf(&np, "%s (lost)", p); + p = NULL; + } break; case COL_BACK_FILE: np = loopcxt_get_backing_file(lc); @@ -257,16 +295,38 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) major(dev), minor(dev)); break; } + case COL_BACK_MAJ: + { + dev_t dev = 0; + if (loopcxt_get_backing_devno(lc, &dev) == 0 && dev) + xasprintf(&np, "%u", major(dev)); + break; + } + case COL_BACK_MIN: + { + dev_t dev = 0; + if (loopcxt_get_backing_devno(lc, &dev) == 0 && dev) + xasprintf(&np, "%u", minor(dev)); + break; + } case COL_MAJMIN: { - struct stat st; - - if (loopcxt_get_device(lc) - && stat(loopcxt_get_device(lc), &st) == 0 - && S_ISBLK(st.st_mode) - && major(st.st_rdev) == LOOPDEV_MAJOR) + dev_t dev = loopcxt_get_devno(lc); + if (dev) xasprintf(&np, raw || json ? "%u:%u" :"%3u:%-3u", - major(st.st_rdev), minor(st.st_rdev)); + major(dev), minor(dev)); + break; + } + case COL_MAJ: { + dev_t dev = loopcxt_get_devno(lc); + if (dev) + xasprintf(&np, "%u", major(dev)); + break; + } + case COL_MIN: { + dev_t dev = loopcxt_get_devno(lc); + if (dev) + xasprintf(&np, "%u", minor(dev)); break; } case COL_BACK_INO: @@ -292,6 +352,9 @@ static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln) if (loopcxt_get_blocksize(lc, &x) == 0) xasprintf(&np, "%jd", x); break; + case COL_REF: + np = loopcxt_get_refname(lc); + break; default: return -EINVAL; } @@ -332,7 +395,7 @@ static int show_table(struct loopdev_cxt *lc, scols_table_set_name(tb, "loopdevices"); for (i = 0; i < ncolumns; i++) { - struct colinfo *ci = get_column_info(i); + const struct colinfo *ci = get_column_info(i); struct libscols_column *cl; cl = scols_table_new_column(tb, ci->name, ci->whint, ci->flags); @@ -424,6 +487,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -P, --partscan create a partitioned loop device\n"), out); fputs(_(" -r, --read-only set up a read-only loop device\n"), out); fputs(_(" --direct-io[=<on|off>] open backing file with O_DIRECT\n"), out); + fputs(_(" --loop-ref <string> loop device reference\n"), out); fputs(_(" --show print device name after setup (with -f)\n"), out); fputs(_(" -v, --verbose verbose mode\n"), out); @@ -437,13 +501,13 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --raw use raw --list output format\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(31)); + fprintf(out, USAGE_HELP_OPTIONS(31)); fputs(USAGE_COLUMNS, out); for (i = 0; i < ARRAY_SIZE(infos); i++) fprintf(out, " %12s %s\n", infos[i].name, _(infos[i].help)); - printf(USAGE_MAN_TAIL("losetup(8)")); + fprintf(out, USAGE_MAN_TAIL("losetup(8)")); exit(EXIT_SUCCESS); } @@ -466,8 +530,8 @@ static void warn_size(const char *filename, uint64_t size, uint64_t offset, int "may be useless or invisible for system tools."), filename); else if (size % 512) - warnx(_("%s: Warning: file does not fit into a 512-byte sector; " - "the end of the file will be ignored."), + warnx(_("%s: Warning: file does not end on a 512-byte sector boundary; " + "the remaining end of the file will be ignored."), filename); } @@ -492,7 +556,8 @@ static int find_unused(struct loopdev_cxt *lc) static int create_loop(struct loopdev_cxt *lc, int nooverlap, int lo_flags, int flags, - const char *file, uint64_t offset, uint64_t sizelimit, + const char *file, const char *refname, + uint64_t offset, uint64_t sizelimit, uint64_t blocksize) { int hasdev = loopcxt_has_device(lc); @@ -581,7 +646,10 @@ static int create_loop(struct loopdev_cxt *lc, loopcxt_set_flags(lc, lo_flags); if (blocksize > 0) loopcxt_set_blocksize(lc, blocksize); - + if (refname && (rc = loopcxt_set_refname(lc, refname))) { + warnx(_("cannot set loop reference string")); + break; + } if ((rc = loopcxt_set_backing_file(lc, file))) { warn(_("%s: failed to use backing file"), file); break; @@ -598,7 +666,7 @@ static int create_loop(struct loopdev_cxt *lc, } /* errors */ - errpre = hasdev && loopcxt_get_fd(lc) < 0 ? + errpre = hasdev && lc->fd < 0 ? loopcxt_get_device(lc) : file; warn(_("%s: failed to set up loop device"), errpre); break; @@ -611,7 +679,7 @@ int main(int argc, char **argv) { struct loopdev_cxt lc; int act = 0, flags = 0, no_overlap = 0, c; - char *file = NULL; + char *file = NULL, *refname = NULL; uint64_t offset = 0, sizelimit = 0, blocksize = 0; int res = 0, showdev = 0, lo_flags = 0; char *outarg = NULL; @@ -622,6 +690,7 @@ int main(int argc, char **argv) OPT_SIZELIMIT = CHAR_MAX + 1, OPT_SHOW, OPT_RAW, + OPT_REF, OPT_DIO, OPT_OUTPUT_ALL }; @@ -646,6 +715,7 @@ int main(int argc, char **argv) { "read-only", no_argument, NULL, 'r' }, { "direct-io", optional_argument, NULL, OPT_DIO }, { "raw", no_argument, NULL, OPT_RAW }, + { "loop-ref", required_argument, NULL, OPT_REF, }, { "show", no_argument, NULL, OPT_SHOW }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, @@ -684,18 +754,19 @@ int main(int argc, char **argv) break; case 'c': act = A_SET_CAPACITY; - if (!is_loopdev(optarg) || - loopcxt_set_device(&lc, optarg)) + if (loopcxt_set_device(&lc, optarg)) err(EXIT_FAILURE, _("%s: failed to use device"), optarg); break; case 'r': lo_flags |= LO_FLAGS_READ_ONLY; break; + case OPT_REF: + refname = optarg; + break; case 'd': act = A_DELETE; - if (!is_loopdev(optarg) || - loopcxt_set_device(&lc, optarg)) + if (loopcxt_set_device(&lc, optarg)) err(EXIT_FAILURE, _("%s: failed to use device"), optarg); break; @@ -733,6 +804,7 @@ int main(int argc, char **argv) list = 1; break; case OPT_OUTPUT_ALL: + list = 1; for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++) columns[ncolumns] = ncolumns; break; @@ -822,8 +894,7 @@ int main(int argc, char **argv) else act = A_SHOW_ONE; - if (!is_loopdev(argv[optind]) || - loopcxt_set_device(&lc, argv[optind])) + if (loopcxt_set_device(&lc, argv[optind])) err(EXIT_FAILURE, _("%s: failed to use device"), argv[optind]); optind++; @@ -863,7 +934,7 @@ int main(int argc, char **argv) switch (act) { case A_CREATE: - res = create_loop(&lc, no_overlap, lo_flags, flags, file, + res = create_loop(&lc, no_overlap, lo_flags, flags, file, refname, offset, sizelimit, blocksize); if (res == 0) { if (showdev) @@ -874,8 +945,7 @@ int main(int argc, char **argv) case A_DELETE: res = delete_loop(&lc); while (optind < argc) { - if (!is_loopdev(argv[optind]) || - loopcxt_set_device(&lc, argv[optind])) + if (loopcxt_set_device(&lc, argv[optind])) warn(_("%s: failed to use device"), argv[optind]); optind++; @@ -888,7 +958,8 @@ int main(int argc, char **argv) case A_FIND_FREE: res = find_unused(&lc); if (!res) - printf("%s\n", loopcxt_get_device(&lc)); + printf("%s%s\n", loopcxt_get_device(&lc), + loopcxt_is_lost(&lc) ? " (lost)" : ""); break; case A_SHOW: if (list) @@ -928,7 +999,13 @@ int main(int argc, char **argv) break; } + if (res && (act == A_SET_CAPACITY + || act == A_CREATE + || act == A_SET_DIRECT_IO + || act == A_SET_BLOCKSIZE) + && loopcxt_is_lost(&lc)) + warn_lost(&lc); + loopcxt_deinit(&lc); return res ? EXIT_FAILURE : EXIT_SUCCESS; } - diff --git a/sys-utils/lscpu-arm.c b/sys-utils/lscpu-arm.c index 78d6d01..b9e8060 100644 --- a/sys-utils/lscpu-arm.c +++ b/sys-utils/lscpu-arm.c @@ -1,21 +1,12 @@ /* - * lscpu-arm.c - ARM CPU identification tables - * - * Copyright (C) 2018 Riku Voipio <riku.voipio@iki.fi> + * SPDX-License-Identifier: GPL-2.0-or-later * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (C) 2018 Riku Voipio <riku.voipio@iki.fi> * * The information here is gathered from * - ARM manuals @@ -102,6 +93,8 @@ static const struct id_part arm_part[] = { { 0xd80, "Cortex-A520" }, { 0xd81, "Cortex-A720" }, { 0xd82, "Cortex-X4" }, + { 0xd84, "Neoverse-V3" }, + { 0xd8e, "Neoverse-N3" }, { -1, "unknown" }, }; @@ -258,8 +251,10 @@ static const struct id_part fujitsu_part[] = { }; static const struct id_part hisi_part[] = { - { 0xd01, "Kunpeng-920" }, /* aka tsv110 */ + { 0xd01, "TaiShan-v110" }, /* used in Kunpeng-920 SoC */ + { 0xd02, "TaiShan-v120" }, /* used in Kirin 990A and 9000S SoCs */ { 0xd40, "Cortex-A76" }, /* HiSilicon uses this ID though advertises A76 */ + { 0xd41, "Cortex-A77" }, /* HiSilicon uses this ID though advertises A77 */ { -1, "unknown" }, }; @@ -280,6 +275,11 @@ static const struct id_part ft_part[] = { { -1, "unknown" }, }; +static const struct id_part ms_part[] = { + { 0xd49, "Azure-Cobalt-100" }, + { -1, "unknown" }, +}; + static const struct id_part unknown_part[] = { { -1, "unknown" }, }; @@ -307,6 +307,7 @@ static const struct hw_impl hw_implementer[] = { { 0x61, apple_part, "Apple" }, { 0x66, faraday_part, "Faraday" }, { 0x69, intel_part, "Intel" }, + { 0x6d, ms_part, "Microsoft" }, { 0x70, ft_part, "Phytium" }, { 0xc0, ampere_part, "Ampere" }, { -1, unknown_part, "unknown" }, diff --git a/sys-utils/lscpu-cpu.c b/sys-utils/lscpu-cpu.c index 6250cf7..9e1e0c4 100644 --- a/sys-utils/lscpu-cpu.c +++ b/sys-utils/lscpu-cpu.c @@ -1,3 +1,13 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2020 Karel Zak <kzak@redhat.com> + */ #include "lscpu.h" struct lscpu_cpu *lscpu_new_cpu(int id) @@ -10,7 +20,7 @@ struct lscpu_cpu *lscpu_new_cpu(int id) cpu->coreid = -1; cpu->socketid = -1; cpu->bookid = -1; - cpu->bookid = -1; + cpu->drawerid = -1; cpu->address = -1; cpu->configured = -1; diff --git a/sys-utils/lscpu-cputype.c b/sys-utils/lscpu-cputype.c index c8f72ab..bcdf06e 100644 --- a/sys-utils/lscpu-cputype.c +++ b/sys-utils/lscpu-cputype.c @@ -1,4 +1,13 @@ - +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2020 Karel Zak <kzak@redhat.com> + */ #include <sys/utsname.h> #include <sys/personality.h> @@ -109,8 +118,8 @@ struct lscpu_cputype *lscpu_cputype_get_default(struct lscpu_cxt *cxt) struct lscpu_cputype *lscpu_add_cputype(struct lscpu_cxt *cxt, struct lscpu_cputype *ct) { DBG(TYPE, ul_debugobj(ct, "add new")); - cxt->cputypes = xrealloc(cxt->cputypes, (cxt->ncputypes + 1) - * sizeof(struct lscpu_cputype *)); + cxt->cputypes = xreallocarray(cxt->cputypes, cxt->ncputypes + 1, + sizeof(struct lscpu_cputype *)); cxt->cputypes[cxt->ncputypes] = ct; cxt->ncputypes++; lscpu_ref_cputype(ct); @@ -212,12 +221,16 @@ static const struct cpuinfo_pattern type_patterns[] = DEF_PAT_CPUTYPE( "family", PAT_FAMILY, family), DEF_PAT_CPUTYPE( "features", PAT_FEATURES, flags), /* s390 */ DEF_PAT_CPUTYPE( "flags", PAT_FLAGS, flags), /* x86 */ + DEF_PAT_CPUTYPE( "marchid", PAT_FAMILY, family), /* riscv */ DEF_PAT_CPUTYPE( "max thread id", PAT_MAX_THREAD_ID, mtid), /* s390 */ + DEF_PAT_CPUTYPE( "mimpid", PAT_MODEL, model), /* riscv */ DEF_PAT_CPUTYPE( "model", PAT_MODEL, model), DEF_PAT_CPUTYPE( "model name", PAT_MODEL_NAME, modelname), + DEF_PAT_CPUTYPE( "mvendorid", PAT_VENDOR, vendor), /* riscv */ DEF_PAT_CPUTYPE( "revision", PAT_REVISION, revision), DEF_PAT_CPUTYPE( "stepping", PAT_STEPPING, stepping), DEF_PAT_CPUTYPE( "type", PAT_TYPE, flags), /* sparc64 */ + DEF_PAT_CPUTYPE( "uarch", PAT_MODEL_NAME, modelname), /* riscv */ DEF_PAT_CPUTYPE( "vendor", PAT_VENDOR, vendor), DEF_PAT_CPUTYPE( "vendor_id", PAT_VENDOR, vendor), /* s390 */ }; @@ -434,8 +447,8 @@ static int cpuinfo_parse_cache(struct lscpu_cxt *cxt, int keynum, char *data) return 0; cxt->necaches++; - cxt->ecaches = xrealloc(cxt->ecaches, - cxt->necaches * sizeof(struct lscpu_cache)); + cxt->ecaches = xreallocarray(cxt->ecaches, + cxt->necaches, sizeof(struct lscpu_cache)); cache = &cxt->ecaches[cxt->necaches - 1]; memset(cache, 0 , sizeof(*cache)); @@ -643,11 +656,11 @@ struct lscpu_arch *lscpu_read_architecture(struct lscpu_cxt *cxt) snprintf(buf, sizeof(buf), " %s ", ct->flags); if (strstr(buf, " lm ")) - ar->bit32 = 1, ar->bit64 = 1; /* x86_64 */ + ar->bit32 = ar->bit64 = 1; /* x86_64 */ if (strstr(buf, " zarch ")) - ar->bit32 = 1, ar->bit64 = 1; /* s390x */ + ar->bit32 = ar->bit64 = 1; /* s390x */ if (strstr(buf, " sun4v ") || strstr(buf, " sun4u ")) - ar->bit32 = 1, ar->bit64 = 1; /* sparc64 */ + ar->bit32 = ar->bit64 = 1; /* sparc64 */ } if (ct && ct->isa) { diff --git a/sys-utils/lscpu-dmi.c b/sys-utils/lscpu-dmi.c index 9b63dd6..2171f76 100644 --- a/sys-utils/lscpu-dmi.c +++ b/sys-utils/lscpu-dmi.c @@ -1,8 +1,12 @@ -// SPDX-License-Identifier: GPL-2.0 /* + * SPDX-License-Identifier: GPL-2.0-only + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * * Copyright (C) 2020 FUJITSU LIMITED. All rights reserved. */ - #include "lscpu.h" void to_dmi_header(struct lscpu_dmi_header *h, uint8_t *data) diff --git a/sys-utils/lscpu-topology.c b/sys-utils/lscpu-topology.c index 754b3fc..e3742e3 100644 --- a/sys-utils/lscpu-topology.c +++ b/sys-utils/lscpu-topology.c @@ -1,3 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2008 Cai Qian <qcai@redhat.com> + * Copyright (C) 2008-2023 Karel Zak <kzak@redhat.com> + */ #include <errno.h> #include <stdlib.h> #include <sys/types.h> @@ -242,7 +253,8 @@ struct lscpu_cache *lscpu_cpu_get_cache(struct lscpu_cxt *cxt, for (i = 0; i < cxt->ncaches; i++) { struct lscpu_cache *ca = &cxt->caches[i]; - if (strcmp(ca->name, name) == 0 && + if (ca->sharedmap && + strcmp(ca->name, name) == 0 && CPU_ISSET_S(cpu->logical_id, cxt->setsize, ca->sharedmap)) return ca; } @@ -274,8 +286,8 @@ static struct lscpu_cache *add_cache(struct lscpu_cxt *cxt, struct lscpu_cache *ca; cxt->ncaches++; - cxt->caches = xrealloc(cxt->caches, - cxt->ncaches * sizeof(*cxt->caches)); + cxt->caches = xreallocarray(cxt->caches, + cxt->ncaches, sizeof(*cxt->caches)); ca = &cxt->caches[cxt->ncaches - 1]; memset(ca, 0 , sizeof(*ca)); diff --git a/sys-utils/lscpu-virt.c b/sys-utils/lscpu-virt.c index 6b6deb8..dc786a8 100644 --- a/sys-utils/lscpu-virt.c +++ b/sys-utils/lscpu-virt.c @@ -1,3 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2008 Cai Qian <qcai@redhat.com> + * Copyright (C) 2008-2023 Karel Zak <kzak@redhat.com> + */ #include <errno.h> #include <stdlib.h> #include <sys/types.h> @@ -6,6 +17,7 @@ #include <unistd.h> #include <string.h> #include <stdio.h> +#include <signal.h> #include "lscpu.h" @@ -15,7 +27,6 @@ #ifdef INCLUDE_VMWARE_BDOOR # include <stdint.h> -# include <signal.h> # include <strings.h> # include <setjmp.h> # ifdef HAVE_SYS_IO_H @@ -395,17 +406,13 @@ static int read_hypervisor_powerpc(struct lscpu_cxt *cxt, int *type) && ul_path_access(cxt->procfs, F_OK, "device-tree/hmc-managed?") == 0 && ul_path_access(cxt->procfs, F_OK, "device-tree/chosen/qemu,graphic-width") != 0) { - FILE *fd; + char buf[256]; vendor = VIRT_VENDOR_PHYP; *type = VIRT_TYPE_PARA; - fd = ul_path_fopen(cxt->procfs, "r", "device-tree/ibm,partition-name"); - if (fd) { - char buf[256]; - if (fscanf(fd, "%255s", buf) == 1 && !strcmp(buf, "full")) - *type = VIRT_TYPE_NONE; - fclose(fd); - } + if (ul_path_scanf(cxt->procfs, "device-tree/ibm,partition-name", "%255s", buf) == 1 && + !strcmp(buf, "full")) + *type = VIRT_TYPE_NONE; /* Qemu */ } else if (is_devtree_compatible(cxt, "qemu,pseries")) { @@ -447,6 +454,7 @@ void vmware_bdoor(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) } static jmp_buf segv_handler_env; +static sigset_t oset; static void segv_handler(__attribute__((__unused__)) int sig, @@ -460,6 +468,7 @@ static int is_vmware_platform(void) { uint32_t eax, ebx, ecx, edx; struct sigaction act, oact; + sigset_t set; /* * FIXME: Not reliable for non-root users. Note it works as expected if @@ -478,8 +487,16 @@ static int is_vmware_platform(void) * the signal. All this magic is needed because lscpu * isn't supposed to require root privileges. */ - if (sigsetjmp(segv_handler_env, 1)) + if (sigsetjmp(segv_handler_env, 1)) { + if (sigprocmask(SIG_SETMASK, &oset, NULL)) + err(EXIT_FAILURE, _("cannot restore signal mask")); return 0; + } + + sigemptyset(&set); + sigaddset(&set, SIGSEGV); + if (sigprocmask(SIG_UNBLOCK, &set, &oset)) + err(EXIT_FAILURE, _("cannot unblock signal")); memset(&act, 0, sizeof(act)); act.sa_sigaction = segv_handler; @@ -493,6 +510,9 @@ static int is_vmware_platform(void) if (sigaction(SIGSEGV, &oact, NULL)) err(EXIT_FAILURE, _("cannot restore signal handler")); + if (sigprocmask(SIG_SETMASK, &oset, NULL)) + err(EXIT_FAILURE, _("cannot restore signal mask")); + return eax != (uint32_t)-1 && ebx == VMWARE_BDOOR_MAGIC; } @@ -551,9 +571,7 @@ struct lscpu_virt *lscpu_read_virtualization(struct lscpu_cxt *cxt) if (virt->vendor == VIRT_VENDOR_XEN) { uint32_t features; - fd = ul_prefix_fopen(cxt->prefix, "r", _PATH_SYS_HYP_FEATURES); - - if (fd && fscanf(fd, "%x", &features) == 1) { + if (ul_path_scanf(cxt->rootfs, _PATH_SYS_HYP_FEATURES, "%x", &features) == 1) { /* Xen PV domain */ if (features & XEN_FEATURES_PV_MASK) virt->type = VIRT_TYPE_PARA; @@ -562,25 +580,18 @@ struct lscpu_virt *lscpu_read_virtualization(struct lscpu_cxt *cxt) == XEN_FEATURES_PVH_MASK) virt->type = VIRT_TYPE_PARA; } - if (fd) - fclose(fd); } } else if ((virt->vendor = read_hypervisor_powerpc(cxt, &virt->type))) { ; /* Xen para-virt or dom0 */ } else if (ul_path_access(cxt->procfs, F_OK, "xen") == 0) { + char xenbuf[256]; int dom0 = 0; - fd = ul_path_fopen(cxt->procfs, "r", "xen/capabilities"); - if (fd) { - char xenbuf[256]; - - if (fscanf(fd, "%255s", xenbuf) == 1 && - !strcmp(xenbuf, "control_d")) - dom0 = 1; - fclose(fd); - } + if (ul_path_scanf(cxt->procfs, "xen/capabilities", "%255s", xenbuf) == 1 && + !strcmp(xenbuf, "control_d")) + dom0 = 1; virt->type = dom0 ? VIRT_TYPE_NONE : VIRT_TYPE_PARA; virt->vendor = VIRT_VENDOR_XEN; diff --git a/sys-utils/lscpu.1 b/sys-utils/lscpu.1 index b73f8d3..57b91d9 100644 --- a/sys-utils/lscpu.1 +++ b/sys-utils/lscpu.1 @@ -2,12 +2,12 @@ .\" Title: lscpu .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "LSCPU" "1" "2023-11-21" "util\-linux 2.39.3" "User Commands" +.TH "LSCPU" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c index 1e61cc7..c073fc0 100644 --- a/sys-utils/lscpu.c +++ b/sys-utils/lscpu.c @@ -1,24 +1,16 @@ /* - * lscpu - CPU architecture information helper - * - * Copyright (C) 2008 Cai Qian <qcai@redhat.com> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * SPDX-License-Identifier: GPL-2.0-or-later * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2008 Cai Qian <qcai@redhat.com> + * Copyright (C) 2008-2023 Karel Zak <kzak@redhat.com> * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * lscpu - CPU architecture information helper */ - #include <assert.h> #include <ctype.h> #include <dirent.h> @@ -855,13 +847,15 @@ print_cpuset(struct lscpu_cxt *cxt, const char *key, cpu_set_t *set) { size_t setbuflen = 7 * cxt->maxcpus; - char setbuf[setbuflen], *p; + char *setbuf, *p; assert(set); assert(key); assert(tb); assert(cxt); + setbuf = xmalloc(setbuflen); + if (cxt->hex) { p = cpumask_create(setbuf, setbuflen, set, cxt->setsize); add_summary_s(tb, sec, key, p); @@ -869,6 +863,8 @@ print_cpuset(struct lscpu_cxt *cxt, p = cpulist_create(setbuf, setbuflen, set, cxt->setsize); add_summary_s(tb, sec, key, p); } + + free(setbuf); } static void @@ -994,18 +990,16 @@ static void print_summary(struct lscpu_cxt *cxt) /* Section: architecture */ sec = add_summary_s(tb, NULL, _("Architecture:"), cxt->arch->name); if (cxt->arch->bit32 || cxt->arch->bit64) { - char buf[32], *p = buf; + const char *p; - if (cxt->arch->bit32) { - strcpy(p, "32-bit, "); - p += 8; - } - if (cxt->arch->bit64) { - strcpy(p, "64-bit, "); - p += 8; - } - *(p - 2) = '\0'; - add_summary_s(tb, sec, _("CPU op-mode(s):"), buf); + if (cxt->arch->bit32 && cxt->arch->bit64) + p = "32-bit, 64-bit"; + else if (cxt->arch->bit32) + p = "32-bit"; + else + p = "64-bit"; + + add_summary_s(tb, sec, _("CPU op-mode(s):"), p); } if (ct && ct->addrsz) add_summary_s(tb, sec, _("Address sizes:"), ct->addrsz); @@ -1194,7 +1188,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --hierarchic[=when] use subsections in summary (auto, never, always)\n"), out); fputs(_(" --output-all print all available columns for -e, -p or -C\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(25)); + fprintf(out, USAGE_HELP_OPTIONS(25)); fputs(_("\nAvailable output columns for -e or -p:\n"), out); for (i = 0; i < ARRAY_SIZE(coldescs_cpu); i++) @@ -1204,7 +1198,7 @@ static void __attribute__((__noreturn__)) usage(void) for (i = 0; i < ARRAY_SIZE(coldescs_cache); i++) fprintf(out, " %13s %s\n", coldescs_cache[i].name, _(coldescs_cache[i].help)); - printf(USAGE_MAN_TAIL("lscpu(1)")); + fprintf(out, USAGE_MAN_TAIL("lscpu(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h index 1a8cfce..2c6a1d1 100644 --- a/sys-utils/lscpu.h +++ b/sys-utils/lscpu.h @@ -1,3 +1,14 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2013 Ondrej Oprala <ooprala@redhat.com> + * Copyright (C) 2013-2023 Karel Zak <kzak@redhat.com> + */ #ifndef LSCPU_H #define LSCPU_H diff --git a/sys-utils/lsipc.1 b/sys-utils/lsipc.1 index e55fc04..31f34ac 100644 --- a/sys-utils/lsipc.1 +++ b/sys-utils/lsipc.1 @@ -2,12 +2,12 @@ .\" Title: lsipc .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "LSIPC" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "LSIPC" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/lsipc.c b/sys-utils/lsipc.c index 0f3cd94..515788c 100644 --- a/sys-utils/lsipc.c +++ b/sys-utils/lsipc.c @@ -136,7 +136,7 @@ struct lsipc_control { }; struct lsipc_coldesc { - const char *name; + const char * const name; const char *help; const char *pretty_name; @@ -320,7 +320,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(26)); + fprintf(out, USAGE_HELP_OPTIONS(26)); fprintf(out, _("\nGeneric columns:\n")); for (i = COLDESC_IDX_GEN_FIRST; i <= COLDESC_IDX_GEN_LAST; i++) @@ -342,7 +342,7 @@ static void __attribute__((__noreturn__)) usage(void) for (i = COLDESC_IDX_SUM_FIRST; i <= COLDESC_IDX_SUM_LAST; i++) fprintf(out, " %14s %s\n", coldescs[i].name, _(coldescs[i].help)); - printf(USAGE_MAN_TAIL("lsipc(1)")); + fprintf(out, USAGE_MAN_TAIL("lsipc(1)")); exit(EXIT_SUCCESS); } @@ -717,16 +717,18 @@ static void do_sem(int id, struct lsipc_control *ctl, struct libscols_table *tb) static void do_sem_global(struct lsipc_control *ctl, struct libscols_table *tb) { - struct sem_data *semds, *semdsp; + struct sem_data *semds; struct ipc_limits lim; int nsems = 0, nsets = 0; ipc_sem_get_limits(&lim); if (ipc_sem_get_info(-1, &semds) > 0) { - for (semdsp = semds; semdsp->next != NULL; semdsp = semdsp->next) { + struct sem_data *p; + + for (p = semds; p->next != NULL; p = p->next) { ++nsets; - nsems += semds->sem_nsems; + nsems += p->sem_nsems; } ipc_sem_free_info(semds); } @@ -1354,4 +1356,3 @@ int main(int argc, char *argv[]) return EXIT_SUCCESS; } - diff --git a/sys-utils/lsirq.1 b/sys-utils/lsirq.1 index 6c555b1..e15a402 100644 --- a/sys-utils/lsirq.1 +++ b/sys-utils/lsirq.1 @@ -2,12 +2,12 @@ .\" Title: lsirq .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "LSIRQ" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "LSIRQ" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/lsirq.c b/sys-utils/lsirq.c index 375476d..2b283d3 100644 --- a/sys-utils/lsirq.c +++ b/sys-utils/lsirq.c @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: LGPL-2.1-or-later + * * lsirq - utility to display kernel interrupt information. * * Copyright (C) 2019 zhenwei pi <pizhenwei@bytedance.com> @@ -8,15 +10,6 @@ * 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. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <ctype.h> #include <errno.h> @@ -57,7 +50,7 @@ static void __attribute__((__noreturn__)) usage(void) printf(_(" %s [options]\n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, stdout); - puts(_("Utility to display kernel interrupt information.")); + fputsln(_("Utility to display kernel interrupt information."), stdout); fputs(USAGE_OPTIONS, stdout); fputs(_(" -J, --json use JSON output format\n"), stdout); @@ -67,12 +60,12 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -s, --sort <column> specify sort column\n"), stdout); fputs(_(" -S, --softirq show softirqs instead of interrupts\n"), stdout); fputs(USAGE_SEPARATOR, stdout); - printf(USAGE_HELP_OPTIONS(22)); + fprintf(stdout, USAGE_HELP_OPTIONS(22)); fputs(USAGE_COLUMNS, stdout); irq_print_columns(stdout, 1); - printf(USAGE_MAN_TAIL("lsirq(1)")); + fprintf(stdout, USAGE_MAN_TAIL("lsirq(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/lsmem.1 b/sys-utils/lsmem.1 index 6bb47f0..510e66a 100644 --- a/sys-utils/lsmem.1 +++ b/sys-utils/lsmem.1 @@ -2,12 +2,12 @@ .\" Title: lsmem .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "LSMEM" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "LSMEM" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c index 379d616..3b5ca19 100644 --- a/sys-utils/lsmem.c +++ b/sys-utils/lsmem.c @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: GPL-2.0-or-later + * * lsmem - Show memory configuration * * Copyright IBM Corp. 2016 @@ -8,15 +10,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <c.h> #include <nls.h> @@ -477,7 +470,7 @@ static void read_info(struct lsmem *lsmem) continue; } lsmem->nblocks++; - lsmem->blocks = xrealloc(lsmem->blocks, lsmem->nblocks * sizeof(blk)); + lsmem->blocks = xreallocarray(lsmem->blocks, lsmem->nblocks, sizeof(blk)); *&lsmem->blocks[lsmem->nblocks - 1] = blk; } } @@ -535,13 +528,13 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --summary[=when] print summary information (never,always or only)\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(22)); + fprintf(out, USAGE_HELP_OPTIONS(22)); fputs(USAGE_COLUMNS, out); for (i = 0; i < ARRAY_SIZE(coldescs); i++) fprintf(out, " %10s %s\n", coldescs[i].name, _(coldescs[i].help)); - printf(USAGE_MAN_TAIL("lsmem(1)")); + fprintf(out, USAGE_MAN_TAIL("lsmem(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/lsns.8 b/sys-utils/lsns.8 index 7823947..7c2147f 100644 --- a/sys-utils/lsns.8 +++ b/sys-utils/lsns.8 @@ -2,12 +2,12 @@ .\" Title: lsns .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "LSNS" "8" "2023-11-21" "util\-linux 2.39.3" "System Administration" +.TH "LSNS" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c index 5b909d4..e68bdbe 100644 --- a/sys-utils/lsns.c +++ b/sys-utils/lsns.c @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: GPL-2.0-or-later + * * lsns(8) - list system namespaces * * Copyright (C) 2015 Karel Zak <kzak@redhat.com> @@ -7,15 +9,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdio.h> #include <string.h> @@ -1302,13 +1295,13 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -T, --tree <rel> use tree format (parent, owner, or process)\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_HELP_OPTIONS(24)); fputs(USAGE_COLUMNS, out); for (i = 0; i < ARRAY_SIZE(infos); i++) fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help)); - printf(USAGE_MAN_TAIL("lsns(8)")); + fprintf(out, USAGE_MAN_TAIL("lsns(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/meson.build b/sys-utils/meson.build index ee00d1d..e683253 100644 --- a/sys-utils/meson.build +++ b/sys-utils/meson.build @@ -36,6 +36,10 @@ renice_sources = files( 'renice.c', ) +setpgid_sources = files( + 'setpgid.c', +) + setsid_sources = files( 'setsid.c', ) @@ -181,6 +185,9 @@ nsenter_sources = files( setpriv_sources = files( 'setpriv.c', ) +if LINUX and conf.get('HAVE_LINUX_LANDLOCK_H').to_string() == '1' + setpriv_sources += files('setpriv-landlock.c') +endif flock_sources = files( 'flock.c', diff --git a/sys-utils/mount.8 b/sys-utils/mount.8 index 1a09d1d..e1a5a4b 100644 --- a/sys-utils/mount.8 +++ b/sys-utils/mount.8 @@ -2,12 +2,12 @@ .\" Title: mount .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-12-01 +.\" Date: 2024-03-20 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "MOUNT" "8" "2023-12-01" "util\-linux 2.39.3" "System Administration" +.TH "MOUNT" "8" "2024-03-20" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -387,11 +387,11 @@ Note that \fBmount\fP does not pass this option to the \fB/sbin/mount.\fP\fItype .sp \fB\-f, \-\-fake\fP .RS 4 -Causes everything to be done except for the mount\-related system calls. The \-\-fake option was originally designed to write an entry to /etc/mtab without actually mounting. +Causes everything to be done except for the mount\-related system calls. The \fB\-\-fake\fP option was originally designed to write an entry to \fI/etc/mtab\fP without actually mounting. .sp -The /etc/mtab is no longer maintained in userspace, and starting from version 2.39, the mount operation can be a complex chain of operations with dependencies between the syscalls. The \-\-fake option forces libmount to skip all mount source preparation, mount option analysis, and the actual mounting process. +The \fI/etc/mtab\fP is no longer maintained in userspace, and starting from version 2.39, the mount operation can be a complex chain of operations with dependencies between the syscalls. The \fB\-\-fake\fP option forces libmount to skip all mount source preparation, mount option analysis, and the actual mounting process. .sp -The difference between fake and non\-fake execution is huge. This is the reason why the \-\-fake option has minimal significance for the current mount(8) implementation and it is maintained mostly for backward compatibility. +The difference between fake and non\-fake execution is huge. This is the reason why the \fB\-\-fake\fP option has minimal significance for the current \fBmount\fP(8) implementation and it is maintained mostly for backward compatibility. .RE .sp \fB\-i, \-\-internal\-only\fP @@ -419,6 +419,16 @@ Move a subtree to some other place. See above, the subsection \fBThe move operat Allow to make a target directory (mountpoint) if it does not exist yet. Alias to "\-o X\-mount.mkdir[=mode]", the default mode is 0755. For more details see \fBX\-mount.mkdir\fP below. .RE .sp +\fB\-\-map\-groups\fP, \fB\-\-map\-users\fP \fIinner\fP:_outer_:_count_ +.RS 4 +Add the specified user/group mapping to an \fBX\-mount.idmap\fP map. These options can be given multiple times to build up complete mappings for users and groups. For more details see \fBX\-mount.idmap\fP below. +.RE +.sp +\fB\-\-map\-users\fP /proc/\fIPID\fP/ns/user +.RS 4 +Use the specified user namespace for user and group mapping in an id\-mapped mount. This is an alias for "\-o X\-mount.idmap=/proc/\fIPID\fP/ns/user" and cannot be used twice nor together with the \fIinner\fP:_outer_:_count_ option format above. For more details see \fBX\-mount.idmap\fP below. +.RE +.sp \fB\-n\fP, \fB\-\-no\-mtab\fP .RS 4 Mount without writing in \fI/etc/mtab\fP. This is necessary for example when \fI/etc\fP is on a read\-only filesystem. @@ -463,7 +473,7 @@ For more details, see the \fBFILESYSTEM\-INDEPENDENT MOUNT OPTIONS\fP and \fBFIL .sp \fB\-\-onlyonce\fP .RS 4 -Forces mount command to check if the filesystem is already mounted. This behavior is the default for \fB\-\-all\fP; otherwise, it depends on the kernel filesystem driver. Some filesystems may be mounted more than once on the same mount point (e.g. tmpfs). +Forces \fBmount\fP command to check if the filesystem is already mounted. This behavior is the default for \fB\-\-all\fP; otherwise, it depends on the kernel filesystem driver. Some filesystems may be mounted more than once on the same mount point (e.g. tmpfs). .RE .sp \fB\-\-options\-mode\fP \fImode\fP @@ -667,15 +677,21 @@ The \fBrootcontext=\fP option allows you to explicitly label the root inode of a Note that the kernel rejects any remount request that includes the context option, \fBeven\fP when unchanged from the current context. .sp \fBWarning: the\fP \fIcontext\fP \fBvalue might contain commas\fP, in which case the value has to be properly quoted, otherwise \fBmount\fP will interpret the comma as a separator between mount options. Don\(cqt forget that the shell strips off quotes and thus \fBdouble quoting is required\fP. For example: -.RE .RS 3 .ll -.6i .sp +.if n .RS 4 +.nf +.fam C mount \-t tmpfs none /mnt \-o \(rs \*(Aqcontext="system_u:object_r:tmp_t:s0:c127,c456",noexec\*(Aq +.fam +.fi +.if n .RE .br .RE .ll +.RE .sp For more details, see \fBselinux\fP(8). .sp @@ -944,7 +960,7 @@ The \fIlist\fP is a comma\-separated list of the filesystem names. The automatic filesystem detection is triggered by the "auto" filesystem type or when the filesystem type is not specified. .sp -Thy \fIlist\fP follows how mount +The \fIlist\fP follows how mount evaluates type patterns (see \fB\-t\fP for more details). Only specified filesystem types are allowed, or all specified types are forbidden if the list is prefixed by "no". @@ -2363,13 +2379,12 @@ For example commands: .if n .RS 4 .nf .fam C -mksquashfs /etc /tmp/etc.squashfs -dd if=/dev/zero of=/tmp/etc.hash bs=1M count=10 -veritysetup format /tmp/etc.squashfs /tmp/etc.hash -openssl smime \-sign \-in <hash> \-nocerts \-inkey private.key \(rs +mksquashfs /etc /tmp/etc.raw +veritysetup format /tmp/etc.raw /tmp/etc.verity \-\-root\-hash\-file=/tmp/etc.roothash +openssl smime \-sign \-in /tmp/etc.roothash \-nocerts \-inkey private.key \(rs \-signer private.crt \-noattr \-binary \-outform der \-out /tmp/etc.roothash.p7s -mount \-o verity.hashdevice=/tmp/etc.hash,verity.roothash=<hash>,\(rs -verity.roothashsig=/tmp/etc.roothash.p7s /tmp/etc.squashfs /mnt +mount \-o verity.hashdevice=/tmp/etc.verity,verity.roothashfile=/tmp/etc.roothash,\(rs +verity.roothashsig=/tmp/etc.roothash.p7s /tmp/etc.raw /mnt .fam .fi .if n .RE @@ -2473,7 +2488,7 @@ The command \fBmount\fP does not pass the mount options \fBunbindable\fP, \fBrun .sp \fBLIBMOUNT_FORCE_MOUNT2\fP={always|never|auto} .RS 4 -force to use classic mount(2) system call (requires support for new file descriptors based mount API). The default is \fBauto\fP; in this case, libmount tries to be smart and use classic mount(2) only for well\-known issues. If the new mount API is unavailable, libmount can still use traditional mount(2), although LIBMOUNT_FORCE_MOUNT2 is set to \fBnever\fP. +force to use classic \fBmount\fP(2) system call (requires support for new file descriptors based mount API). The default is \fBauto\fP; in this case, libmount tries to be smart and use classic \fBmount\fP(2) only for well\-known issues. If the new mount API is unavailable, libmount can still use traditional \fBmount\fP(2), although LIBMOUNT_FORCE_MOUNT2 is set to \fBnever\fP. .RE .sp \fBLIBMOUNT_FSTAB\fP=<path> diff --git a/sys-utils/mount.8.adoc b/sys-utils/mount.8.adoc index 71e3723..ba8b45a 100644 --- a/sys-utils/mount.8.adoc +++ b/sys-utils/mount.8.adoc @@ -325,11 +325,11 @@ Note that *mount* does not pass this option to the **/sbin/mount.**__type__ help (Used in conjunction with *-a*.) Fork off a new incarnation of *mount* for each device. This will do the mounts on different devices or different NFS servers in parallel. This has the advantage that it is faster; also NFS timeouts proceed in parallel. A disadvantage is that the order of the mount operations is undefined. Thus, you cannot use this option if you want to mount both _/usr_ and _/usr/spool_. *-f, --fake*:: -Causes everything to be done except for the mount-related system calls. The --fake option was originally designed to write an entry to /etc/mtab without actually mounting. +Causes everything to be done except for the mount-related system calls. The *--fake* option was originally designed to write an entry to _/etc/mtab_ without actually mounting. + -The /etc/mtab is no longer maintained in userspace, and starting from version 2.39, the mount operation can be a complex chain of operations with dependencies between the syscalls. The --fake option forces libmount to skip all mount source preparation, mount option analysis, and the actual mounting process. +The _/etc/mtab_ is no longer maintained in userspace, and starting from version 2.39, the mount operation can be a complex chain of operations with dependencies between the syscalls. The *--fake* option forces libmount to skip all mount source preparation, mount option analysis, and the actual mounting process. + -The difference between fake and non-fake execution is huge. This is the reason why the --fake option has minimal significance for the current mount(8) implementation and it is maintained mostly for backward compatibility. +The difference between fake and non-fake execution is huge. This is the reason why the *--fake* option has minimal significance for the current *mount*(8) implementation and it is maintained mostly for backward compatibility. *-i, --internal-only*:: Don't call the **/sbin/mount.**__filesystem__ helper even if it exists. @@ -346,6 +346,12 @@ Move a subtree to some other place. See above, the subsection *The move operatio *-m*, **--mkdir**[=__mode__]:: Allow to make a target directory (mountpoint) if it does not exist yet. Alias to "-o X-mount.mkdir[=mode]", the default mode is 0755. For more details see *X-mount.mkdir* below. +*--map-groups*, *--map-users* _inner_:_outer_:_count_:: +Add the specified user/group mapping to an *X-mount.idmap* map. These options can be given multiple times to build up complete mappings for users and groups. For more details see *X-mount.idmap* below. + +*--map-users* /proc/_PID_/ns/user:: +Use the specified user namespace for user and group mapping in an id-mapped mount. This is an alias for "-o X-mount.idmap=/proc/_PID_/ns/user" and cannot be used twice nor together with the _inner_:_outer_:_count_ option format above. For more details see *X-mount.idmap* below. + *-n*, *--no-mtab*:: Mount without writing in _/etc/mtab_. This is necessary for example when _/etc_ is on a read-only filesystem. @@ -381,7 +387,7 @@ Note that the order of the options matters, as the last option wins if there are For more details, see the *FILESYSTEM-INDEPENDENT MOUNT OPTIONS* and *FILESYSTEM-SPECIFIC MOUNT OPTIONS* sections. *--onlyonce*:: -Forces mount command to check if the filesystem is already mounted. This behavior is the default for *--all*; otherwise, it depends on the kernel filesystem driver. Some filesystems may be mounted more than once on the same mount point (e.g. tmpfs). +Forces *mount* command to check if the filesystem is already mounted. This behavior is the default for *--all*; otherwise, it depends on the kernel filesystem driver. Some filesystems may be mounted more than once on the same mount point (e.g. tmpfs). *--options-mode* _mode_:: Controls how to combine options from _fstab_/_mtab_ with options from the command line. _mode_ can be one of *ignore*, *append*, *prepend* or *replace*. For example, *append* means that options from _fstab_ are appended to options from the command line. The default value is *prepend* -- it means command line options are evaluated after _fstab_ options. Note that the last option wins if there are conflicting ones. @@ -521,9 +527,12 @@ The *rootcontext=* option allows you to explicitly label the root inode of a FS Note that the kernel rejects any remount request that includes the context option, *even* when unchanged from the current context. + *Warning: the* _context_ *value might contain commas*, in which case the value has to be properly quoted, otherwise *mount* will interpret the comma as a separator between mount options. Don't forget that the shell strips off quotes and thus *double quoting is required*. For example: ++ ____ +.... mount -t tmpfs none /mnt -o \ 'context="system_u:object_r:tmp_t:s0:c127,c456",noexec' +.... ____ For more details, see *selinux*(8). @@ -684,7 +693,7 @@ The _list_ is a comma-separated list of the filesystem names. The automatic filesystem detection is triggered by the "auto" filesystem type or when the filesystem type is not specified. + -Thy _list_ follows how mount +The _list_ follows how mount evaluates type patterns (see *-t* for more details). Only specified filesystem types are allowed, or all specified types are forbidden if the list is prefixed by "no". @@ -1529,13 +1538,12 @@ Supported since util-linux v2.35. For example commands: .... -mksquashfs /etc /tmp/etc.squashfs -dd if=/dev/zero of=/tmp/etc.hash bs=1M count=10 -veritysetup format /tmp/etc.squashfs /tmp/etc.hash -openssl smime -sign -in <hash> -nocerts -inkey private.key \ +mksquashfs /etc /tmp/etc.raw +veritysetup format /tmp/etc.raw /tmp/etc.verity --root-hash-file=/tmp/etc.roothash +openssl smime -sign -in /tmp/etc.roothash -nocerts -inkey private.key \ -signer private.crt -noattr -binary -outform der -out /tmp/etc.roothash.p7s -mount -o verity.hashdevice=/tmp/etc.hash,verity.roothash=<hash>,\ -verity.roothashsig=/tmp/etc.roothash.p7s /tmp/etc.squashfs /mnt +mount -o verity.hashdevice=/tmp/etc.verity,verity.roothashfile=/tmp/etc.roothash,\ +verity.roothashsig=/tmp/etc.roothash.p7s /tmp/etc.raw /mnt .... create squashfs image from _/etc_ directory, verity hash device and mount verified filesystem image to _/mnt_. The kernel will verify that the root hash is signed by a key from the kernel keyring if roothashsig is used. @@ -1615,7 +1623,7 @@ The command *mount* does not pass the mount options *unbindable*, *runbindable*, == ENVIRONMENT *LIBMOUNT_FORCE_MOUNT2*={always|never|auto}:: -force to use classic mount(2) system call (requires support for new file descriptors based mount API). The default is *auto*; in this case, libmount tries to be smart and use classic mount(2) only for well-known issues. If the new mount API is unavailable, libmount can still use traditional mount(2), although LIBMOUNT_FORCE_MOUNT2 is set to *never*. +force to use classic *mount*(2) system call (requires support for new file descriptors based mount API). The default is *auto*; in this case, libmount tries to be smart and use classic *mount*(2) only for well-known issues. If the new mount API is unavailable, libmount can still use traditional *mount*(2), although LIBMOUNT_FORCE_MOUNT2 is set to *never*. *LIBMOUNT_FSTAB*=<path>:: overrides the default location of the _fstab_ file (ignored for suid) diff --git a/sys-utils/mount.c b/sys-utils/mount.c index dba6fca..50e66de 100644 --- a/sys-utils/mount.c +++ b/sys-utils/mount.c @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: GPL-2.0-or-later + * * mount(8) -- mount a filesystem * * Copyright (C) 2011 Red Hat, Inc. All rights reserved. @@ -8,17 +10,7 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include <stdio.h> #include <stdlib.h> #include <errno.h> @@ -482,7 +474,7 @@ static void __attribute__((__noreturn__)) usage(void) FILE *out = stdout; fputs(USAGE_HEADER, out); - printf(_( + fprintf(out, _( " %1$s [-lhV]\n" " %1$s -a [options]\n" " %1$s [options] [--source] <source> | [--target] <directory>\n" @@ -501,6 +493,12 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -T, --fstab <path> alternative file to /etc/fstab\n"), out); fputs(_(" -i, --internal-only don't call the mount.<type> helpers\n"), out); fputs(_(" -l, --show-labels show also filesystem labels\n"), out); + fputs(_(" --map-groups <inner>:<outer>:<count>\n" + " add the specified GID map to an ID-mapped mount\n"), out); + fputs(_(" --map-users <inner>:<outer>:<count>\n" + " add the specified UID map to an ID-mapped mount\n"), out); + fputs(_(" --map-users /proc/<pid>/ns/user\n" + " specify the user namespace for an ID-mapped mount\n"), out); fputs(_(" -m, --mkdir[=<mode>] alias to '-o X-mount.mkdir[=<mode>]'\n"), out); fputs(_(" -n, --no-mtab don't write to /etc/mtab\n"), out); fputs(_(" --options-mode <mode>\n" @@ -523,7 +521,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -N, --namespace <ns> perform mount in another namespace\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(25)); + fprintf(out, USAGE_HELP_OPTIONS(25)); fputs(USAGE_SEPARATOR, out); fputs(_("Source:\n"), out); @@ -552,7 +550,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --make-rprivate recursively mark a whole subtree as private\n"), out); fputs(_(" --make-runbindable recursively mark a whole subtree as unbindable\n"), out); - printf(USAGE_MAN_TAIL("mount(8)")); + fprintf(out, USAGE_MAN_TAIL("mount(8)")); exit(MNT_EX_SUCCESS); } @@ -615,6 +613,7 @@ int main(int argc, char **argv) int c, rc = MNT_EX_SUCCESS, all = 0, show_labels = 0; struct libmnt_context *cxt; struct libmnt_table *fstab = NULL; + char *idmap = NULL; char *srcbuf = NULL; char *types = NULL; int oper = 0, is_move = 0; @@ -630,6 +629,8 @@ int main(int argc, char **argv) MOUNT_OPT_RSLAVE, MOUNT_OPT_RPRIVATE, MOUNT_OPT_RUNBINDABLE, + MOUNT_OPT_MAP_GROUPS, + MOUNT_OPT_MAP_USERS, MOUNT_OPT_TARGET, MOUNT_OPT_TARGET_PREFIX, MOUNT_OPT_SOURCE, @@ -668,6 +669,8 @@ int main(int argc, char **argv) { "make-rslave", no_argument, NULL, MOUNT_OPT_RSLAVE }, { "make-rprivate", no_argument, NULL, MOUNT_OPT_RPRIVATE }, { "make-runbindable", no_argument, NULL, MOUNT_OPT_RUNBINDABLE }, + { "map-groups", required_argument, NULL, MOUNT_OPT_MAP_GROUPS }, + { "map-users", required_argument, NULL, MOUNT_OPT_MAP_USERS }, { "mkdir", optional_argument, NULL, 'm' }, { "no-canonicalize", no_argument, NULL, 'c' }, { "internal-only", no_argument, NULL, 'i' }, @@ -850,6 +853,23 @@ int main(int argc, char **argv) append_option(cxt, "runbindable", NULL); propa = 1; break; + case MOUNT_OPT_MAP_GROUPS: + case MOUNT_OPT_MAP_USERS: + if (*optarg == '=') + optarg++; + if (idmap && (*idmap == '/' || *optarg == '/')) { + warnx(_("bad usage")); + errtryhelp(MNT_EX_USAGE); + } else if (*optarg == '/') { + idmap = xstrdup(optarg); + } else { + char *tmp; + xasprintf(&tmp, "%s%s%s%s", idmap ? idmap : "", idmap ? " " : "", + c == MOUNT_OPT_MAP_GROUPS ? "g:" : "u:", optarg); + free(idmap); + idmap = tmp; + } + break; case MOUNT_OPT_TARGET: mnt_context_disable_swapmatch(cxt, 1); mnt_context_set_target(cxt, optarg); @@ -898,6 +918,9 @@ int main(int argc, char **argv) argc -= optind; argv += optind; + if (idmap) + append_option(cxt, "X-mount.idmap", idmap); + optmode |= optmode_mode | optmode_src; if (optmode) { if (!optmode_mode) diff --git a/sys-utils/mountpoint.1 b/sys-utils/mountpoint.1 index b14e3eb..2df1d5d 100644 --- a/sys-utils/mountpoint.1 +++ b/sys-utils/mountpoint.1 @@ -2,12 +2,12 @@ .\" Title: mountpoint .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "MOUNTPOINT" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "MOUNTPOINT" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/mountpoint.c b/sys-utils/mountpoint.c index b9904f3..8f0b0d5 100644 --- a/sys-utils/mountpoint.c +++ b/sys-utils/mountpoint.c @@ -1,9 +1,5 @@ /* - * mountpoint(1) - see if a directory is a mountpoint - * - * This is libmount based reimplementation of the mountpoint(1) - * from sysvinit project. - * + * SPDX-License-Identifier: GPL-2.0-or-later * * Copyright (C) 2011 Red Hat, Inc. All rights reserved. * Written by Karel Zak <kzak@redhat.com> @@ -13,16 +9,11 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * mountpoint(1) - see if a directory is a mountpoint * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * This is libmount based reimplementation of the mountpoint(1) + * from sysvinit project. */ - #include <stdio.h> #include <stdlib.h> #include <errno.h> @@ -130,8 +121,8 @@ static void __attribute__((__noreturn__)) usage(void) " -d, --fs-devno print maj:min device number of the filesystem\n" " -x, --devno print maj:min device number of the block device\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(20)); - printf(USAGE_MAN_TAIL("mountpoint(1)")); + fprintf(out, USAGE_HELP_OPTIONS(20)); + fprintf(out, USAGE_MAN_TAIL("mountpoint(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/nsenter.1 b/sys-utils/nsenter.1 index add08ed..d5cac3f 100644 --- a/sys-utils/nsenter.1 +++ b/sys-utils/nsenter.1 @@ -2,12 +2,12 @@ .\" Title: nsenter .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-12-01 +.\" Date: 2024-03-20 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "NSENTER" "1" "2023-12-01" "util\-linux 2.39.3" "User Commands" +.TH "NSENTER" "1" "2024-03-20" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -173,6 +173,12 @@ Enter the PID namespace. If no file is specified, enter the PID namespace of the Enter the user namespace. If no file is specified, enter the user namespace of the target process. If \fIfile\fP is specified, enter the user namespace specified by \fIfile\fP. See also the \fB\-\-setuid\fP and \fB\-\-setgid\fP options. .RE .sp +\fB\-\-user\-parent\fP +.RS 4 +Enter the parent user namespace. Parent user namespace will be acquired from any other enabled namespace. +If combined with \fB\-\-user\fP option the parent user namespace will be fetched from the user namespace and replace it. +.RE +.sp \fB\-C\fP, \fB\-\-cgroup\fP[=\fIfile\fP] .RS 4 Enter the cgroup namespace. If no file is specified, enter the cgroup namespace of the target process. If \fIfile\fP is specified, enter the cgroup namespace specified by \fIfile\fP. @@ -197,6 +203,11 @@ Set the user ID which will be used in the entered namespace. If the argument "follow" is specified the UID of the target process is used. .RE .sp +\fB\-\-keep\-caps\fP +.RS 4 +When the \fB\-\-user\fP option is given, ensure that capabilities granted in the user namespace are preserved in the child process. +.RE +.sp \fB\-\-preserve\-credentials\fP .RS 4 Don\(cqt modify UID and GID when enter user namespace. The default is to drops supplementary groups and sets GID and UID to 0. @@ -232,6 +243,11 @@ Do not fork before exec\(cqing the specified program. By default, when entering Set the SELinux security context used for executing a new process according to already running process specified by \fB\-\-target\fP PID. (The util\-linux has to be compiled with SELinux support otherwise the option is unavailable.) .RE .sp +\fB\-c\fP, \fB\-\-join\-cgroup\fP +.RS 4 +Add the initiated process to the cgroup of the target process. +.RE +.sp \fB\-h\fP, \fB\-\-help\fP .RS 4 Display help text and exit. @@ -241,6 +257,9 @@ Display help text and exit. .RS 4 Print version and exit. .RE +.SH "NOTES" +.sp +The \fB\-\-user\-parent\fP option requires Linux 4.9 or higher, older kernels will raise inappropriate ioctl for device error. .SH "AUTHORS" .sp .MTO "biederm\(atxmission.com" "Eric Biederman" "," diff --git a/sys-utils/nsenter.1.adoc b/sys-utils/nsenter.1.adoc index c053526..58dd125 100644 --- a/sys-utils/nsenter.1.adoc +++ b/sys-utils/nsenter.1.adoc @@ -97,6 +97,10 @@ Enter the PID namespace. If no file is specified, enter the PID namespace of the *-U*, *--user*[=_file_]:: Enter the user namespace. If no file is specified, enter the user namespace of the target process. If _file_ is specified, enter the user namespace specified by _file_. See also the *--setuid* and *--setgid* options. +*--user-parent*:: +Enter the parent user namespace. Parent user namespace will be acquired from any other enabled namespace. +If combined with *--user* option the parent user namespace will be fetched from the user namespace and replace it. + *-C*, *--cgroup*[=_file_]:: Enter the cgroup namespace. If no file is specified, enter the cgroup namespace of the target process. If _file_ is specified, enter the cgroup namespace specified by _file_. @@ -113,6 +117,9 @@ Set the user ID which will be used in the entered namespace. *nsenter* always sets UID for user namespaces, the default is 0. If the argument "follow" is specified the UID of the target process is used. +*--keep-caps*:: +When the *--user* option is given, ensure that capabilities granted in the user namespace are preserved in the child process. + *--preserve-credentials*:: Don't modify UID and GID when enter user namespace. The default is to drops supplementary groups and sets GID and UID to 0. @@ -134,8 +141,15 @@ Do not fork before exec'ing the specified program. By default, when entering a P *-Z*, *--follow-context*:: Set the SELinux security context used for executing a new process according to already running process specified by *--target* PID. (The util-linux has to be compiled with SELinux support otherwise the option is unavailable.) +*-c*, *--join-cgroup*:: +Add the initiated process to the cgroup of the target process. + include::man-common/help-version.adoc[] +== NOTES + +The *--user-parent* option requires Linux 4.9 or higher, older kernels will raise inappropriate ioctl for device error. + == AUTHORS mailto:biederm@xmission.com[Eric Biederman], diff --git a/sys-utils/nsenter.c b/sys-utils/nsenter.c index 56dbf17..8f7bac9 100644 --- a/sys-utils/nsenter.c +++ b/sys-utils/nsenter.c @@ -1,22 +1,14 @@ /* - * nsenter(1) - command-line interface for setns(2) - * - * Copyright (C) 2012-2013 Eric Biederman <ebiederm@xmission.com> + * SPDX-License-Identifier: GPL-2.0-only * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; version 2. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * Copyright (C) 2012-2023 Eric Biederman <ebiederm@xmission.com> * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * nsenter(1) - command-line interface for setns(2) */ - #include <dirent.h> #include <errno.h> #include <getopt.h> @@ -30,6 +22,15 @@ #include <sys/wait.h> #include <grp.h> #include <sys/stat.h> +#include <sys/statfs.h> + +#include <sys/ioctl.h> +#ifdef HAVE_LINUX_NSFS_H +# include <linux/nsfs.h> +#endif +#ifndef NS_GET_USERNS +# define NS_GET_USERNS _IO(0xb7, 0x1) +#endif #ifdef HAVE_LIBSELINUX # include <selinux/selinux.h> @@ -45,6 +46,9 @@ #include "xalloc.h" #include "all-io.h" #include "env.h" +#include "caputils.h" +#include "statfs_magic.h" +#include "pathnames.h" static struct namespace_file { int nstype; @@ -91,22 +95,25 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -p, --pid[=<file>] enter pid namespace\n"), out); fputs(_(" -C, --cgroup[=<file>] enter cgroup namespace\n"), out); fputs(_(" -U, --user[=<file>] enter user namespace\n"), out); + fputs(_(" --user-parent enter parent user namespace\n"), out); fputs(_(" -T, --time[=<file>] enter time namespace\n"), out); fputs(_(" -S, --setuid[=<uid>] set uid in entered namespace\n"), out); fputs(_(" -G, --setgid[=<gid>] set gid in entered namespace\n"), out); fputs(_(" --preserve-credentials do not touch uids or gids\n"), out); + fputs(_(" --keep-caps retain capabilities granted in user namespaces\n"), out); fputs(_(" -r, --root[=<dir>] set the root directory\n"), out); fputs(_(" -w, --wd[=<dir>] set the working directory\n"), out); fputs(_(" -W, --wdns <dir> set the working directory in namespace\n"), out); fputs(_(" -e, --env inherit environment variables from target process\n"), out); fputs(_(" -F, --no-fork do not fork before exec'ing <program>\n"), out); + fputs(_(" -c, --join-cgroup join the cgroup of the target process\n"), out); #ifdef HAVE_LIBSELINUX fputs(_(" -Z, --follow-context set SELinux context according to --target PID\n"), out); #endif fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(24)); - printf(USAGE_MAN_TAIL("nsenter(1)")); + fprintf(out, USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_MAN_TAIL("nsenter(1)")); exit(EXIT_SUCCESS); } @@ -116,6 +123,34 @@ static int root_fd = -1; static int wd_fd = -1; static int env_fd = -1; static int uid_gid_fd = -1; +static int cgroup_procs_fd = -1; + +static void set_parent_user_ns_fd(void) +{ + struct namespace_file *nsfile = NULL; + struct namespace_file *user_nsfile = NULL; + int parent_ns = -1; + + for (nsfile = namespace_files; nsfile->nstype; nsfile++) { + if (nsfile->nstype == CLONE_NEWUSER) + user_nsfile = nsfile; + + if (nsfile->fd == -1) + continue; + + parent_ns = ioctl(nsfile->fd, NS_GET_USERNS); + if (parent_ns < 0) + err(EXIT_FAILURE, _("failed to open parent ns of %s"), nsfile->name); + + break; + } + + if (parent_ns < 0) + errx(EXIT_FAILURE, _("no namespaces to get parent of")); + if (user_nsfile) + user_nsfile->fd = parent_ns; +} + static void open_target_fd(int *fd, const char *type, const char *path) { @@ -164,6 +199,55 @@ static int get_ns_ino(const char *path, ino_t *ino) return 0; } +static void open_cgroup_procs(void) +{ + char *buf = NULL, *path = NULL, *p; + int cgroup_fd = 0; + char fdpath[PATH_MAX]; + + open_target_fd(&cgroup_fd, "cgroup", optarg); + + if (read_all_alloc(cgroup_fd, &buf) < 1) + err(EXIT_FAILURE, _("failed to get cgroup path")); + + p = strtok(buf, "\n"); + if (p) + path = strrchr(p, ':'); + if (!path) + err(EXIT_FAILURE, _("failed to get cgroup path")); + path++; + + snprintf(fdpath, sizeof(fdpath), _PATH_SYS_CGROUP "/%s/cgroup.procs", path); + + if ((cgroup_procs_fd = open(fdpath, O_WRONLY | O_APPEND)) < 0) + err(EXIT_FAILURE, _("failed to open cgroup.procs")); + + free(buf); +} + +static int is_cgroup2(void) +{ + struct statfs fs_stat; + int rc; + + rc = statfs(_PATH_SYS_CGROUP, &fs_stat); + if (rc) + err(EXIT_FAILURE, _("statfs %s failed"), _PATH_SYS_CGROUP); + return F_TYPE_EQUAL(fs_stat.f_type, STATFS_CGROUP2_MAGIC); +} + +static void join_into_cgroup(void) +{ + pid_t pid; + char buf[ sizeof(stringify_value(UINT32_MAX)) ]; + int len; + + pid = getpid(); + len = snprintf(buf, sizeof(buf), "%zu", (size_t) pid); + if (write_all(cgroup_procs_fd, buf, len)) + err(EXIT_FAILURE, _("write cgroup.procs failed")); +} + static int is_usable_namespace(pid_t target, const struct namespace_file *nsfile) { char path[PATH_MAX]; @@ -232,7 +316,9 @@ static void continue_as_child(void) int main(int argc, char *argv[]) { enum { - OPT_PRESERVE_CRED = CHAR_MAX + 1 + OPT_PRESERVE_CRED = CHAR_MAX + 1, + OPT_KEEPCAPS, + OPT_USER_PARENT, }; static const struct option longopts[] = { { "all", no_argument, NULL, 'a' }, @@ -254,7 +340,10 @@ int main(int argc, char *argv[]) { "wdns", optional_argument, NULL, 'W' }, { "env", no_argument, NULL, 'e' }, { "no-fork", no_argument, NULL, 'F' }, + { "join-cgroup", no_argument, NULL, 'c'}, { "preserve-credentials", no_argument, NULL, OPT_PRESERVE_CRED }, + { "keep-caps", no_argument, NULL, OPT_KEEPCAPS }, + { "user-parent", no_argument, NULL, OPT_USER_PARENT}, #ifdef HAVE_LIBSELINUX { "follow-context", no_argument, NULL, 'Z' }, #endif @@ -269,11 +358,13 @@ int main(int argc, char *argv[]) struct namespace_file *nsfile; int c, pass, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0; bool do_rd = false, do_wd = false, do_uid = false, force_uid = false, - do_gid = false, force_gid = false, do_env = false, do_all = false; + do_gid = false, force_gid = false, do_env = false, do_all = false, + do_join_cgroup = false, do_user_parent = false; int do_fork = -1; /* unknown yet */ char *wdns = NULL; uid_t uid = 0; gid_t gid = 0; + int keepcaps = 0; struct ul_env_list *envls; #ifdef HAVE_LIBSELINUX bool selinux = 0; @@ -285,7 +376,7 @@ int main(int argc, char *argv[]) close_stdout_atexit(); while ((c = - getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::T::S:G:r::w::W::eFZ", + getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::T::S:G:r::w::W::ecFZ", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -363,6 +454,9 @@ int main(int argc, char *argv[]) case 'F': do_fork = 0; break; + case 'c': + do_join_cgroup = true; + break; case 'r': if (optarg) open_target_fd(&root_fd, "root", optarg); @@ -384,6 +478,12 @@ int main(int argc, char *argv[]) case OPT_PRESERVE_CRED: preserve_cred = 1; break; + case OPT_KEEPCAPS: + keepcaps = 1; + break; + case OPT_USER_PARENT: + do_user_parent = true; + break; #ifdef HAVE_LIBSELINUX case 'Z': selinux = 1; @@ -441,6 +541,17 @@ int main(int argc, char *argv[]) open_target_fd(&env_fd, "environ", NULL); if (do_uid || do_gid) open_target_fd(&uid_gid_fd, "", NULL); + if (do_join_cgroup) { + if (!is_cgroup2()) + errx(EXIT_FAILURE, _("--join-cgroup is only supported in cgroup v2")); + open_cgroup_procs(); + } + + /* + * Get parent userns from any available ns. + */ + if (do_user_parent) + set_parent_user_ns_fd(); /* * Update namespaces variable to contain all requested namespaces @@ -542,6 +653,10 @@ int main(int argc, char *argv[]) close(env_fd); } + // Join into the target cgroup + if (cgroup_procs_fd >= 0) + join_into_cgroup(); + if (uid_gid_fd >= 0) { struct stat st; @@ -569,6 +684,9 @@ int main(int argc, char *argv[]) err(EXIT_FAILURE, _("setuid failed")); } + if (keepcaps && (namespaces & CLONE_NEWUSER)) + cap_permitted_to_ambient(); + if (optind < argc) { execvp(argv[optind], argv + optind); errexec(argv[optind]); diff --git a/sys-utils/pivot_root.8 b/sys-utils/pivot_root.8 index 92e968f..acedea3 100644 --- a/sys-utils/pivot_root.8 +++ b/sys-utils/pivot_root.8 @@ -2,12 +2,12 @@ .\" Title: pivot_root .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "PIVOT_ROOT" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "PIVOT_ROOT" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/pivot_root.c b/sys-utils/pivot_root.c index aef1b12..e3f084c 100644 --- a/sys-utils/pivot_root.c +++ b/sys-utils/pivot_root.c @@ -1,17 +1,12 @@ /* - * pivot_root.c - Change the root file system - * - * Copyright (C) 2000 Werner Almesberger + * SPDX-License-Identifier: GPL-2.0-or-later * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2000 Werner Almesberger */ #include <err.h> #include <errno.h> @@ -38,8 +33,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_("Change the root filesystem.\n"), out); fputs(USAGE_OPTIONS, out); - printf(USAGE_HELP_OPTIONS(16)); - printf(USAGE_MAN_TAIL("pivot_root(8)")); + fprintf(out, USAGE_HELP_OPTIONS(16)); + fprintf(out, USAGE_MAN_TAIL("pivot_root(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/prlimit.1 b/sys-utils/prlimit.1 index 17f2009..68959a1 100644 --- a/sys-utils/prlimit.1 +++ b/sys-utils/prlimit.1 @@ -2,12 +2,12 @@ .\" Title: prlimit .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-12-01 +.\" Date: 2024-03-20 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "PRLIMIT" "1" "2023-12-01" "util\-linux 2.39.3" "User Commands" +.TH "PRLIMIT" "1" "2024-03-20" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -52,7 +52,7 @@ Because of the nature of limits, the soft limit must be lower or equal to the hi . sp -1 . IP \(bu 2.3 .\} -\fIsoft\fP:_hard_ Specify both limits. +\fIsoft\fP:\fIhard\fP Specify both limits. .RE .sp .RS 4 @@ -94,12 +94,12 @@ Because of the nature of limits, the soft limit must be lower or equal to the hi Do not print a header line. .RE .sp -\fB\-o, \-\-output\fP \fIlist\fP +\fB\-o\fP, \fB\-\-output\fP \fIlist\fP .RS 4 Define the output columns to use. If no output arrangement is specified, then a default set is used. Use \fB\-\-help\fP to get a list of all supported columns. .RE .sp -\fB\-p, \-\-pid\fP +\fB\-p\fP, \fB\-\-pid\fP .RS 4 Specify the process id; if none is given, the running process will be used. .RE @@ -125,82 +125,82 @@ Print version and exit. .RE .SH "RESOURCE OPTIONS" .sp -\fB\-c, \-\-core\fP[=\fIlimits\fP] +\fB\-c\fP, \fB\-\-core\fP[=\fIlimits\fP] .RS 4 Maximum size of a core file. .RE .sp -\fB\-d, \-\-data\fP[=\fIlimits\fP] +\fB\-d\fP, \fB\-\-data\fP[=\fIlimits\fP] .RS 4 Maximum data size. .RE .sp -\fB\-e, \-\-nice\fP[=\fIlimits\fP] +\fB\-e\fP, \fB\-\-nice\fP[=\fIlimits\fP] .RS 4 Maximum nice priority allowed to raise. .RE .sp -\fB\-f, \-\-fsize\fP[=\fIlimits\fP] +\fB\-f\fP, \fB\-\-fsize\fP[=\fIlimits\fP] .RS 4 Maximum file size. .RE .sp -\fB\-i, \-\-sigpending\fP[=\fIlimits\fP] +\fB\-i\fP, \fB\-\-sigpending\fP[=\fIlimits\fP] .RS 4 Maximum number of pending signals. .RE .sp -\fB\-l, \-\-memlock\fP[=\fIlimits\fP] +\fB\-l\fP, \fB\-\-memlock\fP[=\fIlimits\fP] .RS 4 Maximum locked\-in\-memory address space. .RE .sp -\fB\-m, \-\-rss\fP[=\fIlimits\fP] +\fB\-m\fP, \fB\-\-rss\fP[=\fIlimits\fP] .RS 4 Maximum Resident Set Size (RSS). .RE .sp -\fB\-n, \-\-nofile\fP[=\fIlimits\fP] +\fB\-n\fP, \fB\-\-nofile\fP[=\fIlimits\fP] .RS 4 Maximum number of open files. .RE .sp -\fB\-q, \-\-msgqueue\fP[=\fIlimits\fP] +\fB\-q\fP, \fB\-\-msgqueue\fP[=\fIlimits\fP] .RS 4 Maximum number of bytes in POSIX message queues. .RE .sp -\fB\-r, \-\-rtprio\fP[=\fIlimits\fP] +\fB\-r\fP, \fB\-\-rtprio\fP[=\fIlimits\fP] .RS 4 Maximum real\-time priority. .RE .sp -\fB\-s, \-\-stack\fP[=\fIlimits\fP] +\fB\-s\fP, \fB\-\-stack\fP[=\fIlimits\fP] .RS 4 Maximum size of the stack. .RE .sp -\fB\-t, \-\-cpu\fP[=\fIlimits\fP] +\fB\-t\fP, \fB\-\-cpu\fP[=\fIlimits\fP] .RS 4 CPU time, in seconds. .RE .sp -\fB\-u, \-\-nproc\fP[=\fIlimits\fP] +\fB\-u\fP, \fB\-\-nproc\fP[=\fIlimits\fP] .RS 4 Maximum number of processes. .RE .sp -\fB\-v, \-\-as\fP[=\fIlimits\fP] +\fB\-v\fP, \fB\-\-as\fP[=\fIlimits\fP] .RS 4 Address space limit. .RE .sp -\fB\-x, \-\-locks\fP[=\fIlimits\fP] +\fB\-x\fP, \fB\-\-locks\fP[=\fIlimits\fP] .RS 4 Maximum number of file locks held. .RE .sp -\fB\-y, \-\-rttime\fP[=\fIlimits\fP] +\fB\-y\fP, \fB\-\-rttime\fP[=\fIlimits\fP] .RS 4 Timeout for real\-time tasks. .RE diff --git a/sys-utils/prlimit.1.adoc b/sys-utils/prlimit.1.adoc index bc8c9a1..86e06a2 100644 --- a/sys-utils/prlimit.1.adoc +++ b/sys-utils/prlimit.1.adoc @@ -33,7 +33,7 @@ The _limits_ parameter is composed of a soft and a hard value, separated by a co Because of the nature of limits, the soft limit must be lower or equal to the high limit (also called the ceiling). To see all available resource limits, refer to the *RESOURCE OPTIONS* section. //TRANSLATORS: Keep {colon} untranslated. -* _soft_{colon}_hard_ Specify both limits. +* _soft_{colon}__hard__ Specify both limits. * _soft_{colon} Specify only the soft limit. * {colon}__hard__ Specify only the hard limit. * _value_ Specify both limits to the same value. @@ -43,10 +43,10 @@ Because of the nature of limits, the soft limit must be lower or equal to the hi *--noheadings*:: Do not print a header line. -*-o, --output* _list_:: +*-o*, *--output* _list_:: Define the output columns to use. If no output arrangement is specified, then a default set is used. Use *--help* to get a list of all supported columns. -*-p, --pid*:: +*-p*, *--pid*:: Specify the process id; if none is given, the running process will be used. *--raw*:: @@ -59,52 +59,52 @@ include::man-common/help-version.adoc[] == RESOURCE OPTIONS -*-c, --core*[=_limits_]:: +*-c*, *--core*[=_limits_]:: Maximum size of a core file. -*-d, --data*[=_limits_]:: +*-d*, *--data*[=_limits_]:: Maximum data size. -*-e, --nice*[=_limits_]:: +*-e*, *--nice*[=_limits_]:: Maximum nice priority allowed to raise. -*-f, --fsize*[=_limits_]:: +*-f*, *--fsize*[=_limits_]:: Maximum file size. -*-i, --sigpending*[=_limits_]:: +*-i*, *--sigpending*[=_limits_]:: Maximum number of pending signals. -*-l, --memlock*[=_limits_]:: +*-l*, *--memlock*[=_limits_]:: Maximum locked-in-memory address space. -*-m, --rss*[=_limits_]:: +*-m*, *--rss*[=_limits_]:: Maximum Resident Set Size (RSS). -*-n, --nofile*[=_limits_]:: +*-n*, *--nofile*[=_limits_]:: Maximum number of open files. -*-q, --msgqueue*[=_limits_]:: +*-q*, *--msgqueue*[=_limits_]:: Maximum number of bytes in POSIX message queues. -*-r, --rtprio*[=_limits_]:: +*-r*, *--rtprio*[=_limits_]:: Maximum real-time priority. -*-s, --stack*[=_limits_]:: +*-s*, *--stack*[=_limits_]:: Maximum size of the stack. -*-t, --cpu*[=_limits_]:: +*-t*, *--cpu*[=_limits_]:: CPU time, in seconds. -*-u, --nproc*[=_limits_]:: +*-u*, *--nproc*[=_limits_]:: Maximum number of processes. -*-v, --as*[=_limits_]:: +*-v*, *--as*[=_limits_]:: Address space limit. -*-x, --locks*[=_limits_]:: +*-x*, *--locks*[=_limits_]:: Maximum number of file locks held. -*-y, --rttime*[=_limits_]:: +*-y*, *--rttime*[=_limits_]:: Timeout for real-time tasks. == NOTES diff --git a/sys-utils/prlimit.c b/sys-utils/prlimit.c index ca69ccf..57c11fb 100644 --- a/sys-utils/prlimit.c +++ b/sys-utils/prlimit.c @@ -1,23 +1,15 @@ /* - * prlimit - get/set process resource limits. + * SPDX-License-Identifier: GPL-2.0-or-later * - * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org> * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * prlimit - get/set process resource limits. */ - #include <errno.h> #include <getopt.h> #include <stdio.h> @@ -114,14 +106,14 @@ enum { /* column names */ struct colinfo { - const char *name; /* header */ - double whint; /* width hint (N < 1 is in percent of termwidth) */ - int flags; /* SCOLS_FL_* */ - const char *help; + const char * const name; /* header */ + double whint; /* width hint (N < 1 is in percent of termwidth) */ + int flags; /* SCOLS_FL_* */ + const char *help; }; /* columns descriptions */ -static struct colinfo infos[] = { +static const struct colinfo infos[] = { [COL_RES] = { "RESOURCE", 0.25, SCOLS_FL_TRUNC, N_("resource name") }, [COL_HELP] = { "DESCRIPTION", 0.1, SCOLS_FL_TRUNC, N_("resource description")}, [COL_SOFT] = { "SOFT", 0.1, SCOLS_FL_RIGHT, N_("soft limit")}, @@ -179,7 +171,7 @@ static void __attribute__((__noreturn__)) usage(void) " --raw use the raw output format\n" " --verbose verbose output\n" ), out); - printf(USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_HELP_OPTIONS(24)); fputs(_("\nResources:\n"), out); fputs(_(" -c, --core maximum size of core files created\n" @@ -209,7 +201,7 @@ static void __attribute__((__noreturn__)) usage(void) for (i = 0; i < ARRAY_SIZE(infos); i++) fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help)); - printf(USAGE_MAN_TAIL("prlimit(1)")); + fprintf(out, USAGE_MAN_TAIL("prlimit(1)")); exit(EXIT_SUCCESS); } @@ -222,7 +214,7 @@ static inline int get_column_id(int num) return columns[num]; } -static inline struct colinfo *get_column_info(unsigned num) +static inline const struct colinfo *get_column_info(unsigned num) { return &infos[ get_column_id(num) ]; } @@ -314,7 +306,7 @@ static int show_limits(struct list_head *lims) scols_table_enable_noheadings(table, no_headings); for (i = 0; i < ncolumns; i++) { - struct colinfo *col = get_column_info(i); + const struct colinfo *col = get_column_info(i); if (!scols_table_new_column(table, col->name, col->whint, col->flags)) err(EXIT_FAILURE, _("failed to allocate output column")); @@ -455,8 +447,10 @@ static int get_range(char *str, rlim_t *soft, rlim_t *hard, int *found) } *found |= PRLIMIT_SOFT | PRLIMIT_HARD; - } else /* <value> */ + } else if (!*end) /* <value> */ *found |= PRLIMIT_SOFT | PRLIMIT_HARD; + else + return -1; return 0; } diff --git a/sys-utils/readprofile.8 b/sys-utils/readprofile.8 index 92bfd17..8a21c1e 100644 --- a/sys-utils/readprofile.8 +++ b/sys-utils/readprofile.8 @@ -2,12 +2,12 @@ .\" Title: readprofile .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "READPROFILE" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "READPROFILE" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/readprofile.c b/sys-utils/readprofile.c index 579902d..6e6a68b 100644 --- a/sys-utils/readprofile.c +++ b/sys-utils/readprofile.c @@ -1,21 +1,14 @@ /* - * readprofile.c - used to read /proc/profile + * SPDX-License-Identifier: GPL-2.0-or-later * - * Copyright (C) 1994,1996 Alessandro Rubini (rubini@ipvvis.unipv.it) + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Copyright (C) 1994,1996 Alessandro Rubini (rubini@ipvvis.unipv.it) * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * readprofile.c - used to read /proc/profile */ /* @@ -88,14 +81,10 @@ static char *boot_uname_r_str(void) { struct utsname uname_info; char *s; - size_t len; if (uname(&uname_info)) return ""; - len = strlen(BOOT_SYSTEM_MAP) + strlen(uname_info.release) + 1; - s = xmalloc(len); - strcpy(s, BOOT_SYSTEM_MAP); - strcat(s, uname_info.release); + xasprintf(&s, "%s%s", BOOT_SYSTEM_MAP, uname_info.release); return s; } @@ -124,8 +113,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -r, --reset reset all the counters (root only)\n"), out); fputs(_(" -n, --no-auto disable byte order auto-detection\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(27)); - printf(USAGE_MAN_TAIL("readprofile(8)")); + fprintf(out, USAGE_HELP_OPTIONS(27)); + fprintf(out, USAGE_MAN_TAIL("readprofile(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/renice.1 b/sys-utils/renice.1 index 8577db9..582f862 100644 --- a/sys-utils/renice.1 +++ b/sys-utils/renice.1 @@ -2,12 +2,12 @@ .\" Title: renice .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "RENICE" "1" "2023-11-21" "util\-linux 2.39.3" "User Commands" +.TH "RENICE" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/renice.c b/sys-utils/renice.c index c4e1537..a8cf741 100644 --- a/sys-utils/renice.c +++ b/sys-utils/renice.c @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: BSD-4-Clause-UC + * * Copyright (c) 1983, 1989, 1993 * The Regents of the University of California. All rights reserved. * @@ -78,8 +80,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -g, --pgrp interpret arguments as process group ID\n"), out); fputs(_(" -u, --user interpret arguments as username or user ID\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(24)); - printf(USAGE_MAN_TAIL("renice(1)")); + fprintf(out, USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_MAN_TAIL("renice(1)")); exit(EXIT_SUCCESS); } @@ -100,7 +102,7 @@ static int donice(const int which, const int who, const int prio, const int rela if (getprio(which, who, &oldprio) != 0) return 1; - + newprio = prio; // if not relative, set absolute priority if (relative) diff --git a/sys-utils/rfkill.8 b/sys-utils/rfkill.8 index d7c24b3..6516674 100644 --- a/sys-utils/rfkill.8 +++ b/sys-utils/rfkill.8 @@ -2,12 +2,12 @@ .\" Title: rfkill .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "RFKILL" "8" "2023-11-21" "util\-linux 2.39.3" "System Administration" +.TH "RFKILL" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/rfkill.c b/sys-utils/rfkill.c index c4ee137..167d3a2 100644 --- a/sys-utils/rfkill.c +++ b/sys-utils/rfkill.c @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: ISC + * * /dev/rfkill userspace tool * * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> @@ -19,7 +21,6 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - #include <ctype.h> #include <getopt.h> #include <libsmartcols.h> @@ -643,7 +644,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -r, --raw use the raw output format\n"), stdout); fputs(USAGE_SEPARATOR, stdout); - printf(USAGE_HELP_OPTIONS(24)); + fprintf(stdout, USAGE_HELP_OPTIONS(24)); fputs(USAGE_COLUMNS, stdout); for (i = 0; i < ARRAY_SIZE(infos); i++) diff --git a/sys-utils/rtcwake.8 b/sys-utils/rtcwake.8 index 9d0050c..fbafff0 100644 --- a/sys-utils/rtcwake.8 +++ b/sys-utils/rtcwake.8 @@ -2,12 +2,12 @@ .\" Title: rtcwake .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "RTCWAKE" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "RTCWAKE" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/rtcwake.c b/sys-utils/rtcwake.c index 65f916b..67bbf8a 100644 --- a/sys-utils/rtcwake.c +++ b/sys-utils/rtcwake.c @@ -1,4 +1,14 @@ /* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2007 Bernhard Walle <bwalle@suse.de> + * Copyright (C) 2007-2023 Karel Zak <kzak@redhat.com> + * * rtcwake -- enter a system sleep state until specified wakeup time. * * This uses cross-platform Linux interfaces to enter a system sleep state, @@ -18,7 +28,6 @@ * RTC uses a local timezone instead (maybe you dual-boot MS-Windows). * That flag should not be needed on systems with adjtime support. */ - #include <errno.h> #include <fcntl.h> #include <getopt.h> @@ -118,8 +127,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -v, --verbose verbose messages\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(26)); - printf(USAGE_MAN_TAIL("rtcwake(8)")); + fprintf(out, USAGE_HELP_OPTIONS(26)); + fprintf(out, USAGE_MAN_TAIL("rtcwake(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/setarch.8 b/sys-utils/setarch.8 index 66509f0..a4cc285 100644 --- a/sys-utils/setarch.8 +++ b/sys-utils/setarch.8 @@ -2,12 +2,12 @@ .\" Title: setarch .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "SETARCH" "8" "2023-11-21" "util\-linux 2.39.3" "System Administration" +.TH "SETARCH" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/setarch.c b/sys-utils/setarch.c index 1a255e4..227bc6b 100644 --- a/sys-utils/setarch.c +++ b/sys-utils/setarch.c @@ -139,9 +139,9 @@ static void __attribute__((__noreturn__)) usage(int archwrapper) { fputs(USAGE_HEADER, stdout); if (!archwrapper) - printf(_(" %s [<arch>] [options] [<program> [<argument>...]]\n"), program_invocation_short_name); + fprintf(stdout, _(" %s [<arch>] [options] [<program> [<argument>...]]\n"), program_invocation_short_name); else - printf(_(" %s [options] [<program> [<argument>...]]\n"), program_invocation_short_name); + fprintf(stdout, _(" %s [options] [<program> [<argument>...]]\n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, stdout); fputs(_("Change the reported architecture and set personality flags.\n"), stdout); @@ -167,8 +167,8 @@ static void __attribute__((__noreturn__)) usage(int archwrapper) } fputs(USAGE_SEPARATOR, stdout); - printf(USAGE_HELP_OPTIONS(26)); - printf(USAGE_MAN_TAIL("setarch(8)")); + fprintf(stdout, USAGE_HELP_OPTIONS(26)); + fprintf(stdout, USAGE_MAN_TAIL("setarch(8)")); exit(EXIT_SUCCESS); } @@ -271,6 +271,12 @@ static struct arch_domain *init_arch_domains(void) {PER_LINUX, "arm64", "aarch64"}, {PER_LINUX, "aarch64", "aarch64"}, #endif +#if defined(__riscv) + {PER_LINUX32, "riscv32", "riscv32"}, + {PER_LINUX32, "rv32", "riscv32"}, + {PER_LINUX, "riscv64", "riscv64"}, + {PER_LINUX, "rv64", "riscv64"}, +#endif /* place holder, will be filled up at runtime */ {-1, NULL, NULL}, {-1, NULL, NULL} diff --git a/sys-utils/setpgid.1 b/sys-utils/setpgid.1 new file mode 100644 index 0000000..84be988 --- /dev/null +++ b/sys-utils/setpgid.1 @@ -0,0 +1,68 @@ +'\" t +.\" Title: setpgid +.\" Author: [see the "AUTHOR(S)" section] +.\" Generator: Asciidoctor 2.0.20 +.\" Date: 2024-03-20 +.\" Manual: User Commands +.\" Source: util-linux 2.40 +.\" Language: English +.\" +.TH "SETPGID" "1" "2024-03-20" "util\-linux 2.40" "User Commands" +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.ss \n[.ss] 0 +.nh +.ad l +.de URL +\fI\\$2\fP <\\$1>\\$3 +.. +.als MTO URL +.if \n[.g] \{\ +. mso www.tmac +. am URL +. ad l +. . +. am MTO +. ad l +. . +. LINKSTYLE blue R < > +.\} +.SH "NAME" +setpgid \- run a program in a new process group +.SH "SYNOPSIS" +.sp +\fBsetpgid\fP [options] \fIprogram\fP [\fIarguments\fP] +.SH "DESCRIPTION" +.sp +\fBsetpgid\fP runs a program in a new process group. +.SH "OPTIONS" +.sp +\fB\-f\fP, \fB\-\-foreground\fP +.RS 4 +Make the new process group the foreground process group of the controlling +terminal if there is a controlling terminal. +.RE +.sp +\fB\-h\fP, \fB\-\-help\fP +.RS 4 +Display help text and exit. +.RE +.sp +\fB\-V\fP, \fB\-\-version\fP +.RS 4 +Print version and exit. +.RE +.SH "AUTHORS" +.sp +.MTO "daan.j.demeyer\(atgmail.com" "Daan De Meyer" "" +.SH "SEE ALSO" +.sp +\fBsetpgid\fP(2) +.SH "REPORTING BUGS" +.sp +For bug reports, use the issue tracker at \c +.URL "https://github.com/util\-linux/util\-linux/issues" "" "." +.SH "AVAILABILITY" +.sp +The \fBsetpgid\fP command is part of the util\-linux package which can be downloaded from \c +.URL "https://www.kernel.org/pub/linux/utils/util\-linux/" "Linux Kernel Archive" "."
\ No newline at end of file diff --git a/sys-utils/setpgid.1.adoc b/sys-utils/setpgid.1.adoc new file mode 100644 index 0000000..0d43723 --- /dev/null +++ b/sys-utils/setpgid.1.adoc @@ -0,0 +1,49 @@ +// +// No copyright is claimed. This code is in the public domain; do with +// it what you wish. +// +//po4a: entry man manual +// Daan De Meyer <daan.j.demeyer@gmail.com> +// In the public domain. += setpgid(1) +:doctype: manpage +:man manual: User Commands +:man source: util-linux {release-version} +:page-layout: base +:command: setpgid + +== NAME + +setpgid - run a program in a new process group + +== SYNOPSIS + +*setpgid* [options] _program_ [_arguments_] + +== DESCRIPTION + +*setpgid* runs a program in a new process group. + +== OPTIONS + +*-f*, *--foreground*:: +Make the new process group the foreground process group of the controlling +terminal if there is a controlling terminal. + +include::man-common/help-version.adoc[] + +== AUTHORS + +mailto:daan.j.demeyer@gmail.com[Daan De Meyer] + +== SEE ALSO + +*setpgid*(2) + +include::man-common/bugreports.adoc[] + +include::man-common/footer.adoc[] + +ifdef::translation[] +include::man-common/translation.adoc[] +endif::[] diff --git a/sys-utils/setpgid.c b/sys-utils/setpgid.c new file mode 100644 index 0000000..936991d --- /dev/null +++ b/sys-utils/setpgid.c @@ -0,0 +1,91 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Daan De Meyer <daan.j.demeyer@gmail.com> + */ +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> + +#include "closestream.h" + +static void __attribute__((__noreturn__)) usage(void) +{ + FILE *out = stdout; + fputs(USAGE_HEADER, out); + fprintf(out, _( + " %s [options] <program> [arguments ...]\n"), + program_invocation_short_name); + + fputs(USAGE_SEPARATOR, out); + fputs(_("Run a program in a new process group.\n"), out); + + fputs(USAGE_OPTIONS, out); + fputs(_(" -f, --foregound Make a foreground process group\n"), out); + + fprintf(out, USAGE_HELP_OPTIONS(16)); + + fprintf(out, USAGE_MAN_TAIL("setpgid(1)")); + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + int ch, foreground = 0, fd; + sigset_t s, old; + + static const struct option longopts[] = { + {"foreground", no_argument, NULL, 'f'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + close_stdout_atexit(); + + while ((ch = getopt_long(argc, argv, "+Vh", longopts, NULL)) != -1) + switch (ch) { + case 'f': + foreground = 1; + break; + case 'h': + usage(); + case 'V': + print_version(EXIT_SUCCESS); + default: + errtryhelp(EXIT_FAILURE); + } + + if (argc - optind < 1) { + warnx(_("no command specified")); + errtryhelp(EXIT_FAILURE); + } + + if (setpgid(0, 0) < 0) + err(EXIT_FAILURE, _("setpgid failed")); + + if (foreground) { + fd = open("/dev/tty", O_RDONLY|O_CLOEXEC); + if (fd >= 0) { + if (sigemptyset(&s) < 0) + err(EXIT_FAILURE, _("sigemptyset failed")); + if (sigaddset(&s, SIGTTOU) < 0) + err(EXIT_FAILURE, _("sigaddset failed")); + if (sigprocmask(SIG_BLOCK, &s, &old) < 0) + err(EXIT_FAILURE, _("sigprocmask failed")); + if (tcsetpgrp(fd, getpgid(0)) < 0) + err(EXIT_FAILURE, _("tcsetpgrp failed")); + if (sigprocmask(SIG_SETMASK, &old, NULL) < 0) + err(EXIT_FAILURE, _("sigprocmask failed")); + } + } + + execvp(argv[optind], argv + optind); + errexec(argv[optind]); +} diff --git a/sys-utils/setpriv-landlock.c b/sys-utils/setpriv-landlock.c new file mode 100644 index 0000000..00ad38c --- /dev/null +++ b/sys-utils/setpriv-landlock.c @@ -0,0 +1,214 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2023 Thomas Weißschuh <thomas@t-8ch.de> + */ + +#include <sys/prctl.h> +#include <sys/syscall.h> +#include <linux/landlock.h> + +#include "setpriv-landlock.h" + +#include "strutils.h" +#include "xalloc.h" +#include "nls.h" +#include "c.h" + +#ifndef HAVE_LANDLOCK_CREATE_RULESET +static inline int landlock_create_ruleset( + const struct landlock_ruleset_attr *attr, + size_t size, uint32_t flags) +{ + return syscall(__NR_landlock_create_ruleset, attr, size, flags); +} +#endif + +#ifndef HAVE_LANDLOCK_ADD_RULE +static inline int landlock_add_rule( + int ruleset_fd, enum landlock_rule_type rule_type, + const void *rule_attr, uint32_t flags) +{ + return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, + rule_attr, flags); +} +#endif + +#ifndef HAVE_LANDLOCK_RESTRICT_SELF +static inline int landlock_restrict_self(int ruleset_fd, uint32_t flags) +{ + return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); +} +#endif + +#define SETPRIV_EXIT_PRIVERR 127 /* how we exit when we fail to set privs */ + +struct landlock_rule_entry { + struct list_head head; + enum landlock_rule_type rule_type; + union { + struct landlock_path_beneath_attr path_beneath_attr; + }; +}; + +static const struct { + unsigned long long value; + const char *type; +} landlock_access_fs[] = { + { LANDLOCK_ACCESS_FS_EXECUTE, "execute" }, + { LANDLOCK_ACCESS_FS_WRITE_FILE, "write-file" }, + { LANDLOCK_ACCESS_FS_READ_FILE, "read-file" }, + { LANDLOCK_ACCESS_FS_READ_DIR, "read-dir" }, + { LANDLOCK_ACCESS_FS_REMOVE_DIR, "remove-dir" }, + { LANDLOCK_ACCESS_FS_REMOVE_FILE, "remove-file" }, + { LANDLOCK_ACCESS_FS_MAKE_CHAR, "make-char" }, + { LANDLOCK_ACCESS_FS_MAKE_DIR, "make-dir" }, + { LANDLOCK_ACCESS_FS_MAKE_REG, "make-reg" }, + { LANDLOCK_ACCESS_FS_MAKE_SOCK, "make-sock" }, + { LANDLOCK_ACCESS_FS_MAKE_FIFO, "make-fifo" }, + { LANDLOCK_ACCESS_FS_MAKE_BLOCK, "make-block" }, + { LANDLOCK_ACCESS_FS_MAKE_SYM, "make-sym" }, +#ifdef LANDLOCK_ACCESS_FS_REFER + { LANDLOCK_ACCESS_FS_REFER, "refer" }, +#endif +#ifdef LANDLOCK_ACCESS_FS_TRUNCATE + { LANDLOCK_ACCESS_FS_TRUNCATE, "truncate" }, +#endif +}; + +static long landlock_access_to_mask(const char *str, size_t len) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(landlock_access_fs); i++) + if (strncmp(landlock_access_fs[i].type, str, len) == 0) + return landlock_access_fs[i].value; + return -1; +} + +static uint64_t parse_landlock_fs_access(const char *list) +{ + unsigned long r = 0; + size_t i; + + /* without argument, match all */ + if (list[0] == '\0') { + for (i = 0; i < ARRAY_SIZE(landlock_access_fs); i++) + r |= landlock_access_fs[i].value; + } else { + if (string_to_bitmask(list, &r, landlock_access_to_mask)) + errx(EXIT_FAILURE, + _("could not parse landlock fs access: %s"), list); + } + + return r; +} + +void parse_landlock_access(struct setpriv_landlock_opts *opts, const char *str) +{ + const char *type; + size_t i; + + if (strcmp(str, "fs") == 0) { + for (i = 0; i < ARRAY_SIZE(landlock_access_fs); i++) + opts->access_fs |= landlock_access_fs[i].value; + return; + } + + type = startswith(str, "fs:"); + if (type) + opts->access_fs |= parse_landlock_fs_access(type); +} + +void parse_landlock_rule(struct setpriv_landlock_opts *opts, const char *str) +{ + struct landlock_rule_entry *rule = xmalloc(sizeof(*rule)); + const char *accesses, *path; + char *accesses_part; + int parent_fd; + + accesses = startswith(str, "path-beneath:"); + if (!accesses) + errx(EXIT_FAILURE, _("invalid landlock rule: %s"), str); + path = strchr(accesses, ':'); + if (!path) + errx(EXIT_FAILURE, _("invalid landlock rule: %s"), str); + rule->rule_type = LANDLOCK_RULE_PATH_BENEATH; + + accesses_part = xstrndup(accesses, path - accesses); + rule->path_beneath_attr.allowed_access = parse_landlock_fs_access(accesses_part); + free(accesses_part); + + path++; + + parent_fd = open(path, O_RDONLY | O_PATH | O_CLOEXEC); + if (parent_fd == -1) + err(EXIT_FAILURE, _("could not open file for landlock: %s"), path); + + rule->path_beneath_attr.parent_fd = parent_fd; + + list_add(&rule->head, &opts->rules); +} + +void init_landlock_opts(struct setpriv_landlock_opts *opts) +{ + INIT_LIST_HEAD(&opts->rules); +} + +void do_landlock(const struct setpriv_landlock_opts *opts) +{ + struct landlock_rule_entry *rule; + struct list_head *entry; + int fd, ret; + + if (!opts->access_fs) + return; + + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_fs = opts->access_fs, + }; + + fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); + if (fd == -1) + err(SETPRIV_EXIT_PRIVERR, _("landlock_create_ruleset failed")); + + list_for_each(entry, &opts->rules) { + rule = list_entry(entry, struct landlock_rule_entry, head); + + assert(rule->rule_type == LANDLOCK_RULE_PATH_BENEATH); + + ret = landlock_add_rule(fd, rule->rule_type, &rule->path_beneath_attr, 0); + if (ret == -1) + err(SETPRIV_EXIT_PRIVERR, _("adding landlock rule failed")); + } + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) + err(SETPRIV_EXIT_PRIVERR, _("disallow granting new privileges for landlock failed")); + + if (landlock_restrict_self(fd, 0) == -1) + err(SETPRIV_EXIT_PRIVERR, _("landlock_restrict_self faild")); +} + +void usage_setpriv(FILE *out) +{ + size_t i; + + fprintf(out, "\n"); + fprintf(out, _("Landlock accesses:\n")); + fprintf(out, " Access: fs\n"); + fprintf(out, " Rule types: path-beneath\n"); + + fprintf(out, " Rules: "); + for (i = 0; i < ARRAY_SIZE(landlock_access_fs); i++) { + fprintf(out, "%s", landlock_access_fs[i].type); + if (i == ARRAY_SIZE(landlock_access_fs) - 1) + fprintf(out, "\n"); + else + fprintf(out, ","); + } +} diff --git a/sys-utils/setpriv-landlock.h b/sys-utils/setpriv-landlock.h new file mode 100644 index 0000000..d66f86d --- /dev/null +++ b/sys-utils/setpriv-landlock.h @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2023 Thomas Weißschuh <thomas@t-8ch.de> + */ + +#ifndef UTIL_LINUX_SETPRIV_LANDLOCK +#define UTIL_LINUX_SETPRIV_LANDLOCK + +#ifdef HAVE_LINUX_LANDLOCK_H + +#include <stdint.h> + +#include "list.h" + +struct setpriv_landlock_opts { + uint64_t access_fs; + struct list_head rules; +}; + +void do_landlock(const struct setpriv_landlock_opts *opts); +void parse_landlock_access(struct setpriv_landlock_opts *opts, const char *str); +void parse_landlock_rule(struct setpriv_landlock_opts *opts, const char *str); +void init_landlock_opts(struct setpriv_landlock_opts *opts); +void usage_setpriv(FILE *out); + +#else + +#include "c.h" +#include "nls.h" + +struct setpriv_landlock_opts {}; + +static inline void do_landlock(const void *opts __attribute__((unused))) {} +static inline void parse_landlock_access( + void *opts __attribute__((unused)), + const char *str __attribute__((unused))) +{ + errx(EXIT_FAILURE, _("no support for landlock")); +} +#define parse_landlock_rule parse_landlock_access +static inline void init_landlock_opts(void *opts __attribute__((unused))) {} +static inline void usage_setpriv(FILE *out __attribute__((unused))) {} + +#endif /* HAVE_LINUX_LANDLOCK_H */ + +#endif diff --git a/sys-utils/setpriv.1 b/sys-utils/setpriv.1 index c1bf933..dd82a1e 100644 --- a/sys-utils/setpriv.1 +++ b/sys-utils/setpriv.1 @@ -2,12 +2,12 @@ .\" Title: setpriv .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-03-27 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "SETPRIV" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "SETPRIV" "1" "2024-03-27" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -156,6 +156,35 @@ Request a particular SELinux transition (using a transition on exec, not dyntran Request a particular AppArmor profile (using a transition on exec). This will fail and cause \fBsetpriv\fP to abort if AppArmor is not in use, and the transition may be ignored or cause \fBexecve\fP(2) to fail at AppArmor\(cqs whim. .RE .sp +\fB\-\-landlock\-access\fP \fIaccess\fP +.RS 4 +Enable landlock restrictions for a specific set of system accesses. +To allow specific subgroups of accesses use \fB\-\-landlock\-rule\fP. +.sp +Block all filesystem access: +.sp +\fBsetpriv \-\-landlock\-access fs\fP +.sp +Block all file deletions and directory creations: +.sp +\fBsetpriv \-\-landlock\-access fs:remove\-file,make\-dir\fP +.sp +For a complete set of supported access categories use \fBsetpriv \-\-help\fP. +.RE +.sp +\fB\-\-landlock\-rule\fP \fIrule\fP +.RS 4 +Allow one specific access from the categories blocked by \fB\-\-landlock\-access\fP. +.sp +The syntax is as follows: +.sp +\fB\-\-landlock\-rule $ruletype:$access:$rulearg\fP +.sp +For example grant file read access to everything under \fB/boot\fP: +.sp +\fB\-\-landlock\-rule path\-beneath:read\-file:/boot\fP +.RE +.sp \fB\-\-reset\-env\fP .RS 4 Clears all the environment variables except \fBTERM\fP; initializes the environment variables \fBHOME\fP, \fBSHELL\fP, \fBUSER\fP, \fBLOGNAME\fP according to the user\(cqs passwd entry; sets \fBPATH\fP to \fI/usr/local/bin:/bin:/usr/bin\fP for a regular user and to \fI/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\fP for root. @@ -195,6 +224,7 @@ If you want to mimic daemontools\*(Aq \fBsetuid\fP(8), try: \fBsu\fP(1), \fBprctl\fP(2), \fBcapabilities\fP(7) +\fBlandlock\fP(7) .SH "REPORTING BUGS" .sp For bug reports, use the issue tracker at \c diff --git a/sys-utils/setpriv.1.adoc b/sys-utils/setpriv.1.adoc index a0ad6f8..9029346 100644 --- a/sys-utils/setpriv.1.adoc +++ b/sys-utils/setpriv.1.adoc @@ -84,6 +84,32 @@ Request a particular SELinux transition (using a transition on exec, not dyntran *--apparmor-profile* _profile_:: Request a particular AppArmor profile (using a transition on exec). This will fail and cause *setpriv* to abort if AppArmor is not in use, and the transition may be ignored or cause *execve*(2) to fail at AppArmor's whim. +*--landlock-access* _access_:: +Enable landlock restrictions for a specific set of system accesses. +To allow specific subgroups of accesses use *--landlock-rule*. ++ +Block all filesystem access: ++ +*setpriv --landlock-access fs* ++ +Block all file deletions and directory creations: ++ +*setpriv --landlock-access fs:remove-file,make-dir* ++ +For a complete set of supported access categories use *setpriv --help*. + +*--landlock-rule* _rule_:: + +Allow one specific access from the categories blocked by *--landlock-access*. ++ +The syntax is as follows: ++ +*--landlock-rule $ruletype:$access:$rulearg* ++ +For example grant file read access to everything under */boot*: ++ +*--landlock-rule path-beneath:read-file:/boot* + *--reset-env*:: Clears all the environment variables except *TERM*; initializes the environment variables *HOME*, *SHELL*, *USER*, *LOGNAME* according to the user's passwd entry; sets *PATH* to _/usr/local/bin:/bin:/usr/bin_ for a regular user and to _/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin_ for root. + @@ -117,6 +143,7 @@ mailto:luto@amacapital.net[Andy Lutomirski] *su*(1), *prctl*(2), *capabilities*(7) +*landlock*(7) include::man-common/bugreports.adoc[] diff --git a/sys-utils/setpriv.c b/sys-utils/setpriv.c index ddc2cc6..74d3fbe 100644 --- a/sys-utils/setpriv.c +++ b/sys-utils/setpriv.c @@ -41,6 +41,7 @@ #include "pathnames.h" #include "signames.h" #include "env.h" +#include "setpriv-landlock.h" #ifndef PR_SET_NO_NEW_PRIVS # define PR_SET_NO_NEW_PRIVS 38 @@ -110,6 +111,7 @@ struct privctx { /* LSMs */ const char *selinux_label; const char *apparmor_profile; + struct setpriv_landlock_opts landlock; }; static void __attribute__((__noreturn__)) usage(void) @@ -143,14 +145,18 @@ static void __attribute__((__noreturn__)) usage(void) " set or clear parent death signal\n"), out); fputs(_(" --selinux-label <label> set SELinux label\n"), out); fputs(_(" --apparmor-profile <pr> set AppArmor profile\n"), out); + fputs(_(" --landlock-access <access> add Landlock access\n"), out); + fputs(_(" --landlock-rule <rule> add Landlock rule\n"), out); fputs(_(" --reset-env clear all environment and initialize\n" " HOME, SHELL, USER, LOGNAME and PATH\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(29)); + fprintf(out, USAGE_HELP_OPTIONS(29)); fputs(USAGE_SEPARATOR, out); fputs(_(" This tool can be dangerous. Read the manpage, and be careful.\n"), out); - printf(USAGE_MAN_TAIL("setpriv(1)")); + fprintf(out, USAGE_MAN_TAIL("setpriv(1)")); + + usage_setpriv(out); exit(EXIT_SUCCESS); } @@ -651,7 +657,6 @@ static void do_apparmor_profile(const char *label) _("write failed: %s"), _PATH_PROC_ATTR_EXEC); } - static void do_reset_environ(struct passwd *pw) { char *term = getenv("TERM"); @@ -754,6 +759,8 @@ int main(int argc, char **argv) PDEATHSIG, SELINUX_LABEL, APPARMOR_PROFILE, + LANDLOCK_ACCESS, + LANDLOCK_RULE, RESET_ENV }; @@ -779,6 +786,8 @@ int main(int argc, char **argv) { "pdeathsig", required_argument, NULL, PDEATHSIG, }, { "selinux-label", required_argument, NULL, SELINUX_LABEL }, { "apparmor-profile", required_argument, NULL, APPARMOR_PROFILE }, + { "landlock-access", required_argument, NULL, LANDLOCK_ACCESS }, + { "landlock-rule", required_argument, NULL, LANDLOCK_RULE }, { "help", no_argument, NULL, 'h' }, { "reset-env", no_argument, NULL, RESET_ENV, }, { "version", no_argument, NULL, 'V' }, @@ -805,6 +814,7 @@ int main(int argc, char **argv) close_stdout_atexit(); memset(&opts, 0, sizeof(opts)); + init_landlock_opts(&opts.landlock); while ((c = getopt_long(argc, argv, "+dhV", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -933,6 +943,12 @@ int main(int argc, char **argv) _("duplicate --apparmor-profile option")); opts.apparmor_profile = optarg; break; + case LANDLOCK_ACCESS: + parse_landlock_access(&opts.landlock, optarg); + break; + case LANDLOCK_RULE: + parse_landlock_rule(&opts.landlock, optarg); + break; case RESET_ENV: opts.reset_env = 1; break; @@ -1056,6 +1072,8 @@ int main(int argc, char **argv) if (opts.pdeathsig && prctl(PR_SET_PDEATHSIG, opts.pdeathsig < 0 ? 0 : opts.pdeathsig) != 0) err(SETPRIV_EXIT_PRIVERR, _("set parent death signal failed")); + do_landlock(&opts.landlock); + execvp(argv[optind], argv + optind); errexec(argv[optind]); } diff --git a/sys-utils/setsid.1 b/sys-utils/setsid.1 index 950d361..e345738 100644 --- a/sys-utils/setsid.1 +++ b/sys-utils/setsid.1 @@ -2,12 +2,12 @@ .\" Title: setsid .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "SETSID" "1" "2023-10-23" "util\-linux 2.39.3" "User Commands" +.TH "SETSID" "1" "2024-01-31" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/setsid.c b/sys-utils/setsid.c index 5725e80..5ccfd0f 100644 --- a/sys-utils/setsid.c +++ b/sys-utils/setsid.c @@ -1,7 +1,10 @@ /* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Rick Sladkey <jrs@world.std.com> + * * setsid.c -- execute a command in a new session - * Rick Sladkey <jrs@world.std.com> - * In the public domain. * * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL> * - added Native Language Support @@ -12,7 +15,6 @@ * 2008-08-20 Daniel Kahn Gillmor <dkg@fifthhorseman.net> * - if forked, wait on child process and emit its return code. */ - #include <getopt.h> #include <stdio.h> #include <stdlib.h> @@ -41,9 +43,9 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -f, --fork always fork\n"), out); fputs(_(" -w, --wait wait program to exit, and use the same return\n"), out); - printf(USAGE_HELP_OPTIONS(16)); + fprintf(out, USAGE_HELP_OPTIONS(16)); - printf(USAGE_MAN_TAIL("setsid(1)")); + fprintf(out, USAGE_MAN_TAIL("setsid(1)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/swapoff.c b/sys-utils/swapoff.c index 1ddfcda..62f1374 100644 --- a/sys-utils/swapoff.c +++ b/sys-utils/swapoff.c @@ -1,3 +1,16 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com> + * + * Original implementation from Linux 0.99, without License and copyright in + * the code. Karel Zak rewrote the code under GPL-2.0-or-later. + */ #include <stdio.h> #include <errno.h> #include <getopt.h> @@ -148,7 +161,7 @@ static void __attribute__((__noreturn__)) usage(void) " -v, --verbose verbose mode\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_HELP_OPTIONS(24)); fputs(_("\nThe <spec> parameter:\n" \ " -L <label> LABEL of device to be used\n" \ @@ -158,7 +171,7 @@ static void __attribute__((__noreturn__)) usage(void) " <device> name of device to be used\n" \ " <file> name of file to be used\n"), out); - printf(USAGE_MAN_TAIL("swapoff(8)")); + fprintf(out, USAGE_MAN_TAIL("swapoff(8)")); exit(SWAPOFF_EX_OK); } diff --git a/sys-utils/swapon-common.c b/sys-utils/swapon-common.c index bffedec..a4149a5 100644 --- a/sys-utils/swapon-common.c +++ b/sys-utils/swapon-common.c @@ -1,4 +1,16 @@ - +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com> + * + * Original implementation from Linux 0.99, without License and copyright in + * the code. Karel Zak rewrote the code under GPL-2.0-or-later. + */ #include "c.h" #include "nls.h" #include "xalloc.h" @@ -85,7 +97,7 @@ static size_t ulct; void add_label(const char *label) { - llist = xrealloc(llist, (++llct) * sizeof(char *)); + llist = xreallocarray(llist, ++llct, sizeof(char *)); llist[llct - 1] = label; } @@ -101,7 +113,7 @@ size_t numof_labels(void) void add_uuid(const char *uuid) { - ulist = xrealloc(ulist, (++ulct) * sizeof(char *)); + ulist = xreallocarray(ulist, ++ulct, sizeof(char *)); ulist[ulct - 1] = uuid; } diff --git a/sys-utils/swapon-common.h b/sys-utils/swapon-common.h index a13c0de..4d66a14 100644 --- a/sys-utils/swapon-common.h +++ b/sys-utils/swapon-common.h @@ -1,3 +1,16 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com> + * + * Original implementation from Linux 0.99, without License and copyright in + * the code. Karel Zak rewrote the code under GPL-2.0-or-later. + */ #ifndef UTIL_LINUX_SWAPON_COMMON_H #define UTIL_LINUX_SWAPON_COMMON_H diff --git a/sys-utils/swapon.8 b/sys-utils/swapon.8 index 88c57f2..bbdaa80 100644 --- a/sys-utils/swapon.8 +++ b/sys-utils/swapon.8 @@ -2,12 +2,12 @@ .\" Title: swapon .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-12-01 +.\" Date: 2024-03-20 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "SWAPON" "8" "2023-12-01" "util\-linux 2.39.3" "System Administration" +.TH "SWAPON" "8" "2024-03-20" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -98,7 +98,7 @@ The \fIopts\fP string is evaluated last and overrides all other command line opt .sp \fB\-p\fP, \fB\-\-priority\fP \fIpriority\fP .RS 4 -Specify the priority of the swap device. \fIpriority\fP is a value between \-1 and 32767. Higher numbers indicate higher priority. See \fBswapon\fP(2) for a full description of swap priorities. Add \fBpri=\fP\fIvalue\fP to the option field of \fI/etc/fstab\fP for use with \fBswapon \-a\fP. When no priority is defined, it defaults to \-1. +Specify the priority of the swap device. \fIpriority\fP is a value between 0 and 32767. Higher numbers indicate higher priority. See \fBswapon\fP(2) for a full description of swap priorities. Add \fBpri=\fP\fIvalue\fP to the option field of \fI/etc/fstab\fP for use with \fBswapon \-a\fP. When no priority is defined, Linux kernel defaults to negative numbers. .RE .sp \fB\-s\fP, \fB\-\-summary\fP diff --git a/sys-utils/swapon.8.adoc b/sys-utils/swapon.8.adoc index cf1b28f..4335d7f 100644 --- a/sys-utils/swapon.8.adoc +++ b/sys-utils/swapon.8.adoc @@ -63,7 +63,7 @@ Specify swap options by an __fstab__-compatible comma-separated string. For exam The _opts_ string is evaluated last and overrides all other command line options. *-p*, *--priority* _priority_:: -Specify the priority of the swap device. _priority_ is a value between -1 and 32767. Higher numbers indicate higher priority. See *swapon*(2) for a full description of swap priorities. Add **pri=**__value__ to the option field of _/etc/fstab_ for use with *swapon -a*. When no priority is defined, it defaults to -1. +Specify the priority of the swap device. _priority_ is a value between 0 and 32767. Higher numbers indicate higher priority. See *swapon*(2) for a full description of swap priorities. Add **pri=**__value__ to the option field of _/etc/fstab_ for use with *swapon -a*. When no priority is defined, Linux kernel defaults to negative numbers. *-s*, *--summary*:: Display swap usage summary by device. Equivalent to *cat /proc/swaps*. This output format is DEPRECATED in favour of *--show* that provides better control on output data. diff --git a/sys-utils/swapon.c b/sys-utils/swapon.c index 8735549..ce499c1 100644 --- a/sys-utils/swapon.c +++ b/sys-utils/swapon.c @@ -1,3 +1,16 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Copyright (C) 2012-2023 Karel Zak <kzak@redhat.com> + * + * Original implementation from Linux 0.99, without License and copyright in + * the code. Karel Zak rewrote the code under GPL-2.0-or-later. + */ #include <assert.h> #include <stdlib.h> #include <stdio.h> @@ -77,10 +90,10 @@ enum { /* column names */ struct colinfo { - const char *name; /* header */ - double whint; /* width hint (N < 1 is in percent of termwidth) */ - int flags; /* SCOLS_FL_* */ - const char *help; + const char * const name; /* header */ + double whint; /* width hint (N < 1 is in percent of termwidth) */ + int flags; /* SCOLS_FL_* */ + const char *help; }; enum { @@ -92,7 +105,7 @@ enum { COL_UUID, COL_LABEL }; -static struct colinfo infos[] = { +static const struct colinfo infos[] = { [COL_PATH] = { "NAME", 0.20, 0, N_("device file or partition path") }, [COL_TYPE] = { "TYPE", 0.20, SCOLS_FL_TRUNC, N_("type of the device")}, [COL_SIZE] = { "SIZE", 0.20, SCOLS_FL_RIGHT, N_("size of the swap area")}, @@ -159,7 +172,7 @@ static inline int get_column_id(const struct swapon_ctl *ctl, int num) return ctl->columns[num]; } -static inline struct colinfo *get_column_info(const struct swapon_ctl *ctl, unsigned num) +static inline const struct colinfo *get_column_info(const struct swapon_ctl *ctl, unsigned num) { return &infos[get_column_id(ctl, num)]; } @@ -299,7 +312,7 @@ static int show_table(struct swapon_ctl *ctl) scols_table_enable_noheadings(table, ctl->no_heading); for (i = 0; i < ctl->ncolumns; i++) { - struct colinfo *col = get_column_info(ctl, i); + const struct colinfo *col = get_column_info(ctl, i); if (!scols_table_new_column(table, col->name, col->whint, col->flags)) err(EXIT_FAILURE, _("failed to allocate output column")); @@ -825,7 +838,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -v, --verbose verbose mode\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(26)); + fprintf(out, USAGE_HELP_OPTIONS(26)); fputs(_("\nThe <spec> parameter:\n" \ " -L <label> synonym for LABEL=<label>\n" @@ -846,7 +859,7 @@ static void __attribute__((__noreturn__)) usage(void) for (i = 0; i < ARRAY_SIZE(infos); i++) fprintf(out, " %-5s %s\n", infos[i].name, _(infos[i].help)); - printf(USAGE_MAN_TAIL("swapon(8)")); + fprintf(out, USAGE_MAN_TAIL("swapon(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/switch_root.8 b/sys-utils/switch_root.8 index 4e5263c..f5d9dfc 100644 --- a/sys-utils/switch_root.8 +++ b/sys-utils/switch_root.8 @@ -2,12 +2,12 @@ .\" Title: switch_root .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "SWITCH_ROOT" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "SWITCH_ROOT" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/switch_root.c b/sys-utils/switch_root.c index 174eec6..ab8c2a1 100644 --- a/sys-utils/switch_root.c +++ b/sys-utils/switch_root.c @@ -230,8 +230,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_("Switch to another filesystem as the root of the mount tree.\n"), output); fputs(USAGE_OPTIONS, output); - printf(USAGE_HELP_OPTIONS(16)); - printf(USAGE_MAN_TAIL("switch_root(8)")); + fprintf(output, USAGE_HELP_OPTIONS(16)); + fprintf(output, USAGE_MAN_TAIL("switch_root(8)")); exit(EXIT_SUCCESS); } @@ -280,4 +280,3 @@ int main(int argc, char *argv[]) execv(init, initargs); errexec(init); } - diff --git a/sys-utils/tunelp.8 b/sys-utils/tunelp.8 index ad2ac60..e7efb67 100644 --- a/sys-utils/tunelp.8 +++ b/sys-utils/tunelp.8 @@ -2,12 +2,12 @@ .\" Title: tunelp .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "TUNELP" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "TUNELP" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/tunelp.c b/sys-utils/tunelp.c index 731acd1..95a21b3 100644 --- a/sys-utils/tunelp.c +++ b/sys-utils/tunelp.c @@ -112,8 +112,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -r, --reset reset the port\n"), out); fputs(_(" -q, --print-irq <on|off> display current irq setting\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(30)); - printf(USAGE_MAN_TAIL("tunelp(8)")); + fprintf(out, USAGE_HELP_OPTIONS(30)); + fprintf(out, USAGE_MAN_TAIL("tunelp(8)")); exit(EXIT_SUCCESS); } diff --git a/sys-utils/umount.8 b/sys-utils/umount.8 index 07b10b7..4bbb3b1 100644 --- a/sys-utils/umount.8 +++ b/sys-utils/umount.8 @@ -2,12 +2,12 @@ .\" Title: umount .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "UMOUNT" "8" "2023-11-21" "util\-linux 2.39.3" "System Administration" +.TH "UMOUNT" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/umount.c b/sys-utils/umount.c index 3a740ae..17e668c 100644 --- a/sys-utils/umount.c +++ b/sys-utils/umount.c @@ -107,8 +107,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -N, --namespace <ns> perform umount in another namespace\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(25)); - printf(USAGE_MAN_TAIL("umount(8)")); + fprintf(out, USAGE_HELP_OPTIONS(25)); + fprintf(out, USAGE_MAN_TAIL("umount(8)")); exit(MNT_EX_SUCCESS); } @@ -656,4 +656,3 @@ int main(int argc, char **argv) return (rc < 256) ? rc : 255; } - diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1 index 389181c..181e567 100644 --- a/sys-utils/unshare.1 +++ b/sys-utils/unshare.1 @@ -2,12 +2,12 @@ .\" Title: unshare .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-03-20 .\" Manual: User Commands -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "UNSHARE" "1" "2023-11-21" "util\-linux 2.39.3" "User Commands" +.TH "UNSHARE" "1" "2024-03-20" "util\-linux 2.40" "User Commands" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 @@ -152,9 +152,9 @@ Just before running the program, mount the proc filesystem at \fImountpoint\fP ( Run the program only after the current effective user ID has been mapped to \fIuid\fP. If this option is specified multiple times, the last occurrence takes precedence. This option implies \fB\-\-user\fP. .RE .sp -\fB\-\-map\-users=\fP\fIinneruid:outeruid:count\fP|\fBauto\fP +\fB\-\-map\-users=\fP\fIinneruid:outeruid:count\fP|\fBauto\fP|\fBall\fP .RS 4 -Run the program only after the block of user IDs of size \fIcount\fP beginning at \fIouteruid\fP has been mapped to the block of user IDs beginning at \fIinneruid\fP. This mapping is created with \fBnewuidmap\fP(1). If the range of user IDs overlaps with the mapping specified by \fB\-\-map\-user\fP, then a "hole" will be removed from the mapping. This may result in the highest user ID of the mapping not being mapped. The special value \fBauto\fP will map the first block of user IDs owned by the effective user from \fI/etc/subuid\fP to a block starting at user ID 0. If this option is specified multiple times, the last occurrence takes precedence. This option implies \fB\-\-user\fP. +Run the program only after the block of user IDs of size \fIcount\fP beginning at \fIouteruid\fP has been mapped to the block of user IDs beginning at \fIinneruid\fP. This mapping is created with \fBnewuidmap\fP(1) if \fBunshare\fP was run unprivileged. If the range of user IDs overlaps with the mapping specified by \fB\-\-map\-user\fP, then a "hole" will be removed from the mapping. This may result in the highest user ID of the mapping not being mapped. Use \fB\-\-map\-users\fP multiple times to map more than one block of user IDs. The special value \fBauto\fP will map the first block of user IDs owned by the effective user from \fI/etc/subuid\fP to a block starting at user ID 0. The special value \fBall\fP will create a pass\-through map for every user ID available in the parent namespace. This option implies \fB\-\-user\fP. .sp Before util\-linux version 2.39, this option expected a comma\-separated argument of the form \fIouteruid,inneruid,count\fP but that format is now deprecated for consistency with the ordering used in \fI/proc/[pid]/uid_map\fP and the \fIX\-mount.idmap\fP mount option. .RE @@ -164,9 +164,9 @@ Before util\-linux version 2.39, this option expected a comma\-separated argumen Run the program only after the current effective group ID has been mapped to \fIgid\fP. If this option is specified multiple times, the last occurrence takes precedence. This option implies \fB\-\-setgroups=deny\fP and \fB\-\-user\fP. .RE .sp -\fB\-\-map\-groups=\fP\fIinnergid:outergid:count\fP|\fBauto\fP +\fB\-\-map\-groups=\fP\fIinnergid:outergid:count\fP|\fBauto\fP|\fBall\fP .RS 4 -Run the program only after the block of group IDs of size \fIcount\fP beginning at \fIoutergid\fP has been mapped to the block of group IDs beginning at \fIinnergid\fP. This mapping is created with \fBnewgidmap\fP(1). If the range of group IDs overlaps with the mapping specified by \fB\-\-map\-group\fP, then a "hole" will be removed from the mapping. This may result in the highest group ID of the mapping not being mapped. The special value \fBauto\fP will map the first block of user IDs owned by the effective user from \fI/etc/subgid\fP to a block starting at group ID 0. If this option is specified multiple times, the last occurrence takes precedence. This option implies \fB\-\-user\fP. +Run the program only after the block of group IDs of size \fIcount\fP beginning at \fIoutergid\fP has been mapped to the block of group IDs beginning at \fIinnergid\fP. This mapping is created with \fBnewgidmap\fP(1) if \fBunshare\fP was run unprivileged. If the range of group IDs overlaps with the mapping specified by \fB\-\-map\-group\fP, then a "hole" will be removed from the mapping. This may result in the highest group ID of the mapping not being mapped. Use \fB\-\-map\-groups\fP multiple times to map more than one block of group IDs. The special value \fBauto\fP will map the first block of user IDs owned by the effective user from \fI/etc/subgid\fP to a block starting at group ID 0. The special value \fBall\fP will create a pass\-through map for every group ID available in the parent namespace. This option implies \fB\-\-user\fP. .sp Before util\-linux version 2.39, this option expected a comma\-separated argument of the form \fIoutergid,innergid,count\fP but that format is now deprecated for consistency with the ordering used in \fI/proc/[pid]/gid_map\fP and the \fIX\-mount.idmap\fP mount option. .RE diff --git a/sys-utils/unshare.1.adoc b/sys-utils/unshare.1.adoc index 670774a..e6201e2 100644 --- a/sys-utils/unshare.1.adoc +++ b/sys-utils/unshare.1.adoc @@ -93,16 +93,16 @@ Just before running the program, mount the proc filesystem at _mountpoint_ (defa **--map-user=**__uid|name__:: Run the program only after the current effective user ID has been mapped to _uid_. If this option is specified multiple times, the last occurrence takes precedence. This option implies *--user*. -**--map-users=**__inneruid:outeruid:count__|**auto**:: -Run the program only after the block of user IDs of size _count_ beginning at _outeruid_ has been mapped to the block of user IDs beginning at _inneruid_. This mapping is created with **newuidmap**(1). If the range of user IDs overlaps with the mapping specified by *--map-user*, then a "hole" will be removed from the mapping. This may result in the highest user ID of the mapping not being mapped. The special value *auto* will map the first block of user IDs owned by the effective user from _/etc/subuid_ to a block starting at user ID 0. If this option is specified multiple times, the last occurrence takes precedence. This option implies *--user*. +**--map-users=**__inneruid:outeruid:count__|**auto**|**all**:: +Run the program only after the block of user IDs of size _count_ beginning at _outeruid_ has been mapped to the block of user IDs beginning at _inneruid_. This mapping is created with **newuidmap**(1) if *unshare* was run unprivileged. If the range of user IDs overlaps with the mapping specified by *--map-user*, then a "hole" will be removed from the mapping. This may result in the highest user ID of the mapping not being mapped. Use *--map-users* multiple times to map more than one block of user IDs. The special value *auto* will map the first block of user IDs owned by the effective user from _/etc/subuid_ to a block starting at user ID 0. The special value *all* will create a pass-through map for every user ID available in the parent namespace. This option implies *--user*. + Before util-linux version 2.39, this option expected a comma-separated argument of the form _outeruid,inneruid,count_ but that format is now deprecated for consistency with the ordering used in _/proc/[pid]/uid_map_ and the _X-mount.idmap_ mount option. **--map-group=**__gid|name__:: Run the program only after the current effective group ID has been mapped to _gid_. If this option is specified multiple times, the last occurrence takes precedence. This option implies *--setgroups=deny* and *--user*. -**--map-groups=**__innergid:outergid:count__|**auto**:: -Run the program only after the block of group IDs of size _count_ beginning at _outergid_ has been mapped to the block of group IDs beginning at _innergid_. This mapping is created with **newgidmap**(1). If the range of group IDs overlaps with the mapping specified by *--map-group*, then a "hole" will be removed from the mapping. This may result in the highest group ID of the mapping not being mapped. The special value *auto* will map the first block of user IDs owned by the effective user from _/etc/subgid_ to a block starting at group ID 0. If this option is specified multiple times, the last occurrence takes precedence. This option implies *--user*. +**--map-groups=**__innergid:outergid:count__|**auto**|**all**:: +Run the program only after the block of group IDs of size _count_ beginning at _outergid_ has been mapped to the block of group IDs beginning at _innergid_. This mapping is created with **newgidmap**(1) if *unshare* was run unprivileged. If the range of group IDs overlaps with the mapping specified by *--map-group*, then a "hole" will be removed from the mapping. This may result in the highest group ID of the mapping not being mapped. Use *--map-groups* multiple times to map more than one block of group IDs. The special value *auto* will map the first block of user IDs owned by the effective user from _/etc/subgid_ to a block starting at group ID 0. The special value *all* will create a pass-through map for every group ID available in the parent namespace. This option implies *--user*. + Before util-linux version 2.39, this option expected a comma-separated argument of the form _outergid,innergid,count_ but that format is now deprecated for consistency with the ordering used in _/proc/[pid]/gid_map_ and the _X-mount.idmap_ mount option. diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c index 29fad71..ccb0834 100644 --- a/sys-utils/unshare.c +++ b/sys-utils/unshare.c @@ -212,12 +212,12 @@ static ino_t get_mnt_ino(pid_t pid) return st.st_ino; } -static void settime(time_t offset, clockid_t clk_id) +static void settime(int64_t offset, clockid_t clk_id) { char buf[sizeof(stringify_value(ULONG_MAX)) * 3]; int fd, len; - len = snprintf(buf, sizeof(buf), "%d %" PRId64 " 0", clk_id, (int64_t) offset); + len = snprintf(buf, sizeof(buf), "%d %" PRId64 " 0", clk_id, offset); fd = open("/proc/self/timens_offsets", O_WRONLY); if (fd < 0) @@ -364,6 +364,7 @@ static gid_t get_group(const char *s, const char *err) * @outer: First ID mapped on the outside of the namespace * @inner: First ID mapped on the inside of the namespace * @count: Length of the inside and outside ranges + * @next: Next range of IDs in the chain * * A range of uids/gids to map using new[gu]idmap. */ @@ -371,9 +372,16 @@ struct map_range { unsigned int outer; unsigned int inner; unsigned int count; + struct map_range *next; }; -#define UID_BUFSIZ sizeof(stringify_value(ULONG_MAX)) +static void insert_map_range(struct map_range **chain, struct map_range map) +{ + struct map_range *tail = *chain; + *chain = xmalloc(sizeof(**chain)); + memcpy(*chain, &map, sizeof(**chain)); + (*chain)->next = tail; +} /** * get_map_range() - Parse a mapping range from a string @@ -382,20 +390,18 @@ struct map_range { * Parse a string of the form inner:outer:count or outer,inner,count into * a new mapping range. * - * Return: A new &struct map_range + * Return: A struct map_range */ -static struct map_range *get_map_range(const char *s) +static struct map_range get_map_range(const char *s) { int end; - struct map_range *ret; - - ret = xmalloc(sizeof(*ret)); + struct map_range ret = { .next = NULL }; - if (sscanf(s, "%u:%u:%u%n", &ret->inner, &ret->outer, &ret->count, + if (sscanf(s, "%u:%u:%u%n", &ret.inner, &ret.outer, &ret.count, &end) >= 3 && !s[end]) return ret; /* inner:outer:count */ - if (sscanf(s, "%u,%u,%u%n", &ret->outer, &ret->inner, &ret->count, + if (sscanf(s, "%u,%u,%u%n", &ret.outer, &ret.inner, &ret.count, &end) >= 3 && !s[end]) return ret; /* outer,inner,count */ @@ -410,16 +416,13 @@ static struct map_range *get_map_range(const char *s) * * This finds the first subid range matching @uid in @filename. */ -static struct map_range *read_subid_range(char *filename, uid_t uid) +static struct map_range read_subid_range(char *filename, uid_t uid) { char *line = NULL, *pwbuf; FILE *idmap; size_t n = 0; struct passwd *pw; - struct map_range *map; - - map = xmalloc(sizeof(*map)); - map->inner = -1; + struct map_range map = { .inner = -1, .next = NULL }; pw = xgetpwuid(uid, &pwbuf); if (!pw) @@ -452,13 +455,13 @@ static struct map_range *read_subid_range(char *filename, uid_t uid) if (!rest) continue; *rest = '\0'; - map->outer = strtoul_or_err(s, _("failed to parse subid map")); + map.outer = strtoul_or_err(s, _("failed to parse subid map")); s = rest + 1; rest = strchr(s, '\n'); if (rest) *rest = '\0'; - map->count = strtoul_or_err(s, _("failed to parse subid map")); + map.count = strtoul_or_err(s, _("failed to parse subid map")); fclose(idmap); free(pw); @@ -472,129 +475,203 @@ static struct map_range *read_subid_range(char *filename, uid_t uid) } /** - * map_ids() - Create a new uid/gid map - * @idmapper: Either newuidmap or newgidmap - * @ppid: Pid to set the map for - * @outer: ID outside the namespace for a single map. - * @inner: ID inside the namespace for a single map. May be -1 to only use @map. - * @map: A range of IDs to map + * read_kernel_map() - Read all available IDs from the kernel + * @chain: destination list to receive pass-through ID mappings + * @filename: either /proc/self/uid_map or /proc/self/gid_map * - * This creates a new uid/gid map for @ppid using @idmapper. The ID @outer in - * the parent (our) namespace is mapped to the ID @inner in the child (@ppid's) - * namespace. In addition, the range of IDs beginning at @map->outer is mapped - * to the range of IDs beginning at @map->inner. The tricky bit is that we - * cannot let these mappings overlap. We accomplish this by removing a "hole" - * from @map, if @outer or @inner overlap it. This may result in one less than - * @map->count IDs being mapped from @map. The unmapped IDs are always the - * topmost IDs of the mapping (either in the parent or the child namespace). + * This is used by --map-users=all and --map-groups=all to construct + * pass-through mappings for all IDs available in the parent namespace. + */ +static void read_kernel_map(struct map_range **chain, char *filename) +{ + char *line = NULL; + size_t size = 0; + FILE *idmap; + + idmap = fopen(filename, "r"); + if (!idmap) + err(EXIT_FAILURE, _("could not open '%s'"), filename); + + while (getline(&line, &size, idmap) != -1) { + unsigned int start, count; + if (sscanf(line, " %u %*u %u", &start, &count) < 2) + continue; + insert_map_range(chain, (struct map_range) { + .inner = start, + .outer = start, + .count = count + }); + } + + fclose(idmap); + free(line); +} + +/** + * add_single_map_range() - Add a single-ID map into a list without overlap + * @chain: A linked list of ID range mappings + * @outer: ID outside the namespace for a single map. + * @inner: ID inside the namespace for a single map, or -1 for no map. * - * Most of the time, this function will be called with @map->outer as some - * large ID, @map->inner as 0, and @map->count as a large number (at least - * 1000, but less than @map->outer). Typically, there will be no conflict with - * @outer. However, @inner may split the mapping for e.g. --map-current-user. + * Prepend a mapping to @chain for the single ID @outer to the single ID + * @inner. The tricky bit is that we cannot let existing mappings overlap it. + * We accomplish this by removing a "hole" from each existing range @map, if + * @outer or @inner overlap it. This may result in one less than @map->count + * IDs being mapped from @map. The unmapped IDs are always the topmost IDs + * of the mapping (either in the parent or the child namespace). * - * This function always exec()s or errors out and does not return. + * Most of the time, this function will be called with a single mapping range + * @map, @map->outer as some large ID, @map->inner as 0, and @map->count as a + * large number (at least 1000, but less than @map->outer). Typically, there + * will be no conflict with @outer. However, @inner may split the mapping for + * e.g. --map-current-user. */ -static void __attribute__((__noreturn__)) -map_ids(const char *idmapper, int ppid, unsigned int outer, unsigned int inner, - struct map_range *map) + +static void add_single_map_range(struct map_range **chain, unsigned int outer, + unsigned int inner) { - /* idmapper + pid + 4 * map + NULL */ - char *argv[15]; - /* argv - idmapper - "1" - NULL */ - char args[12][UID_BUFSIZ]; - int i = 0, j = 0; - struct map_range lo, mid, hi; - unsigned int inner_offset, outer_offset; - - /* Some helper macros to reduce bookkeeping */ -#define push_str(s) do { \ - argv[i++] = s; \ -} while (0) -#define push_ul(x) do { \ - snprintf(args[j], sizeof(args[j]), "%u", x); \ - push_str(args[j++]); \ -} while (0) - - push_str(xstrdup(idmapper)); - push_ul(ppid); - if ((int)inner == -1) { + struct map_range *map = *chain; + + if (inner + 1 == 0) + outer = (unsigned int) -1; + *chain = NULL; + + while (map) { + struct map_range lo = { 0 }, mid = { 0 }, hi = { 0 }, + *next = map->next; + unsigned int inner_offset, outer_offset; + /* - * If we don't have a "single" mapping, then we can just use map - * directly, starting inner IDs from zero for an auto mapping + * Start inner IDs from zero for an auto mapping; otherwise, if + * the single mapping exists and overlaps the range, remove an ID */ - push_ul(map->inner + 1 ? map->inner : 0); - push_ul(map->outer); - push_ul(map->count); - push_str(NULL); + if (map->inner + 1 == 0) + map->inner = 0; + else if (inner + 1 != 0 && + ((outer >= map->outer && outer <= map->outer + map->count) || + (inner >= map->inner && inner <= map->inner + map->count))) + map->count--; + + /* Determine where the splits between lo, mid, and hi will be */ + outer_offset = min(outer > map->outer ? outer - map->outer : 0, + map->count); + inner_offset = min(inner > map->inner ? inner - map->inner : 0, + map->count); - execvp(idmapper, argv); - errexec(idmapper); + /* + * In the worst case, we need three mappings: + * From the bottom of map to either inner or outer + */ + lo.outer = map->outer; + lo.inner = map->inner; + lo.count = min(inner_offset, outer_offset); + + /* From the lower of inner or outer to the higher */ + mid.outer = lo.outer + lo.count; + mid.outer += mid.outer == outer; + mid.inner = lo.inner + lo.count; + mid.inner += mid.inner == inner; + mid.count = abs_diff(outer_offset, inner_offset); + + /* And from the higher of inner or outer to the end of the map */ + hi.outer = mid.outer + mid.count; + hi.outer += hi.outer == outer; + hi.inner = mid.inner + mid.count; + hi.inner += hi.inner == inner; + hi.count = map->count - lo.count - mid.count; + + /* Insert non-empty mappings into the output chain */ + if (hi.count) + insert_map_range(chain, hi); + if (mid.count) + insert_map_range(chain, mid); + if (lo.count) + insert_map_range(chain, lo); + + free(map); + map = next; } - /* - * Start inner IDs from zero for an auto mapping; otherwise, if the two - * fixed mappings overlap, remove an ID from map - */ - if (map->inner + 1 == 0) - map->inner = 0; - else if ((outer >= map->outer && outer <= map->outer + map->count) || - (inner >= map->inner && inner <= map->inner + map->count)) - map->count--; - - /* Determine where the splits between lo, mid, and hi will be */ - outer_offset = min(outer > map->outer ? outer - map->outer : 0, - map->count); - inner_offset = min(inner > map->inner ? inner - map->inner : 0, - map->count); - - /* - * In the worst case, we need three mappings: - * From the bottom of map to either inner or outer - */ - lo.outer = map->outer; - lo.inner = map->inner; - lo.count = min(inner_offset, outer_offset); - - /* From the lower of inner or outer to the higher */ - mid.outer = lo.outer + lo.count; - mid.outer += mid.outer == outer; - mid.inner = lo.inner + lo.count; - mid.inner += mid.inner == inner; - mid.count = abs_diff(outer_offset, inner_offset); - - /* And from the higher of inner or outer to the end of the map */ - hi.outer = mid.outer + mid.count; - hi.outer += hi.outer == outer; - hi.inner = mid.inner + mid.count; - hi.inner += hi.inner == inner; - hi.count = map->count - lo.count - mid.count; - - push_ul(inner); - push_ul(outer); - push_str("1"); - /* new[gu]idmap doesn't like zero-length mappings, so skip them */ - if (lo.count) { - push_ul(lo.inner); - push_ul(lo.outer); - push_ul(lo.count); + if (inner + 1 != 0) { + /* Insert single ID mapping as the first entry in the chain */ + insert_map_range(chain, (struct map_range) { + .inner = inner, + .outer = outer, + .count = 1 + }); } - if (mid.count) { - push_ul(mid.inner); - push_ul(mid.outer); - push_ul(mid.count); - } - if (hi.count) { - push_ul(hi.inner); - push_ul(hi.outer); - push_ul(hi.count); +} + +/** + * map_ids_external() - Create a new uid/gid map using setuid helper + * @idmapper: Either newuidmap or newgidmap + * @ppid: Pid to set the map for + * @chain: A linked list of ID range mappings + * + * This creates a new uid/gid map for @ppid using @idmapper to set the + * mapping for each of the ranges in @chain. + * + * This function always exec()s or errors out and does not return. + */ +static void __attribute__((__noreturn__)) +map_ids_external(const char *idmapper, int ppid, struct map_range *chain) +{ + unsigned int i = 0, length = 3; + char **argv; + + for (struct map_range *map = chain; map; map = map->next) + length += 3; + argv = xcalloc(length, sizeof(*argv)); + argv[i++] = xstrdup(idmapper); + xasprintf(&argv[i++], "%u", ppid); + + for (struct map_range *map = chain; map; map = map->next) { + xasprintf(&argv[i++], "%u", map->inner); + xasprintf(&argv[i++], "%u", map->outer); + xasprintf(&argv[i++], "%u", map->count); } - push_str(NULL); + + argv[i] = NULL; execvp(idmapper, argv); errexec(idmapper); } /** + * map_ids_internal() - Create a new uid/gid map using root privilege + * @type: Either uid_map or gid_map + * @ppid: Pid to set the map for + * @chain: A linked list of ID range mappings + * + * This creates a new uid/gid map for @ppid using a privileged write to + * /proc/@ppid/@type to set a mapping for each of the ranges in @chain. + */ +static void map_ids_internal(const char *type, int ppid, struct map_range *chain) +{ + int count, fd; + unsigned int length = 0; + char buffer[4096], *path; + + xasprintf(&path, "/proc/%u/%s", ppid, type); + for (struct map_range *map = chain; map; map = map->next) { + count = snprintf(buffer + length, sizeof(buffer) - length, + "%u %u %u\n", + map->inner, map->outer, map->count); + if (count < 0 || count + length > sizeof(buffer)) + errx(EXIT_FAILURE, + _("%s too large for kernel 4k limit"), path); + length += count; + } + + fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY); + if (fd < 0) + err(EXIT_FAILURE, _("failed to open %s"), path); + if (write_all(fd, buffer, length) < 0) + err(EXIT_FAILURE, _("failed to write %s"), path); + close(fd); + free(path); +} + +/** * map_ids_from_child() - Set up a new uid/gid map * @fd: The eventfd to wait on * @mapuser: The user to map the current user to (or -1) @@ -619,6 +696,19 @@ static pid_t map_ids_from_child(int *fd, uid_t mapuser, if (child) return child; + if (usermap) + add_single_map_range(&usermap, geteuid(), mapuser); + if (groupmap) + add_single_map_range(&groupmap, getegid(), mapgroup); + + if (geteuid() == 0) { + if (usermap) + map_ids_internal("uid_map", ppid, usermap); + if (groupmap) + map_ids_internal("gid_map", ppid, groupmap); + exit(EXIT_SUCCESS); + } + /* Avoid forking more than we need to */ if (usermap && groupmap) { pid = fork(); @@ -629,9 +719,9 @@ static pid_t map_ids_from_child(int *fd, uid_t mapuser, } if (!pid && usermap) - map_ids("newuidmap", ppid, geteuid(), mapuser, usermap); + map_ids_external("newuidmap", ppid, usermap); if (groupmap) - map_ids("newgidmap", ppid, getegid(), mapgroup, groupmap); + map_ids_external("newgidmap", ppid, groupmap); exit(EXIT_SUCCESS); } @@ -683,8 +773,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" --boottime <offset> set clock boottime offset (seconds) in time namespaces\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(27)); - printf(USAGE_MAN_TAIL("unshare(1)")); + fprintf(out, USAGE_HELP_OPTIONS(27)); + fprintf(out, USAGE_MAN_TAIL("unshare(1)")); exit(EXIT_SUCCESS); } @@ -764,8 +854,8 @@ int main(int argc, char *argv[]) uid_t uid = 0, real_euid = geteuid(); gid_t gid = 0, real_egid = getegid(); int keepcaps = 0; - time_t monotonic = 0; - time_t boottime = 0; + int64_t monotonic = 0; + int64_t boottime = 0; int force_monotonic = 0; int force_boottime = 0; @@ -844,21 +934,27 @@ int main(int argc, char *argv[]) case OPT_MAPUSERS: unshare_flags |= CLONE_NEWUSER; if (!strcmp(optarg, "auto")) - usermap = read_subid_range(_PATH_SUBUID, real_euid); + insert_map_range(&usermap, + read_subid_range(_PATH_SUBUID, real_euid)); + else if (!strcmp(optarg, "all")) + read_kernel_map(&usermap, _PATH_PROC_UIDMAP); else - usermap = get_map_range(optarg); + insert_map_range(&usermap, get_map_range(optarg)); break; case OPT_MAPGROUPS: unshare_flags |= CLONE_NEWUSER; if (!strcmp(optarg, "auto")) - groupmap = read_subid_range(_PATH_SUBGID, real_euid); + insert_map_range(&groupmap, + read_subid_range(_PATH_SUBGID, real_euid)); + else if (!strcmp(optarg, "all")) + read_kernel_map(&groupmap, _PATH_PROC_GIDMAP); else - groupmap = get_map_range(optarg); + insert_map_range(&groupmap, get_map_range(optarg)); break; case OPT_MAPAUTO: unshare_flags |= CLONE_NEWUSER; - usermap = read_subid_range(_PATH_SUBUID, real_euid); - groupmap = read_subid_range(_PATH_SUBGID, real_euid); + insert_map_range(&usermap, read_subid_range(_PATH_SUBUID, real_euid)); + insert_map_range(&groupmap, read_subid_range(_PATH_SUBGID, real_euid)); break; case OPT_SETGROUPS: setgrpcmd = setgroups_str2id(optarg); @@ -895,11 +991,11 @@ int main(int argc, char *argv[]) newdir = optarg; break; case OPT_MONOTONIC: - monotonic = strtoul_or_err(optarg, _("failed to parse monotonic offset")); + monotonic = strtos64_or_err(optarg, _("failed to parse monotonic offset")); force_monotonic = 1; break; case OPT_BOOTTIME: - boottime = strtoul_or_err(optarg, _("failed to parse boottime offset")); + boottime = strtos64_or_err(optarg, _("failed to parse boottime offset")); force_boottime = 1; break; @@ -994,8 +1090,10 @@ int main(int argc, char *argv[]) int termsig = WTERMSIG(status); - if (signal(termsig, SIG_DFL) == SIG_ERR || - sigemptyset(&sigset) != 0 || + if (termsig != SIGKILL && signal(termsig, SIG_DFL) == SIG_ERR) + err(EXIT_FAILURE, + _("signal handler reset failed")); + if (sigemptyset(&sigset) != 0 || sigaddset(&sigset, termsig) != 0 || sigprocmask(SIG_UNBLOCK, &sigset, NULL) != 0) err(EXIT_FAILURE, @@ -1089,42 +1187,8 @@ int main(int argc, char *argv[]) if (force_uid && setuid(uid) < 0) /* change UID */ err(EXIT_FAILURE, _("setuid failed")); - /* We use capabilities system calls to propagate the permitted - * capabilities into the ambient set because we have already - * forked so are in async-signal-safe context. */ - if (keepcaps && (unshare_flags & CLONE_NEWUSER)) { - struct __user_cap_header_struct header = { - .version = _LINUX_CAPABILITY_VERSION_3, - .pid = 0, - }; - - struct __user_cap_data_struct payload[_LINUX_CAPABILITY_U32S_3] = {{ 0 }}; - uint64_t effective, cap; - - if (capget(&header, payload) < 0) - err(EXIT_FAILURE, _("capget failed")); - - /* In order the make capabilities ambient, we first need to ensure - * that they are all inheritable. */ - payload[0].inheritable = payload[0].permitted; - payload[1].inheritable = payload[1].permitted; - - if (capset(&header, payload) < 0) - err(EXIT_FAILURE, _("capset failed")); - - effective = ((uint64_t)payload[1].effective << 32) | (uint64_t)payload[0].effective; - - for (cap = 0; cap < (sizeof(effective) * 8); cap++) { - /* This is the same check as cap_valid(), but using - * the runtime value for the last valid cap. */ - if (cap > (uint64_t) cap_last_cap()) - continue; - - if ((effective & (1 << cap)) - && prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0) - err(EXIT_FAILURE, _("prctl(PR_CAP_AMBIENT) failed")); - } - } + if (keepcaps && (unshare_flags & CLONE_NEWUSER)) + cap_permitted_to_ambient(); if (optind < argc) { execvp(argv[optind], argv + optind); diff --git a/sys-utils/wdctl.8 b/sys-utils/wdctl.8 index 70d5ee8..6c28854 100644 --- a/sys-utils/wdctl.8 +++ b/sys-utils/wdctl.8 @@ -2,12 +2,12 @@ .\" Title: wdctl .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-10-23 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "WDCTL" "8" "2023-10-23" "util\-linux 2.39.3" "System Administration" +.TH "WDCTL" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/wdctl.c b/sys-utils/wdctl.c index 2a656b8..8611924 100644 --- a/sys-utils/wdctl.c +++ b/sys-utils/wdctl.c @@ -87,16 +87,16 @@ static const struct wdflag wdflags[] = { /* column names */ struct colinfo { - const char *name; /* header */ - double whint; /* width hint (N < 1 is in percent of termwidth) */ - int flags; /* SCOLS_FL_* */ - const char *help; + const char * const name; /* header */ + double whint; /* width hint (N < 1 is in percent of termwidth) */ + int flags; /* SCOLS_FL_* */ + const char *help; }; enum { COL_FLAG, COL_DESC, COL_STATUS, COL_BSTATUS, COL_DEVICE }; /* columns descriptions */ -static struct colinfo infos[] = { +static const struct colinfo infos[] = { [COL_FLAG] = { "FLAG", 14, 0, N_("flag name") }, [COL_DESC] = { "DESCRIPTION", 0.1, SCOLS_FL_TRUNC, N_("flag description") }, [COL_STATUS] = { "STATUS", 1, SCOLS_FL_RIGHT, N_("flag status") }, @@ -125,7 +125,12 @@ struct wd_device { struct watchdog_info ident; - unsigned int has_timeout : 1, + unsigned int has_identity : 1, + has_fw_version : 1, + has_options : 1, + has_status : 1, + has_bootstatus : 1, + has_timeout : 1, has_timeleft : 1, has_pretimeout : 1, has_nowayout : 1, @@ -188,7 +193,7 @@ static int get_column_id(int num) return columns[num]; } -static struct colinfo *get_column_info(unsigned num) +static const struct colinfo *get_column_info(unsigned num) { return &infos[ get_column_id(num) ]; } @@ -242,7 +247,7 @@ static void __attribute__((__noreturn__)) usage(void) " -x, --flags-only print only flags table (same as -I -T)\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(24)); + fprintf(out, USAGE_HELP_OPTIONS(24)); fputs(USAGE_SEPARATOR, out); if (dflt) @@ -254,7 +259,7 @@ static void __attribute__((__noreturn__)) usage(void) for (i = 0; i < ARRAY_SIZE(infos); i++) fprintf(out, " %13s %s\n", infos[i].name, _(infos[i].help)); - printf(USAGE_MAN_TAIL("wdctl(8)")); + fprintf(out, USAGE_MAN_TAIL("wdctl(8)")); exit(EXIT_SUCCESS); } @@ -354,7 +359,7 @@ static int show_flags(struct wd_control *ctl, struct wd_device *wd, uint32_t wan /* define columns */ for (i = 0; i < (size_t) ncolumns; i++) { - struct colinfo *col = get_column_info(i); + const struct colinfo *col = get_column_info(i); if (!scols_table_new_column(table, col->name, col->whint, col->flags)) { warnx(_("failed to allocate output column")); @@ -401,7 +406,7 @@ static int set_watchdog(struct wd_control *ctl, struct wd_device *wd) assert(wd->devpath); assert(ctl); - if (!ctl->set_timeout && !ctl->set_timeout) + if (!ctl->set_timeout && !ctl->set_pretimeout) goto sysfs_only; sigemptyset(&oldsigs); @@ -549,13 +554,16 @@ static int read_watchdog_from_sysfs(struct wd_device *wd) if (!sys) return 1; - ul_path_read_buffer(sys, (char *) wd->ident.identity, sizeof(wd->ident.identity), "identity"); - ul_path_read_u32(sys, &wd->ident.firmware_version, "fw_version"); - ul_path_scanf(sys, "options", "%x", &wd->ident.options); - - ul_path_scanf(sys, "status", "%x", &wd->status); - ul_path_read_u32(sys, &wd->bstatus, "bootstatus"); - + if (ul_path_read_buffer(sys, (char *) wd->ident.identity, sizeof(wd->ident.identity), "identity") >= 0) + wd->has_identity = 1; + if (ul_path_read_u32(sys, &wd->ident.firmware_version, "fw_version") == 0) + wd->has_fw_version = 1; + if (ul_path_scanf(sys, "options", "%x", &wd->ident.options) == 1) + wd->has_options = 1; + if (ul_path_scanf(sys, "status", "%x", &wd->status) == 1) + wd->has_status = 1; + if (ul_path_read_u32(sys, &wd->bstatus, "bootstatus") == 0) + wd->has_bootstatus = 1; if (ul_path_read_s32(sys, &wd->nowayout, "nowayout") == 0) wd->has_nowayout = 1; if (ul_path_read_s32(sys, &wd->timeout, "timeout") == 0) @@ -598,12 +606,32 @@ static int read_governors(struct wd_device *wd) return 0; } +static bool should_read_from_device(struct wd_device *wd) +{ + if (!wd->has_nowayout) + return false; + + if (wd->nowayout) + return false; + + return !wd->has_identity || + !wd->has_fw_version || + !wd->has_options || + !wd->has_status || + !wd->has_bootstatus || + !wd->has_timeout || + !wd->has_timeleft; + // pretimeout attribute may be hidden in sysfs +} + static int read_watchdog(struct wd_device *wd) { - int rc = read_watchdog_from_device(wd); + int rc; + + rc = read_watchdog_from_sysfs(wd); - if (rc == -EBUSY || rc == -EACCES || rc == -EPERM) - rc = read_watchdog_from_sysfs(wd); + if (rc && should_read_from_device(wd)) + rc = read_watchdog_from_device(wd); if (rc) { warn(_("cannot read information about %s"), wd->devpath); diff --git a/sys-utils/zramctl.8 b/sys-utils/zramctl.8 index 50deb4c..ca545ff 100644 --- a/sys-utils/zramctl.8 +++ b/sys-utils/zramctl.8 @@ -2,12 +2,12 @@ .\" Title: zramctl .\" Author: [see the "AUTHOR(S)" section] .\" Generator: Asciidoctor 2.0.20 -.\" Date: 2023-11-21 +.\" Date: 2024-01-31 .\" Manual: System Administration -.\" Source: util-linux 2.39.3 +.\" Source: util-linux 2.40 .\" Language: English .\" -.TH "ZRAMCTL" "8" "2023-11-21" "util\-linux 2.39.3" "System Administration" +.TH "ZRAMCTL" "8" "2024-01-31" "util\-linux 2.40" "System Administration" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 diff --git a/sys-utils/zramctl.c b/sys-utils/zramctl.c index a84ce66..cc32ab4 100644 --- a/sys-utils/zramctl.c +++ b/sys-utils/zramctl.c @@ -559,10 +559,10 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -t, --streams <number> number of compression streams\n"), out); fputs(USAGE_SEPARATOR, out); - printf(USAGE_HELP_OPTIONS(27)); + fprintf(out, USAGE_HELP_OPTIONS(27)); fputs(USAGE_ARGUMENTS, out); - printf(USAGE_ARG_SIZE(_("<size>"))); + fprintf(out, USAGE_ARG_SIZE(_("<size>"))); fputs(_(" <alg> specify algorithm, supported are:\n"), out); fputs(_(" lzo, lz4, lz4hc, deflate, 842 and zstd\n"), out); @@ -572,7 +572,7 @@ static void __attribute__((__noreturn__)) usage(void) for (i = 0; i < ARRAY_SIZE(infos); i++) fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help)); - printf(USAGE_MAN_TAIL("zramctl(8)")); + fprintf(out, USAGE_MAN_TAIL("zramctl(8)")); exit(EXIT_SUCCESS); } |