* [PATCH 3/3] treewide: consistently use tabs for indentation where it is the rule
From: Benno Schulenberg @ 2025-12-09 15:02 UTC (permalink / raw)
To: util-linux
In-Reply-To: <20251209150222.50981-1-bensberg@telfort.nl>
Also unwrap a line, delete two blank lines, and improve three comments.
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
disk-utils/blockdev.c | 20 ++--
disk-utils/cfdisk.c | 8 +-
disk-utils/fdformat.c | 2 +-
| 10 +-
disk-utils/fdisk.c | 6 +-
disk-utils/mkfs.bfs.c | 2 +-
disk-utils/mkfs.cramfs.c | 6 +-
disk-utils/mkswap.c | 3 +-
disk-utils/sfdisk.c | 4 +-
lib/buffer.c | 2 +-
lib/env.c | 86 ++++++++---------
lib/fileeq.c | 2 +-
lib/ismounted.c | 32 +++---
lib/logindefs.c | 46 ++++-----
lib/loopdev.c | 38 ++++----
lib/procfs.c | 4 +-
lib/pty-session.c | 6 +-
lib/shells.c | 54 +++++------
lib/strutils.c | 148 ++++++++++++++--------------
lib/sysfs.c | 171 ++++++++++++++++-----------------
lib/timer.c | 2 +-
login-utils/login.c | 4 +-
login-utils/sulogin-consoles.c | 10 +-
misc-utils/findmnt.c | 16 +--
misc-utils/lastlog2.c | 7 +-
misc-utils/lsblk-devtree.c | 16 +--
misc-utils/rename.c | 4 +-
sys-utils/ipcrm.c | 2 +-
sys-utils/ldattach.c | 6 +-
sys-utils/losetup.c | 2 +-
sys-utils/lscpu-topology.c | 2 +-
sys-utils/lsns.c | 16 +--
sys-utils/swapoff.c | 2 +-
sys-utils/tunelp.c | 4 +-
sys-utils/unshare.c | 16 +--
sys-utils/zramctl.c | 6 +-
term-utils/agetty.c | 14 +--
term-utils/mesg.c | 4 +-
term-utils/script.c | 2 +-
term-utils/scriptreplay.c | 4 +-
text-utils/col.c | 65 ++++++-------
text-utils/hexdump-display.c | 4 +-
text-utils/hexdump-parse.c | 10 +-
text-utils/hexdump.c | 2 +-
44 files changed, 433 insertions(+), 437 deletions(-)
diff --git a/disk-utils/blockdev.c b/disk-utils/blockdev.c
index 55b47acf6..3ef74aa22 100644
--- a/disk-utils/blockdev.c
+++ b/disk-utils/blockdev.c
@@ -140,7 +140,7 @@ static const struct bdc bdcms[] =
.argname = "<bytes>",
.argtype = ARG_INT,
.flags = FL_NORESULT,
- .help = N_("set blocksize on file descriptor opening the block device")
+ .help = N_("set blocksize on file descriptor opening the block device")
},{
IOCTL_ENTRY(BLKGETSIZE),
.name = "--getsize",
@@ -210,23 +210,23 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(USAGE_HEADER, stdout);
fprintf(stdout, _(
- " %1$s [-v|-q] commands devices\n"
- " %1$s --report [devices]\n"
- " %1$s -h|-V\n"
- ), program_invocation_short_name);
+ " %1$s [-v|-q] commands devices\n"
+ " %1$s --report [devices]\n"
+ " %1$s -h|-V\n"
+ ), program_invocation_short_name);
fputs(USAGE_SEPARATOR, stdout);
- fputsln( _("Call block device ioctls from the command line."), stdout);
+ fputsln(_("Call block device ioctls from the command line."), stdout);
fputs(USAGE_OPTIONS, stdout);
- fputsln( _(" -q quiet mode"), stdout);
- fputsln( _(" -v verbose mode"), stdout);
- fputsln( _(" --report print report for specified (or all) devices"), stdout);
+ fputsln(_(" -q quiet mode"), stdout);
+ fputsln(_(" -v verbose mode"), stdout);
+ fputsln(_(" --report print report for specified (or all) devices"), stdout);
fputs(USAGE_SEPARATOR, stdout);
fprintf(stdout, USAGE_HELP_OPTIONS(16));
fputs(USAGE_SEPARATOR, stdout);
- fputsln( _("Available commands:"), stdout);
+ fputsln(_("Available commands:"), stdout);
fprintf(stdout, _(" %-25s get size in 512-byte sectors\n"), "--getsz");
for (i = 0; i < ARRAY_SIZE(bdcms); i++) {
if (bdcms[i].argname)
diff --git a/disk-utils/cfdisk.c b/disk-utils/cfdisk.c
index e4e16001e..e2f1cd74d 100644
--- a/disk-utils/cfdisk.c
+++ b/disk-utils/cfdisk.c
@@ -1760,7 +1760,7 @@ static int ui_refresh(struct cfdisk *cf)
{
struct fdisk_label *lb;
char *id = NULL;
- uint64_t bytes = fdisk_get_nsectors(cf->cxt) * fdisk_get_sector_size(cf->cxt);
+ uint64_t bytes = fdisk_get_nsectors(cf->cxt) * fdisk_get_sector_size(cf->cxt);
char *strsz;
if (!ui_enabled)
@@ -2783,9 +2783,9 @@ int main(int argc, char *argv[])
if (optarg)
colormode = colormode_or_err(optarg);
break;
- case 'r':
- read_only = 1;
- break;
+ case 'r':
+ read_only = 1;
+ break;
case 'V':
print_version(EXIT_SUCCESS);
case 'z':
diff --git a/disk-utils/fdformat.c b/disk-utils/fdformat.c
index 49cb51d8a..04e414a53 100644
--- a/disk-utils/fdformat.c
+++ b/disk-utils/fdformat.c
@@ -164,7 +164,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -f, --from <N> start at the track N (default 0)\n"), out);
fputs(_(" -t, --to <N> stop at the track N\n"), out);
fputs(_(" -r, --repair <N> try to repair tracks failed during\n"
- " the verification (max N retries)\n"), out);
+ " the verification (max N retries)\n"), out);
fputs(_(" -n, --no-verify disable the verification after the format\n"), out);
fputs(USAGE_SEPARATOR, out);
--git a/disk-utils/fdisk-menu.c b/disk-utils/fdisk-menu.c
index 707394d4e..f3c9f154e 100644
--- a/disk-utils/fdisk-menu.c
+++ b/disk-utils/fdisk-menu.c
@@ -499,9 +499,9 @@ static int script_read(struct fdisk_context *cxt)
fdisk_warnx(cxt, _("Failed to apply script %s"), filename);
fdisk_warnx(cxt, _("Resetting fdisk!"));
rc = fdisk_reassign_device(cxt);
- if (rc == 0 && !fdisk_has_label(cxt)) {
- fdisk_info(cxt, _("Device does not contain a recognized partition table."));
- rc = fdisk_create_disklabel(cxt, NULL);
+ if (rc == 0 && !fdisk_has_label(cxt)) {
+ fdisk_info(cxt, _("Device does not contain a recognized partition table."));
+ rc = fdisk_create_disklabel(cxt, NULL);
}
} else
fdisk_info(cxt, _("Script successfully applied."));
@@ -751,8 +751,8 @@ static int gpt_menu_cb(struct fdisk_context **cxt0,
case 'i':
return fdisk_set_disklabel_id(cxt);
case 'l':
- rc = fdisk_ask_number(cxt, 1, fdisk_get_npartitions(cxt),
- ~(uint32_t)0, _("New maximum entries"), &length);
+ rc = fdisk_ask_number(cxt, 1, fdisk_get_npartitions(cxt),
+ ~(uint32_t)0, _("New maximum entries"), &length);
if (rc)
return rc;
return fdisk_gpt_set_npartitions(cxt, (uint32_t) length);
diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c
index 72feed587..f44a4899e 100644
--- a/disk-utils/fdisk.c
+++ b/disk-utils/fdisk.c
@@ -494,11 +494,11 @@ static struct fdisk_parttype *ask_partition_type(struct fdisk_context *cxt, int
*canceled = 0;
if (fdisk_label_has_parttypes_shortcuts(lb))
- q = fdisk_label_has_code_parttypes(lb) ?
+ q = fdisk_label_has_code_parttypes(lb) ?
_("Hex code or alias (type L to list all): ") :
_("Partition type or alias (type L to list all): ");
else
- q = fdisk_label_has_code_parttypes(lb) ?
+ q = fdisk_label_has_code_parttypes(lb) ?
_("Hex code (type L to list all codes): ") :
_("Partition type (type L to list all types): ");
do {
@@ -523,7 +523,7 @@ static struct fdisk_parttype *ask_partition_type(struct fdisk_context *cxt, int
fdisk_info(cxt, _("Failed to parse '%s' partition type."), buf);
return t;
}
- } while (1);
+ } while (1);
return NULL;
}
diff --git a/disk-utils/mkfs.bfs.c b/disk-utils/mkfs.bfs.c
index 30c28d9e7..838fb59b4 100644
--- a/disk-utils/mkfs.bfs.c
+++ b/disk-utils/mkfs.bfs.c
@@ -184,7 +184,7 @@ int main(int argc, char **argv)
/* when called via mkfs we may get options c,l,v */
break;
- case OPT_LOCK:
+ case OPT_LOCK:
lockmode = "1";
if (optarg) {
if (*optarg == '=')
diff --git a/disk-utils/mkfs.cramfs.c b/disk-utils/mkfs.cramfs.c
index a91016d26..0b1695e77 100644
--- a/disk-utils/mkfs.cramfs.c
+++ b/disk-utils/mkfs.cramfs.c
@@ -764,9 +764,9 @@ int main(int argc, char **argv)
fslen_ub += (image_length + 3); /* 3 is for padding */
break;
case 'l':
- lockmode = "1";
+ lockmode = "1";
if (optarg) {
- if (*optarg == '=')
+ if (*optarg == '=')
optarg++;
lockmode = optarg;
}
@@ -810,7 +810,7 @@ int main(int argc, char **argv)
if (fd < 0)
err(MKFS_EX_USAGE, _("cannot open %s"), outfile);
- if (blkdev_lock(fd, outfile, lockmode) != 0)
+ if (blkdev_lock(fd, outfile, lockmode) != 0)
exit(MKFS_EX_ERROR);
root_entry = xcalloc(1, sizeof(struct entry));
diff --git a/disk-utils/mkswap.c b/disk-utils/mkswap.c
index 3cb7a043b..17ec1603f 100644
--- a/disk-utils/mkswap.c
+++ b/disk-utils/mkswap.c
@@ -800,8 +800,7 @@ int main(int argc, char **argv)
deinit_signature_page(&ctl);
#ifdef HAVE_LIBSELINUX
- if ((ctl.file || S_ISREG(ctl.devstat.st_mode)) &&
- is_selinux_enabled() > 0) {
+ if ((ctl.file || S_ISREG(ctl.devstat.st_mode)) && is_selinux_enabled() > 0) {
const char *context_string;
char *oldcontext;
context_t newcontext;
diff --git a/disk-utils/sfdisk.c b/disk-utils/sfdisk.c
index b691cb084..aeab826c2 100644
--- a/disk-utils/sfdisk.c
+++ b/disk-utils/sfdisk.c
@@ -478,7 +478,7 @@ static int move_partition_data(struct sfdisk *sf, size_t partno, struct fdisk_pa
fdisk_info(sf->cxt, _(" typescript file: %s"), typescript);
printf(_(" start sector: (from/to) %ju / %ju\n"), (uintmax_t) from, (uintmax_t) to);
printf(_(" sectors: %ju\n"), (uintmax_t) nsectors);
- printf(_(" step size: %zu bytes\n"), step_bytes);
+ printf(_(" step size: %zu bytes\n"), step_bytes);
putchar('\n');
fflush(stdout);
@@ -602,7 +602,7 @@ static int move_partition_data(struct sfdisk *sf, size_t partno, struct fdisk_pa
i + 1, nsectors,
100.0 / ((double) nsectors/(i+1)));
fflush(stdout);
- fputc('\r', stdout);
+ fputc('\r', stdout);
}
next:
diff --git a/lib/buffer.c b/lib/buffer.c
index bdc4744bc..76aefe950 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -303,6 +303,6 @@ int main(void)
ul_buffer_free_data(&buf);
- return EXIT_SUCCESS;
+ return EXIT_SUCCESS;
}
#endif /* TEST_PROGRAM_BUFFER */
diff --git a/lib/env.c b/lib/env.c
index 039fad0dc..e5e66337f 100644
--- a/lib/env.c
+++ b/lib/env.c
@@ -27,28 +27,28 @@ extern char **environ;
#endif
static char * const forbid[] = {
- "BASH_ENV=", /* GNU creeping featurism strikes again... */
- "ENV=",
- "HOME=",
- "IFS=",
- "KRB_CONF=",
- "LD_", /* anything with the LD_ prefix */
- "LIBPATH=",
- "MAIL=",
- "NLSPATH=",
- "PATH=",
- "SHELL=",
- "SHLIB_PATH=",
- (char *) 0
+ "BASH_ENV=", /* GNU creeping featurism strikes again... */
+ "ENV=",
+ "HOME=",
+ "IFS=",
+ "KRB_CONF=",
+ "LD_", /* anything with the LD_ prefix */
+ "LIBPATH=",
+ "MAIL=",
+ "NLSPATH=",
+ "PATH=",
+ "SHELL=",
+ "SHLIB_PATH=",
+ (char *) 0
};
/* these are allowed, but with no slashes inside
(to work around security problems in GNU gettext) */
static char * const noslash[] = {
- "LANG=",
- "LANGUAGE=",
- "LC_", /* anything with the LC_ prefix */
- (char *) 0
+ "LANG=",
+ "LANGUAGE=",
+ "LC_", /* anything with the LC_ prefix */
+ (char *) 0
};
@@ -218,39 +218,39 @@ void env_list_free(struct ul_env_list *ls)
*/
void __sanitize_env(struct ul_env_list **org)
{
- char **envp = environ;
- char * const *bad;
- char **cur;
- int last = 0;
+ char **envp = environ;
+ char * const *bad;
+ char **cur;
+ int last = 0;
- for (cur = envp; *cur; cur++)
- last++;
+ for (cur = envp; *cur; cur++)
+ last++;
- for (cur = envp; *cur; cur++) {
- for (bad = forbid; *bad; bad++) {
- if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
+ for (cur = envp; *cur; cur++) {
+ for (bad = forbid; *bad; bad++) {
+ if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
if (org)
*org = env_list_add_from_string(*org, *cur);
- last = ul_remove_entry(envp, cur - envp, last);
- cur--;
- break;
- }
- }
- }
+ last = ul_remove_entry(envp, cur - envp, last);
+ cur--;
+ break;
+ }
+ }
+ }
- for (cur = envp; *cur; cur++) {
- for (bad = noslash; *bad; bad++) {
- if (strncmp(*cur, *bad, strlen(*bad)) != 0)
- continue;
- if (!strchr(*cur, '/'))
- continue; /* OK */
+ for (cur = envp; *cur; cur++) {
+ for (bad = noslash; *bad; bad++) {
+ if (strncmp(*cur, *bad, strlen(*bad)) != 0)
+ continue;
+ if (!strchr(*cur, '/'))
+ continue; /* OK */
if (org)
*org = env_list_add_from_string(*org, *cur);
- last = ul_remove_entry(envp, cur - envp, last);
- cur--;
- break;
- }
- }
+ last = ul_remove_entry(envp, cur - envp, last);
+ cur--;
+ break;
+ }
+ }
}
void sanitize_env(void)
diff --git a/lib/fileeq.c b/lib/fileeq.c
index ffd208962..762619563 100644
--- a/lib/fileeq.c
+++ b/lib/fileeq.c
@@ -335,7 +335,7 @@ static int get_fd(struct ul_fileeq *eq, struct ul_fileeq_data *data, off_t *off)
return data->fd;
#if defined(POSIX_FADV_SEQUENTIAL) && defined(HAVE_POSIX_FADVISE)
- ignore_result( posix_fadvise(data->fd, o, 0, POSIX_FADV_SEQUENTIAL) );
+ ignore_result( posix_fadvise(data->fd, o, 0, POSIX_FADV_SEQUENTIAL) );
#endif
if (o) {
DBG(DATA, ul_debugobj(data, "lseek off=%ju", (uintmax_t) o));
diff --git a/lib/ismounted.c b/lib/ismounted.c
index ae5327c90..28ddc0d58 100644
--- a/lib/ismounted.c
+++ b/lib/ismounted.c
@@ -216,31 +216,31 @@ static int check_getmntinfo(const char *file, int *mount_flags,
char *mtpt, int mtlen)
{
struct statfs *mp;
- int len, n;
- const char *s1;
+ int len, n;
+ const char *s1;
char *s2;
- n = getmntinfo(&mp, MNT_NOWAIT);
- if (n == 0)
+ n = getmntinfo(&mp, MNT_NOWAIT);
+ if (n == 0)
return errno;
- len = sizeof(_PATH_DEV) - 1;
- s1 = file;
- if (strncmp(_PATH_DEV, s1, len) == 0)
- s1 += len;
+ len = sizeof(_PATH_DEV) - 1;
+ s1 = file;
+ if (strncmp(_PATH_DEV, s1, len) == 0)
+ s1 += len;
*mount_flags = 0;
- while (--n >= 0) {
- s2 = mp->f_mntfromname;
- if (strncmp(_PATH_DEV, s2, len) == 0) {
- s2 += len - 1;
- *s2 = 'r';
- }
- if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
+ while (--n >= 0) {
+ s2 = mp->f_mntfromname;
+ if (strncmp(_PATH_DEV, s2, len) == 0) {
+ s2 += len - 1;
+ *s2 = 'r';
+ }
+ if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
*mount_flags = MF_MOUNTED;
break;
}
- ++mp;
+ ++mp;
}
if (mtpt && n >= 0)
xstrncpy(mtpt, mp->f_mntonname, mtlen);
diff --git a/lib/logindefs.c b/lib/logindefs.c
index 079f2dabf..3da5911d1 100644
--- a/lib/logindefs.c
+++ b/lib/logindefs.c
@@ -253,7 +253,7 @@ static void load_defaults(void)
econf_err error;
if (file != NULL)
- free_getlogindefs_data();
+ free_getlogindefs_data();
#ifdef HAVE_ECONF_READCONFIG
error = econf_readConfig(&file, NULL,
@@ -282,10 +282,10 @@ void logindefs_load_file(const char *filename)
xasprintf(&path, _PATH_VENDORDIR"/%s", filename);
if (!econf_readFile(&file_l, path, "= \t", "#")) {
- if (file == NULL)
- file = file_l;
- else if (!econf_mergeFiles(&file_m, file, file_l)) {
- econf_free(file);
+ if (file == NULL)
+ file = file_l;
+ else if (!econf_mergeFiles(&file_m, file, file_l)) {
+ econf_free(file);
file = file_m;
econf_free(file_l);
}
@@ -296,10 +296,10 @@ void logindefs_load_file(const char *filename)
xasprintf(&path, "/etc/%s", filename);
if (!econf_readFile(&file_l, path, "= \t", "#")) {
- if (file == NULL)
- file = file_l;
- else if (!econf_mergeFiles(&file_m, file, file_l)) {
- econf_free(file);
+ if (file == NULL)
+ file = file_l;
+ else if (!econf_mergeFiles(&file_m, file, file_l)) {
+ econf_free(file);
file = file_m;
econf_free(file_l);
}
@@ -319,18 +319,18 @@ void logindefs_load_file(const char *filename)
int getlogindefs_bool(const char *name, int dflt)
{
- bool value;
+ bool value;
econf_err error;
if (!file)
- load_defaults();
+ load_defaults();
if (!file)
return dflt;
if ((error = econf_getBoolValue(file, NULL, name, &value))) {
- if (error != ECONF_NOKEY)
- syslog(LOG_NOTICE, _("couldn't fetch %s: %s"), name,
+ if (error != ECONF_NOKEY)
+ syslog(LOG_NOTICE, _("couldn't fetch %s: %s"), name,
econf_errString(error));
return dflt;
}
@@ -343,14 +343,14 @@ unsigned long getlogindefs_num(const char *name, unsigned long dflt)
econf_err error;
if (!file)
- load_defaults();
+ load_defaults();
if (!file)
return dflt;
if ((error = econf_getUInt64Value(file, NULL, name, &value))) {
- if (error != ECONF_NOKEY)
- syslog(LOG_NOTICE, _("couldn't fetch %s: %s"), name,
+ if (error != ECONF_NOKEY)
+ syslog(LOG_NOTICE, _("couldn't fetch %s: %s"), name,
econf_errString(error));
return dflt;
}
@@ -365,19 +365,19 @@ unsigned long getlogindefs_num(const char *name, unsigned long dflt)
*/
const char *getlogindefs_str(const char *name, const char *dflt)
{
- char *value;
+ char *value;
econf_err error;
if (!file)
- load_defaults();
+ load_defaults();
if (!file)
return dflt;
if ((error = econf_getStringValue(file, NULL, name, &value))) {
- if (error != ECONF_NOKEY)
- syslog(LOG_NOTICE, _("couldn't fetch %s: %s"), name,
- econf_errString(error));
+ if (error != ECONF_NOKEY)
+ syslog(LOG_NOTICE, _("couldn't fetch %s: %s"), name,
+ econf_errString(error));
return dflt;
}
if (value)
@@ -591,10 +591,10 @@ int main(int argc, char *argv[])
NULL};
for (i = 0; keys[i] != NULL; i++) {
- char *value = NULL;
+ char *value = NULL;
econf_getStringValue(file, NULL, keys[i], &value);
- printf ("%s: $%s: '%s'\n", argv[1], keys[i], value);
+ printf ("%s: $%s: '%s'\n", argv[1], keys[i], value);
}
econf_free (file);
diff --git a/lib/loopdev.c b/lib/loopdev.c
index efc997f87..6b27e451f 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -326,7 +326,7 @@ static int __loopcxt_get_fd(struct loopdev_cxt *lc, mode_t mode)
lc->fd = open(lc->device, lc->mode | O_CLOEXEC);
DBG(CXT, ul_debugobj(lc, "open %s [%s]: %m", lc->device,
mode == O_RDONLY ? "ro" :
- mode == O_RDWR ? "rw" : "??"));
+ mode == O_RDWR ? "rw" : "??"));
if (lc->fd < 0 && old >= 0) {
/* restore original on error */
@@ -1661,28 +1661,28 @@ int loopcxt_detach_device(struct loopdev_cxt *lc)
int loopcxt_remove_device(struct loopdev_cxt *lc)
{
- int rc = -EINVAL;
- int ctl, nr = -1;
+ int rc = -EINVAL;
+ int ctl, nr = -1;
- if (!(lc->flags & LOOPDEV_FL_CONTROL)) {
- rc = -ENOSYS;
- goto done;
- }
+ if (!(lc->flags & LOOPDEV_FL_CONTROL)) {
+ rc = -ENOSYS;
+ goto done;
+ }
- rc = loopcxt_get_device_nr(lc, &nr);
- if (rc)
- goto done;
+ rc = loopcxt_get_device_nr(lc, &nr);
+ if (rc)
+ goto done;
- ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC);
- if (ctl >= 0) {
- DBG(CXT, ul_debugobj(lc, "remove_device %d", nr));
- rc = ioctl(ctl, LOOP_CTL_REMOVE, nr);
- close(ctl);
- }
- lc->control_ok = rc >= 0 ? 1 : 0;
+ ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC);
+ if (ctl >= 0) {
+ DBG(CXT, ul_debugobj(lc, "remove_device %d", nr));
+ rc = ioctl(ctl, LOOP_CTL_REMOVE, nr);
+ close(ctl);
+ }
+ lc->control_ok = rc >= 0 ? 1 : 0;
done:
- DBG(CXT, ul_debugobj(lc, "remove_device done [rc=%d]", rc));
- return rc;
+ DBG(CXT, ul_debugobj(lc, "remove_device done [rc=%d]", rc));
+ return rc;
}
int loopcxt_add_device(struct loopdev_cxt *lc)
diff --git a/lib/procfs.c b/lib/procfs.c
index ca34e54b0..1f6b01a85 100644
--- a/lib/procfs.c
+++ b/lib/procfs.c
@@ -476,7 +476,7 @@ static int test_tasks(int argc, char *argv[], const char *prefix)
printf(" %d", tid);
printf("\n");
- ul_unref_path(pc);
+ ul_unref_path(pc);
return EXIT_SUCCESS;
}
@@ -501,7 +501,7 @@ static int test_fds(int argc, char *argv[], const char *prefix)
printf(" %d", fd);
fputc('\n', stdout);
- ul_unref_path(pc);
+ ul_unref_path(pc);
return EXIT_SUCCESS;
}
diff --git a/lib/pty-session.c b/lib/pty-session.c
index e9db4988b..b3e41e0c8 100644
--- a/lib/pty-session.c
+++ b/lib/pty-session.c
@@ -169,7 +169,7 @@ int ul_pty_setup(struct ul_pty *pty)
sigprocmask(0, NULL, &pty->orgsig);
if (pty->isterm) {
- DBG(SETUP, ul_debugobj(pty, "create for terminal"));
+ DBG(SETUP, ul_debugobj(pty, "create for terminal"));
/* original setting of the current terminal */
if (tcgetattr(STDIN_FILENO, &pty->stdin_attrs) != 0) {
@@ -594,9 +594,9 @@ static int handle_signal(struct ul_pty *pty, int fd)
case SIGQUIT:
DBG(SIG, ul_debugobj(pty, " get signal SIG{TERM,INT,QUIT}"));
pty->delivered_signal = info.ssi_signo;
- /* Child termination is going to generate SIGCHLD (see above) */
+ /* Child termination is going to generate SIGCHLD (see above) */
if (pty->child > 0)
- kill(pty->child, SIGTERM);
+ kill(pty->child, SIGTERM);
if (pty->callbacks.log_signal)
rc = pty->callbacks.log_signal(pty->callback_data,
diff --git a/lib/shells.c b/lib/shells.c
index ef2aecd0f..f773f0df8 100644
--- a/lib/shells.c
+++ b/lib/shells.c
@@ -44,34 +44,34 @@ static econf_file *open_etc_shells(void)
extern void print_shells(FILE *out, const char *format)
{
#if defined (HAVE_LIBECONF) && defined (USE_VENDORDIR)
- size_t size = 0;
- econf_err error;
- char **keys = NULL;
- econf_file *key_file = open_etc_shells();
+ size_t size = 0;
+ econf_err error;
+ char **keys = NULL;
+ econf_file *key_file = open_etc_shells();
if (!key_file)
return;
- error = econf_getKeys(key_file, NULL, &size, &keys);
- if (error) {
- econf_free(key_file);
- errx(EXIT_FAILURE,
- _("Cannot evaluate entries in shells files: %s"),
- econf_errString(error));
- }
+ error = econf_getKeys(key_file, NULL, &size, &keys);
+ if (error) {
+ econf_free(key_file);
+ errx(EXIT_FAILURE,
+ _("Cannot evaluate entries in shells files: %s"),
+ econf_errString(error));
+ }
- for (size_t i = 0; i < size; i++) {
- fprintf(out, format, keys[i]);
- }
- econf_free(keys);
- econf_free(key_file);
+ for (size_t i = 0; i < size; i++) {
+ fprintf(out, format, keys[i]);
+ }
+ econf_free(keys);
+ econf_free(key_file);
#else
- char *s;
+ char *s;
setusershell();
- while ((s = getusershell()))
- fprintf(out, format, s);
- endusershell();
+ while ((s = getusershell()))
+ fprintf(out, format, s);
+ endusershell();
#endif
}
@@ -91,19 +91,19 @@ extern int is_known_shell(const char *shell_name)
#if defined (HAVE_LIBECONF) && defined (USE_VENDORDIR)
char *val = NULL;
econf_err error;
- econf_file *key_file = open_etc_shells();
+ econf_file *key_file = open_etc_shells();
if (!key_file)
- return 0;
+ return 0;
error = econf_getStringValue (key_file, NULL, shell_name, &val);
if (error) {
- if (error != ECONF_NOKEY)
- syslog(LOG_ALERT,
- _("Cannot evaluate entries in shells files: %s"),
- econf_errString(error));
+ if (error != ECONF_NOKEY)
+ syslog(LOG_ALERT,
+ _("Cannot evaluate entries in shells files: %s"),
+ econf_errString(error));
} else
- ret = 1;
+ ret = 1;
free(val);
econf_free(key_file);
diff --git a/lib/strutils.c b/lib/strutils.c
index a3b1376e3..72d0352c8 100644
--- a/lib/strutils.c
+++ b/lib/strutils.c
@@ -281,20 +281,20 @@ int ul_parse_switch(const char *arg, ...)
#ifndef HAVE_MEMPCPY
void *mempcpy(void *restrict dest, const void *restrict src, size_t n)
{
- return ((char *)memcpy(dest, src, n)) + n;
+ return ((char *)memcpy(dest, src, n)) + n;
}
#endif
#ifndef HAVE_STRNLEN
size_t strnlen(const char *s, size_t maxlen)
{
- size_t i;
+ size_t i;
- for (i = 0; i < maxlen; i++) {
- if (s[i] == '\0')
- return i;
- }
- return maxlen;
+ for (i = 0; i < maxlen; i++) {
+ if (s[i] == '\0')
+ return i;
+ }
+ return maxlen;
}
#endif
@@ -980,38 +980,38 @@ int streq_paths(const char *a, const char *b)
/* concatenate two strings to a new string, the size of the second string is limited by @b */
char *ul_strnconcat(const char *s, const char *suffix, size_t b)
{
- size_t a;
- char *r;
+ size_t a;
+ char *r;
- if (!s && !suffix)
- return strdup("");
- if (!s)
- return strndup(suffix, b);
- if (!suffix)
- return strdup(s);
+ if (!s && !suffix)
+ return strdup("");
+ if (!s)
+ return strndup(suffix, b);
+ if (!suffix)
+ return strdup(s);
- assert(s);
- assert(suffix);
+ assert(s);
+ assert(suffix);
- a = strlen(s);
- if (b > ((size_t) -1) - a)
- return NULL;
+ a = strlen(s);
+ if (b > ((size_t) -1) - a)
+ return NULL;
- r = malloc(a + b + 1);
- if (!r)
- return NULL;
+ r = malloc(a + b + 1);
+ if (!r)
+ return NULL;
- memcpy(r, s, a);
- memcpy(r + a, suffix, b);
- r[a+b] = 0;
+ memcpy(r, s, a);
+ memcpy(r + a, suffix, b);
+ r[a+b] = 0;
- return r;
+ return r;
}
/* concatenate two strings to a new string */
char *ul_strconcat(const char *s, const char *suffix)
{
- return ul_strnconcat(s, suffix, suffix ? strlen(suffix) : 0);
+ return ul_strnconcat(s, suffix, suffix ? strlen(suffix) : 0);
}
/* concatenate @s and string defined by @format to a new string */
@@ -1088,20 +1088,20 @@ extern int ul_strvfappend(char **a, const char *format, va_list ap)
static size_t strcspn_escaped(const char *s, const char *reject)
{
- int escaped = 0;
- int n;
+ int escaped = 0;
+ int n;
- for (n=0; s[n]; n++) {
- if (escaped)
- escaped = 0;
- else if (s[n] == '\\')
- escaped = 1;
- else if (strchr(reject, s[n]))
- break;
- }
+ for (n=0; s[n]; n++) {
+ if (escaped)
+ escaped = 0;
+ else if (s[n] == '\\')
+ escaped = 1;
+ else if (strchr(reject, s[n]))
+ break;
+ }
- /* if s ends in \, return index of previous char */
- return n - escaped;
+ /* if s ends in \, return index of previous char */
+ return n - escaped;
}
/*
@@ -1138,46 +1138,46 @@ char *ul_strchr_escaped(const char *s, int c)
/* Split a string into words. */
const char *ul_split(const char **state, size_t *l, const char *separator, int quoted)
{
- const char *current;
+ const char *current;
- current = *state;
+ current = *state;
- if (!*current) {
- assert(**state == '\0');
- return NULL;
- }
+ if (!*current) {
+ assert(**state == '\0');
+ return NULL;
+ }
- current += strspn(current, separator);
- if (!*current) {
- *state = current;
- return NULL;
- }
+ current += strspn(current, separator);
+ if (!*current) {
+ *state = current;
+ return NULL;
+ }
- if (quoted && strchr("\'\"", *current)) {
- char quotechars[2] = {*current, '\0'};
+ if (quoted && strchr("\'\"", *current)) {
+ char quotechars[2] = {*current, '\0'};
- *l = strcspn_escaped(current + 1, quotechars);
- if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
- (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
- /* right quote missing or garbage at the end */
- *state = current;
- return NULL;
- }
- *state = current++ + *l + 2;
- } else if (quoted) {
- *l = strcspn_escaped(current, separator);
- if (current[*l] && !strchr(separator, current[*l])) {
- /* unfinished escape */
- *state = current;
- return NULL;
- }
- *state = current + *l;
- } else {
- *l = strcspn(current, separator);
- *state = current + *l;
- }
+ *l = strcspn_escaped(current + 1, quotechars);
+ if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
+ (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
+ /* right quote missing or garbage at the end */
+ *state = current;
+ return NULL;
+ }
+ *state = current++ + *l + 2;
+ } else if (quoted) {
+ *l = strcspn_escaped(current, separator);
+ if (current[*l] && !strchr(separator, current[*l])) {
+ /* unfinished escape */
+ *state = current;
+ return NULL;
+ }
+ *state = current + *l;
+ } else {
+ *l = strcspn(current, separator);
+ *state = current + *l;
+ }
- return current;
+ return current;
}
/* Rewind file pointer forward to new line. */
diff --git a/lib/sysfs.c b/lib/sysfs.c
index c888617b7..13977ee5b 100644
--- a/lib/sysfs.c
+++ b/lib/sysfs.c
@@ -183,7 +183,7 @@ char *sysfs_blkdev_get_name(struct path_cxt *pc, char *buf, size_t bufsiz)
char *name;
ssize_t sz;
- /* read /sys/dev/block/<maj:min> link */
+ /* read /sys/dev/block/<maj:min> link */
sz = ul_path_readlink(pc, link, sizeof(link), NULL);
if (sz < 0)
return NULL;
@@ -522,29 +522,29 @@ int sysfs_blkdev_is_removable(struct path_cxt *pc)
}
static int get_dm_wholedisk(struct path_cxt *pc, char *diskname,
- size_t len, dev_t *diskdevno)
+ size_t len, dev_t *diskdevno)
{
- int rc = 0;
- char *name;
+ int rc = 0;
+ char *name;
- /* Note, sysfs_blkdev_get_slave() returns the first slave only,
- * if there is more slaves, then return NULL
- */
- name = sysfs_blkdev_get_slave(pc);
- if (!name)
- return -1;
+ /* Note: sysfs_blkdev_get_slave() returns the first slave only;
+ * if there are more slaves, it returns NULL.
+ */
+ name = sysfs_blkdev_get_slave(pc);
+ if (!name)
+ return -1;
- if (diskname && len)
- xstrncpy(diskname, name, len);
+ if (diskname && len)
+ xstrncpy(diskname, name, len);
- if (diskdevno) {
- *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
- if (!*diskdevno)
- rc = -1;
- }
+ if (diskdevno) {
+ *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
+ if (!*diskdevno)
+ rc = -1;
+ }
- free(name);
- return rc;
+ free(name);
+ return rc;
}
/*
@@ -556,85 +556,84 @@ int sysfs_blkdev_get_wholedisk( struct path_cxt *pc,
size_t len,
dev_t *diskdevno)
{
- int is_part = 0;
+ int is_part = 0;
- if (!pc)
- return -1;
+ if (!pc)
+ return -1;
- is_part = ul_path_access(pc, F_OK, "partition") == 0;
- if (!is_part) {
- /*
- * Extra case for partitions mapped by device-mapper.
- *
- * All regular partitions (added by BLKPG ioctl or kernel PT
- * parser) have the /sys/.../partition file. The partitions
- * mapped by DM don't have such file, but they have "part"
- * prefix in DM UUID.
- */
- char *uuid = NULL, *tmp, *prefix;
+ is_part = ul_path_access(pc, F_OK, "partition") == 0;
+ if (!is_part) {
+ /*
+ * Extra case for partitions mapped by device-mapper.
+ *
+ * All regular partitions (added by BLKPG ioctl or kernel PT
+ * parser) have the /sys/.../partition file. The partitions
+ * mapped by DM don't have such file, but they have "part"
+ * prefix in DM UUID.
+ */
+ char *uuid = NULL, *tmp, *prefix;
- ul_path_read_string(pc, &uuid, "dm/uuid");
- tmp = uuid;
- prefix = uuid ? strsep(&tmp, "-") : NULL;
+ ul_path_read_string(pc, &uuid, "dm/uuid");
+ tmp = uuid;
+ prefix = uuid ? strsep(&tmp, "-") : NULL;
- if (prefix && c_strncasecmp(prefix, "part", 4) == 0)
- is_part = 1;
- free(uuid);
+ if (prefix && c_strncasecmp(prefix, "part", 4) == 0)
+ is_part = 1;
+ free(uuid);
- if (is_part &&
- get_dm_wholedisk(pc, diskname, len, diskdevno) == 0)
- /*
- * partitioned device, mapped by DM
- */
- goto done;
+ if (is_part &&
+ get_dm_wholedisk(pc, diskname, len, diskdevno) == 0)
+ /*
+ * partitioned device, mapped by DM
+ */
+ goto done;
- is_part = 0;
- }
+ is_part = 0;
+ }
- if (!is_part) {
- /*
- * unpartitioned device
- */
- if (diskname && !sysfs_blkdev_get_name(pc, diskname, len))
- goto err;
- if (diskdevno)
- *diskdevno = sysfs_blkdev_get_devno(pc);
+ if (!is_part) {
+ /*
+ * unpartitioned device
+ */
+ if (diskname && !sysfs_blkdev_get_name(pc, diskname, len))
+ goto err;
+ if (diskdevno)
+ *diskdevno = sysfs_blkdev_get_devno(pc);
+ } else {
+ /*
+ * partitioned device
+ * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1
+ * - dirname ../../block/sda/sda1 = ../../block/sda
+ * - basename ../../block/sda = sda
+ */
+ char linkpath[PATH_MAX];
+ char *name;
+ ssize_t linklen;
- } else {
- /*
- * partitioned device
- * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1
- * - dirname ../../block/sda/sda1 = ../../block/sda
- * - basename ../../block/sda = sda
- */
- char linkpath[PATH_MAX];
- char *name;
- ssize_t linklen;
+ linklen = ul_path_readlink(pc, linkpath, sizeof(linkpath), NULL);
+ if (linklen < 0)
+ goto err;
- linklen = ul_path_readlink(pc, linkpath, sizeof(linkpath), NULL);
- if (linklen < 0)
- goto err;
+ stripoff_last_component(linkpath); /* dirname */
+ name = stripoff_last_component(linkpath); /* basename */
+ if (!name)
+ goto err;
- stripoff_last_component(linkpath); /* dirname */
- name = stripoff_last_component(linkpath); /* basename */
- if (!name)
- goto err;
+ sysfs_devname_sys_to_dev(name);
+ if (diskname && len)
+ xstrncpy(diskname, name, len);
- sysfs_devname_sys_to_dev(name);
- if (diskname && len)
- xstrncpy(diskname, name, len);
-
- if (diskdevno) {
- *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
- if (!*diskdevno)
- goto err;
- }
- }
+ if (diskdevno) {
+ *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
+ if (!*diskdevno)
+ goto err;
+ }
+ }
done:
- return 0;
+ return 0;
err:
- return -1;
+ return -1;
}
int sysfs_devno_to_wholedisk(dev_t devno, char *diskname,
@@ -790,7 +789,7 @@ char *sysfs_blkdev_scsi_host_strdup_attribute(struct path_cxt *pc,
return NULL;
if (!(f = fopen(buf, "r" UL_CLOEXECSTR)))
- return NULL;
+ return NULL;
rc = fscanf(f, "%1023[^\n]", buf);
fclose(f);
@@ -1093,7 +1092,7 @@ char *sysfs_chrdev_devno_to_devname(dev_t devno, char *buf, size_t bufsiz)
if (!pc)
return NULL;
- /* read /sys/dev/char/<maj:min> link */
+ /* read /sys/dev/char/<maj:min> link */
sz = ul_path_readlink(pc, link, sizeof(link), NULL);
ul_unref_path(pc);
diff --git a/lib/timer.c b/lib/timer.c
index cfa18f6fd..2f7e90cd4 100644
--- a/lib/timer.c
+++ b/lib/timer.c
@@ -92,7 +92,7 @@ int setup_timer(struct ul_timer *timer,
void cancel_timer(struct ul_timer *timer)
{
setitimer(ITIMER_REAL, &timer->old_timer, NULL);
- sigaction(SIGALRM, &timer->old_sa, NULL);
+ sigaction(SIGALRM, &timer->old_sa, NULL);
}
#endif /* !HAVE_TIMER_CREATE */
diff --git a/login-utils/login.c b/login-utils/login.c
index 604d63c23..84a361d73 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -1306,8 +1306,8 @@ static void load_credentials(struct login_context *cxt) {
struct path_cxt *pc;
env = safe_getenv("CREDENTIALS_DIRECTORY");
- if (!env)
- return;
+ if (!env)
+ return;
pc = ul_new_path("%s", env);
if (!pc) {
diff --git a/login-utils/sulogin-consoles.c b/login-utils/sulogin-consoles.c
index 93eeab111..7faf19da1 100644
--- a/login-utils/sulogin-consoles.c
+++ b/login-utils/sulogin-consoles.c
@@ -124,7 +124,7 @@ void emergency_do_mounts(void)
if (stat("/dev", &xt) == 0
&& rt.st_dev == xt.st_dev
&& mount("devtmpfs", "/dev", "devtmpfs",
- MS_RELATIME, "mode=0755,nr_inodes=0") == 0) {
+ MS_RELATIME, "mode=0755,nr_inodes=0") == 0) {
emergency_flags |= MNT_DEVTMPFS;
mknod("/dev/console", S_IFCHR|S_IRUSR|S_IWUSR,
@@ -249,9 +249,9 @@ char* scandev(DIR *dir, const dev_t comparedev)
"/dev/char/%u:%u", major(comparedev), minor(comparedev))) > 0 &&
(size_t)len < sizeof(path)) {
- name = realpath(path, NULL);
- if (name)
- goto out;
+ name = realpath(path, NULL);
+ if (name)
+ goto out;
}
fd = dirfd(dir);
@@ -771,7 +771,7 @@ console:
fallback:
if (fallback >= 0) {
const char *name;
- char *n;
+ char *n;
struct console *console;
if (device && *device != '\0')
diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c
index 78511dca7..f1526bcad 100644
--- a/misc-utils/findmnt.c
+++ b/misc-utils/findmnt.c
@@ -812,14 +812,14 @@ static char *get_tabdiff_data(struct libmnt_fs *old_fs,
break;
case COL_OLD_OPTIONS:
if (old_fs && (change == MNT_TABDIFF_REMOUNT ||
- change == MNT_TABDIFF_UMOUNT)
+ change == MNT_TABDIFF_UMOUNT)
&& mnt_fs_get_options(old_fs))
str = xstrdup(mnt_fs_get_options(old_fs));
break;
case COL_OLD_TARGET:
if (old_fs && (change == MNT_TABDIFF_MOVE ||
- change == MNT_TABDIFF_UMOUNT)
- && mnt_fs_get_target(old_fs))
+ change == MNT_TABDIFF_UMOUNT)
+ && mnt_fs_get_target(old_fs))
str = xstrdup(mnt_fs_get_target(old_fs));
break;
default:
@@ -1519,10 +1519,10 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(USAGE_HEADER, out);
fprintf(out, _(
- " %1$s [options]\n"
- " %1$s [options] <device> | <mountpoint>\n"
- " %1$s [options] <device> <mountpoint>\n"
- " %1$s [options] [--source <device>] [--target <path> | --mountpoint <dir>]\n"),
+ " %1$s [options]\n"
+ " %1$s [options] <device> | <mountpoint>\n"
+ " %1$s [options] <device> <mountpoint>\n"
+ " %1$s [options] [--source <device>] [--target <path> | --mountpoint <dir>]\n"),
program_invocation_short_name);
fputs(USAGE_SEPARATOR, out);
@@ -1677,7 +1677,7 @@ static struct libscols_table *init_scols_table(struct findmnt *findmnt)
scols_wrapzero_nextchunk,
NULL);
if ((flags & FL_JSON) || use_filter)
- scols_column_set_json_type(cl, get_column_json_type(id, fl, NULL,
+ scols_column_set_json_type(cl, get_column_json_type(id, fl, NULL,
flags));
}
diff --git a/misc-utils/lastlog2.c b/misc-utils/lastlog2.c
index e973b5461..be33f2ae3 100644
--- a/misc-utils/lastlog2.c
+++ b/misc-utils/lastlog2.c
@@ -68,10 +68,9 @@ static int print_entry(const char *user, int64_t ll_time,
/* Print only if newer than t days */
if (tflg && ((time (NULL) - ll_time) > t_days))
return 0;
- /* this is necessary if you compile this on architectures with
- a 32bit time_t type. */
- time_t t_time = ll_time;
- tm = localtime_r(&t_time, &tm_buf);
+ /* This is needed on architectures with a 32bit time_t type. */
+ time_t t_time = ll_time;
+ tm = localtime_r(&t_time, &tm_buf);
if (tm == NULL)
datep = "(unknown)";
else {
diff --git a/misc-utils/lsblk-devtree.c b/misc-utils/lsblk-devtree.c
index 07f67b4da..5e9d38da1 100644
--- a/misc-utils/lsblk-devtree.c
+++ b/misc-utils/lsblk-devtree.c
@@ -160,7 +160,7 @@ int lsblk_device_new_dependence(struct lsblk_device *parent, struct lsblk_device
dp->parent = parent;
list_add_tail(&dp->ls_parents, &child->parents);
- DBG(DEV, ul_debugobj(parent, "add dependence 0x%p [%s->%s]", dp, parent->name, child->name));
+ DBG(DEV, ul_debugobj(parent, "add dependence 0x%p [%s->%s]", dp, parent->name, child->name));
return 0;
}
@@ -307,16 +307,16 @@ int lsblk_devtree_add_root(struct lsblk_devtree *tr, struct lsblk_device *dev)
/* We don't increment reference counter for tr->roots list. The primary
* reference is tr->devices */
- DBG(TREE, ul_debugobj(tr, "add root device 0x%p [%s]", dev, dev->name));
- list_add_tail(&dev->ls_roots, &tr->roots);
+ DBG(TREE, ul_debugobj(tr, "add root device 0x%p [%s]", dev, dev->name));
+ list_add_tail(&dev->ls_roots, &tr->roots);
return 0;
}
int lsblk_devtree_remove_root(struct lsblk_devtree *tr __attribute__((unused)),
struct lsblk_device *dev)
{
- DBG(TREE, ul_debugobj(tr, "remove root device 0x%p [%s]", dev, dev->name));
- list_del_init(&dev->ls_roots);
+ DBG(TREE, ul_debugobj(tr, "remove root device 0x%p [%s]", dev, dev->name));
+ list_del_init(&dev->ls_roots);
return 0;
}
@@ -343,8 +343,8 @@ int lsblk_devtree_add_device(struct lsblk_devtree *tr, struct lsblk_device *dev)
{
lsblk_ref_device(dev);
- DBG(TREE, ul_debugobj(tr, "add device 0x%p [%s]", dev, dev->name));
- list_add_tail(&dev->ls_devices, &tr->devices);
+ DBG(TREE, ul_debugobj(tr, "add device 0x%p [%s]", dev, dev->name));
+ list_add_tail(&dev->ls_devices, &tr->devices);
return 0;
}
@@ -398,7 +398,7 @@ struct lsblk_device *lsblk_devtree_get_device(struct lsblk_devtree *tr, const ch
int lsblk_devtree_remove_device(struct lsblk_devtree *tr, struct lsblk_device *dev)
{
- DBG(TREE, ul_debugobj(tr, "remove device 0x%p [%s]", dev, dev->name));
+ DBG(TREE, ul_debugobj(tr, "remove device 0x%p [%s]", dev, dev->name));
if (!lsblk_devtree_has_device(tr, dev))
return 1;
diff --git a/misc-utils/rename.c b/misc-utils/rename.c
index d7bf4c5d7..629c48840 100644
--- a/misc-utils/rename.c
+++ b/misc-utils/rename.c
@@ -147,8 +147,8 @@ static int do_symlink(char *from, char *to, char *s, int verbose, int noact,
ssize_t ssz;
struct stat sb;
- if ( faccessat(AT_FDCWD, s, F_OK, AT_SYMLINK_NOFOLLOW) != 0 &&
- errno != EINVAL )
+ if (faccessat(AT_FDCWD, s, F_OK, AT_SYMLINK_NOFOLLOW) != 0 &&
+ errno != EINVAL )
/* Skip if AT_SYMLINK_NOFOLLOW is not supported; lstat() below will
detect the access error */
{
diff --git a/sys-utils/ipcrm.c b/sys-utils/ipcrm.c
index 8e38f8d61..740d4f3c6 100644
--- a/sys-utils/ipcrm.c
+++ b/sys-utils/ipcrm.c
@@ -78,7 +78,7 @@ static void __attribute__((__noreturn__)) usage(void)
static int remove_id(int type, int iskey, int id)
{
- int ret;
+ int ret;
char *errmsg;
/* needed to delete semaphores */
union semun arg;
diff --git a/sys-utils/ldattach.c b/sys-utils/ldattach.c
index 0bc97c903..eba8da126 100644
--- a/sys-utils/ldattach.c
+++ b/sys-utils/ldattach.c
@@ -304,9 +304,9 @@ int main(int argc, char **argv)
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{"debug", no_argument, NULL, 'd'},
- {"intro-command", required_argument, NULL, 'c'},
- {"pause", required_argument, NULL, 'p'},
- {"mtu", required_argument, NULL, 'm'},
+ {"intro-command", required_argument, NULL, 'c'},
+ {"pause", required_argument, NULL, 'p'},
+ {"mtu", required_argument, NULL, 'm'},
{NULL, 0, NULL, 0}
};
diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c
index fe30d70da..be8bfd933 100644
--- a/sys-utils/losetup.c
+++ b/sys-utils/losetup.c
@@ -830,7 +830,7 @@ int main(int argc, char **argv)
case OPT_SIZELIMIT: /* --sizelimit */
sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
flags |= LOOPDEV_FL_SIZELIMIT;
- break;
+ break;
case 'h':
usage();
diff --git a/sys-utils/lscpu-topology.c b/sys-utils/lscpu-topology.c
index 6e0782f64..460ba449b 100644
--- a/sys-utils/lscpu-topology.c
+++ b/sys-utils/lscpu-topology.c
@@ -465,7 +465,7 @@ static int read_caches(struct lscpu_cxt *cxt, struct lscpu_cpu *cpu)
if (ul_path_readf_s32(sys, &level, "cpu%d/cache/index%zu/level", num, i) != 0)
continue;
if (ul_path_readf_buffer(sys, buf, sizeof(buf),
- "cpu%d/cache/index%zu/type", num, i) <= 0)
+ "cpu%d/cache/index%zu/type", num, i) <= 0)
continue;
if (id == -1)
diff --git a/sys-utils/lsns.c b/sys-utils/lsns.c
index 2b7337777..dd94e8ab4 100644
--- a/sys-utils/lsns.c
+++ b/sys-utils/lsns.c
@@ -1593,16 +1593,16 @@ static void __attribute__((__noreturn__)) usage(void)
static void __attribute__((__noreturn__)) list_colunms(struct lsns *ls)
{
- struct libscols_table *col_tb = xcolumn_list_table_new("lsns-columns", stdout, ls->raw, ls->json);
+ struct libscols_table *col_tb = xcolumn_list_table_new("lsns-columns", stdout, ls->raw, ls->json);
- for (size_t i = 0; i < ARRAY_SIZE(infos); i++)
- xcolumn_list_table_append_line(col_tb, infos[i].name,
- infos[i].json_type, NULL,
- _(infos[i].help));
- scols_print_table(col_tb);
- scols_unref_table(col_tb);
+ for (size_t i = 0; i < ARRAY_SIZE(infos); i++)
+ xcolumn_list_table_append_line(col_tb, infos[i].name,
+ infos[i].json_type, NULL,
+ _(infos[i].help));
+ scols_print_table(col_tb);
+ scols_unref_table(col_tb);
- exit(EXIT_SUCCESS);
+ exit(EXIT_SUCCESS);
}
static int stat_self_ns (const char *ns, struct stat *st)
diff --git a/sys-utils/swapoff.c b/sys-utils/swapoff.c
index 21c8e1ee8..152d1e11b 100644
--- a/sys-utils/swapoff.c
+++ b/sys-utils/swapoff.c
@@ -96,7 +96,7 @@ static char *resolve_swapfile_tag(const char *name, const char *value)
static int do_swapoff(const char *orig_special, int quiet, int canonic)
{
- const char *special = orig_special;
+ const char *special = orig_special;
char *buf = NULL;
int rc = SWAPOFF_EX_OK;
diff --git a/sys-utils/tunelp.c b/sys-utils/tunelp.c
index 68b795d3b..3ada170db 100644
--- a/sys-utils/tunelp.c
+++ b/sys-utils/tunelp.c
@@ -246,7 +246,7 @@ int main(int argc, char **argv)
/* Need to open O_NONBLOCK in case ABORTOPEN is already set
* and printer is off or off-line or in an error condition.
* Otherwise we would abort...
- */
+ */
if (fd < 0)
err(EXIT_FAILURE, "%s", filename);
@@ -264,7 +264,7 @@ int main(int argc, char **argv)
*/
if (LPGETIRQ >= 0x0600 && ioctl(fd, LPGETIRQ, &irq) < 0
&& errno == EINVAL)
- /* We don't understand the new ioctls */
+ /* We don't understand the new ioctls */
offset = 0x0600;
cmds = cmdst;
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 11aeae48e..7b177e618 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -1038,7 +1038,7 @@ int main(int argc, char *argv[])
kill_child_signo = SIGKILL;
}
break;
- case OPT_KEEPCAPS:
+ case OPT_KEEPCAPS:
keepcaps = 1;
cap_last_cap(); /* Force last cap to be cached before we fork. */
break;
@@ -1056,11 +1056,11 @@ int main(int argc, char *argv[])
case 'w':
newdir = optarg;
break;
- case OPT_MONOTONIC:
+ case OPT_MONOTONIC:
monotonic = strtos64_or_err(optarg, _("failed to parse monotonic offset"));
force_monotonic = 1;
break;
- case OPT_BOOTTIME:
+ case OPT_BOOTTIME:
boottime = strtos64_or_err(optarg, _("failed to parse boottime offset"));
force_boottime = 1;
break;
@@ -1206,13 +1206,13 @@ int main(int argc, char *argv[])
#endif
}
- if (mapuser != (uid_t) -1 && !usermap)
+ if (mapuser != (uid_t) -1 && !usermap)
map_id(_PATH_PROC_UIDMAP, mapuser, real_euid);
- /* Since Linux 3.19 unprivileged writing of /proc/self/gid_map
- * has been disabled unless /proc/self/setgroups is written
- * first to permanently disable the ability to call setgroups
- * in that user namespace. */
+ /* Since Linux 3.19 unprivileged writing of /proc/self/gid_map
+ * has been disabled unless /proc/self/setgroups is written
+ * first to permanently disable the ability to call setgroups
+ * in that user namespace. */
if (mapgroup != (gid_t) -1 && !groupmap) {
if (setgrpcmd == SETGROUPS_ALLOW)
errx(EXIT_FAILURE, _("options --setgroups=allow and "
diff --git a/sys-utils/zramctl.c b/sys-utils/zramctl.c
index 057e4a3c0..a890d1b9d 100644
--- a/sys-utils/zramctl.c
+++ b/sys-utils/zramctl.c
@@ -224,7 +224,7 @@ static int zram_wait_initialized(struct zram *z)
/* Wait up to 3 seconds. */
r = sd_event_add_time_relative(event, NULL, CLOCK_BOOTTIME, 3 * 1000 * 1000, 0, NULL, (void*) (intptr_t) (-ETIMEDOUT));
if (r < 0)
- return r;
+ return r;
/* Check if the device is already initialized. */
#if HAVE_DECL_SD_DEVICE_OPEN
@@ -277,7 +277,7 @@ static int zram_lock(struct zram *z, int operation)
#if HAVE_DECL_SD_DEVICE_OPEN
if (z->device) {
fd = sd_device_open(z->device, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (fd < 0)
+ if (fd < 0)
return fd;
} else {
#endif
@@ -909,7 +909,7 @@ int main(int argc, char **argv)
if (outarg && string_add_to_idarray(outarg,
columns, ARRAY_SIZE(columns),
&ncolumns, column_name_to_id) < 0)
- return EXIT_FAILURE;
+ return EXIT_FAILURE;
if (optind < argc) {
zram = new_zram(argv[optind++]);
diff --git a/term-utils/agetty.c b/term-utils/agetty.c
index f4d720448..d3b650023 100644
--- a/term-utils/agetty.c
+++ b/term-utils/agetty.c
@@ -1706,8 +1706,8 @@ static int issuefile_read_stream(struct issue *ie, FILE *f, struct options *op,
static int issuedir_read(struct issue *ie, const char *dirname,
struct options *op, struct termios *tp)
{
- int dd, nfiles, i;
- struct dirent **namelist = NULL;
+ int dd, nfiles, i;
+ struct dirent **namelist = NULL;
dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (dd < 0)
@@ -1943,9 +1943,9 @@ skip:
struct list_head *current = NULL;
char *name = NULL;
- /* Reading all issue files and concatinating all contents to one content.
- * The ordering rules are defineded in:
- * https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md
+ /* Reading all issue files and concatinating all contents to one content.
+ * The ordering rules are defineded in:
+ * https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md
*
* Note that _PATH_RUNSTATEDIR (/run) is always read by ul_configs_file_list().
*/
@@ -3120,8 +3120,8 @@ static void load_credentials(struct options *op) {
struct path_cxt *pc;
env = safe_getenv("CREDENTIALS_DIRECTORY");
- if (!env)
- return;
+ if (!env)
+ return;
pc = ul_new_path("%s", env);
if (!pc) {
diff --git a/term-utils/mesg.c b/term-utils/mesg.c
index 3ff3b9e04..e51f659a6 100644
--- a/term-utils/mesg.c
+++ b/term-utils/mesg.c
@@ -173,8 +173,8 @@ int main(int argc, char *argv[])
case RPMATCH_INVALID:
warnx(_("invalid argument: %s"), argv[0]);
errtryhelp(EXIT_FAILURE);
- default:
- abort();
+ default:
+ abort();
}
close(fd);
return ret;
diff --git a/term-utils/script.c b/term-utils/script.c
index 4e302347f..8076df41c 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -1078,7 +1078,7 @@ int main(int argc, char **argv)
log_info(&ctl, "INPUT_LOG", "%s", infile);
}
- /* this is the main loop */
+ /* this is the main loop */
rc = ul_pty_proxy_master(ctl.pty);
/* all done; cleanup and kill */
diff --git a/term-utils/scriptreplay.c b/term-utils/scriptreplay.c
index 7e1eec7db..3efcd3015 100644
--- a/term-utils/scriptreplay.c
+++ b/term-utils/scriptreplay.c
@@ -175,8 +175,8 @@ main(int argc, char *argv[])
char streams[6] = {0}; /* IOSI - in, out, signal,info */
const char *log_out = NULL,
*log_in = NULL,
- *log_io = NULL,
- *log_tm = NULL;
+ *log_io = NULL,
+ *log_tm = NULL;
double divi = 1;
int diviopt = FALSE, idx;
int ch, rc = 0, crmode = REPLAY_CRMODE_AUTO, summary = 0;
diff --git a/text-utils/col.c b/text-utils/col.c
index 5866d7d0e..ddf2a6109 100644
--- a/text-utils/col.c
+++ b/text-utils/col.c
@@ -601,45 +601,44 @@ static void free_line_allocations(struct col_alloc *root)
static void process_char(struct col_ctl *ctl, struct col_lines *lns)
{
- /* Deal printable characters */
- if (!iswgraph(lns->ch) && handle_not_graphic(ctl, lns))
- return;
+ /* Deal with non-printable characters. */
+ if (!iswgraph(lns->ch) && handle_not_graphic(ctl, lns))
+ return;
- /* Must stuff ch in a line - are we at the right one? */
- if ((size_t)lns->cur_line != lns->this_line - lns->adjust)
- update_cur_line(ctl, lns);
+ /* Must stuff ch in a line - are we at the right one? */
+ if ((size_t)lns->cur_line != lns->this_line - lns->adjust)
+ update_cur_line(ctl, lns);
- /* Does line buffer need to grow? */
- if (ctl->l->l_lsize <= ctl->l->l_line_len + 1) {
- size_t need;
+ /* Does line buffer need to grow? */
+ if (ctl->l->l_lsize <= ctl->l->l_line_len + 1) {
+ size_t need;
- need = ctl->l->l_lsize ? ctl->l->l_lsize * 2 : NALLOC;
- ctl->l->l_line = xrealloc(ctl->l->l_line, need * sizeof(struct col_char));
- ctl->l->l_lsize = need;
- }
+ need = ctl->l->l_lsize ? ctl->l->l_lsize * 2 : NALLOC;
+ ctl->l->l_line = xrealloc(ctl->l->l_line, need * sizeof(struct col_char));
+ ctl->l->l_lsize = need;
+ }
- /* Store character */
- lns->c = &ctl->l->l_line[ctl->l->l_line_len++];
- lns->c->c_char = lns->ch;
- lns->c->c_set = lns->cur_set;
+ /* Store character */
+ lns->c = &ctl->l->l_line[ctl->l->l_line_len++];
+ lns->c->c_char = lns->ch;
+ lns->c->c_set = lns->cur_set;
- if (0 < lns->cur_col)
- lns->c->c_column = lns->cur_col;
- else
- lns->c->c_column = 0;
- lns->c->c_width = wcwidth(lns->ch);
-
- /*
- * If things are put in out of order, they will need sorting
- * when it is flushed.
- */
- if (lns->cur_col < ctl->l->l_max_col)
- ctl->l->l_needs_sort = 1;
- else
- ctl->l->l_max_col = lns->cur_col;
- if (0 < lns->c->c_width)
- lns->cur_col += lns->c->c_width;
+ if (0 < lns->cur_col)
+ lns->c->c_column = lns->cur_col;
+ else
+ lns->c->c_column = 0;
+ lns->c->c_width = wcwidth(lns->ch);
+ /*
+ * If things are put in out of order, they will need sorting
+ * when it is flushed.
+ */
+ if (lns->cur_col < ctl->l->l_max_col)
+ ctl->l->l_needs_sort = 1;
+ else
+ ctl->l->l_max_col = lns->cur_col;
+ if (0 < lns->c->c_width)
+ lns->cur_col += lns->c->c_width;
}
int main(int argc, char **argv)
diff --git a/text-utils/hexdump-display.c b/text-utils/hexdump-display.c
index c865127c8..b605cad44 100644
--- a/text-utils/hexdump-display.c
+++ b/text-utils/hexdump-display.c
@@ -448,7 +448,7 @@ doskip(const char *fname, int statok, struct hexdump *hex)
if (statok) {
if (fstat(fileno(stdin), &sbuf))
- err(EXIT_FAILURE, "%s", fname);
+ err(EXIT_FAILURE, "%s", fname);
if (S_ISREG(sbuf.st_mode) && hex->skip > sbuf.st_size) {
/* If size valid and skip >= size */
hex->skip -= sbuf.st_size;
@@ -458,7 +458,7 @@ doskip(const char *fname, int statok, struct hexdump *hex)
}
/* sbuf may be undefined here - do not test it */
if (fseek(stdin, hex->skip, SEEK_SET))
- err(EXIT_FAILURE, "%s", fname);
+ err(EXIT_FAILURE, "%s", fname);
address += hex->skip;
hex->skip = 0;
}
diff --git a/text-utils/hexdump-parse.c b/text-utils/hexdump-parse.c
index 018013e5e..efc39c3b3 100644
--- a/text-utils/hexdump-parse.c
+++ b/text-utils/hexdump-parse.c
@@ -52,22 +52,22 @@ static struct list_head *color_fmt(char *cfmt, int bcnt);
static void __attribute__ ((__noreturn__)) badcnt(const char *s)
{
- errx(EXIT_FAILURE, _("bad byte count for conversion character %s"), s);
+ errx(EXIT_FAILURE, _("bad byte count for conversion character %s"), s);
}
static void __attribute__ ((__noreturn__)) badsfmt(void)
{
- errx(EXIT_FAILURE, _("%%s requires a precision or a byte count"));
+ errx(EXIT_FAILURE, _("%%s requires a precision or a byte count"));
}
static void __attribute__ ((__noreturn__)) badfmt(const char *fmt)
{
- errx(EXIT_FAILURE, _("bad format {%s}"), fmt);
+ errx(EXIT_FAILURE, _("bad format {%s}"), fmt);
}
static void __attribute__ ((__noreturn__)) badconv(const char *ch)
{
- errx(EXIT_FAILURE, _("bad conversion character %%%s"), ch);
+ errx(EXIT_FAILURE, _("bad conversion character %%%s"), ch);
}
#define first_letter(s,f) strchr(f, *(s))
@@ -81,7 +81,7 @@ void addfile(char *name, struct hexdump *hex)
size_t n = 0;
if ((fp = fopen(name, "r")) == NULL)
- err(EXIT_FAILURE, _("can't read %s"), name);
+ err(EXIT_FAILURE, _("can't read %s"), name);
while (getline(&buf, &n, fp) != -1) {
fmt = buf;
diff --git a/text-utils/hexdump.c b/text-utils/hexdump.c
index 60bf6f94b..ba8d5e1f6 100644
--- a/text-utils/hexdump.c
+++ b/text-utils/hexdump.c
@@ -116,7 +116,7 @@ parse_args(int argc, char **argv, struct hexdump *hex)
colormode = UL_COLORMODE_AUTO;
if (optarg)
colormode = colormode_or_err(optarg);
- break;
+ break;
case 'n':
hex->length = strtosize_or_err(optarg, _("failed to parse length"));
break;
--
2.51.2
^ permalink raw reply related
* [PATCH 2/3] chmem: do not word a configuration failure as an instruction to the user
From: Benno Schulenberg @ 2025-12-09 15:02 UTC (permalink / raw)
To: util-linux; +Cc: Sumanth Korikkar
In-Reply-To: <20251209150222.50981-1-bensberg@telfort.nl>
When the current machine does not support configuring/deconfiguring
memory, simply report that it cannot be done, instead of seemingly
telling the user to skip the configuring/deconfiguring.
Also, there is no need to mention `chmem` in the message: mentioning
just the recommended option (-e or -d) is enough. Also, consistently
terminate all four messages with a period.
This improves upon commit ab2e709600 ("chmem: improve messages").
CC: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
sys-utils/chmem.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sys-utils/chmem.c b/sys-utils/chmem.c
index 6ec66bb6b..dcec888d1 100644
--- a/sys-utils/chmem.c
+++ b/sys-utils/chmem.c
@@ -325,10 +325,10 @@ static int chmem_config_size(struct chmem_desc *desc, int configure)
if (!desc->have_memconfig) {
if (configure)
fprintf(stdout,
- _("Skip configuration. Use chmem -e instead.\n"));
+ _("Cannot configure. Use -e instead.\n"));
else
fprintf(stdout,
- _("Skip deconfiguration. Use chmem -d instead\n"));
+ _("Cannot deconfigure. Use -d instead.\n"));
return -1;
}
size = desc->size;
@@ -363,10 +363,10 @@ static int chmem_config_range(struct chmem_desc *desc, int configure)
if (!desc->have_memconfig) {
if (configure)
fprintf(stdout,
- _("Skip configuration. Use chmem -e instead.\n"));
+ _("Cannot configure. Use -e instead.\n"));
else
fprintf(stdout,
- _("Skip deconfiguration. Use chmem -d instead\n"));
+ _("Cannot deconfigure. Use -d instead.\n"));
return -1;
}
todo = desc->end - desc->start + 1;
--
2.51.2
^ permalink raw reply related
* [PATCH 1/3] losetup: snip --verbose from bash-completion, and 'v' from options string
From: Benno Schulenberg @ 2025-12-09 15:02 UTC (permalink / raw)
To: util-linux
This should have been part of commit 7e27c81597 from two months ago.
Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
bash-completion/losetup | 1 -
sys-utils/losetup.c | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/bash-completion/losetup b/bash-completion/losetup
index 2d314c111..bf1591fbf 100644
--- a/bash-completion/losetup
+++ b/bash-completion/losetup
@@ -59,7 +59,6 @@ _losetup_module()
--read-only
--remove
--show
- --verbose
--direct-io
--loop-ref
--sector-size
diff --git a/sys-utils/losetup.c b/sys-utils/losetup.c
index 7da0ebbd0..fe30d70da 100644
--- a/sys-utils/losetup.c
+++ b/sys-utils/losetup.c
@@ -751,7 +751,7 @@ int main(int argc, char **argv)
if (loopcxt_init(&lc, 0))
err(EXIT_FAILURE, _("failed to initialize loopcxt"));
- while ((c = getopt_long(argc, argv, "ab:cdDfhj:JlLno:O:PrvV",
+ while ((c = getopt_long(argc, argv, "ab:cdDfhj:JlLno:O:PrV",
longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
--
2.51.2
^ permalink raw reply related
* [PATCH v3] x32: Implement prctl in assembly
From: H.J. Lu @ 2025-12-08 22:41 UTC (permalink / raw)
To: Florian Weimer
Cc: Adhemerval Zanella Netto, Alejandro Colomar,
Thomas Weißschuh, util-linux, Xi Ruoyao, GNU C Library
In-Reply-To: <lhujyyxjbjy.fsf@oldenburg.str.redhat.com>
[-- Attachment #1: Type: text/plain, Size: 2197 bytes --]
On Mon, Dec 8, 2025 at 10:25 PM Florian Weimer <fweimer@redhat.com> wrote:
>
> * Adhemerval Zanella Netto:
>
> > On 08/12/25 06:09, Florian Weimer wrote:
> >> * H. J. Lu:
> >>
> >>> On Mon, Dec 8, 2025 at 4:11 PM Florian Weimer <fweimer@redhat.com> wrote:
> >>>>
> >>>> * H. J. Lu:
> >>>>> Here is the v2 patch to implement prctl in assembly for x32.
> >>>>>
> >>>>> Since the variadic prctl function takes at most 5 integer arguments which
> >>>>> are passed in the same integer registers on x32 as the function with 5
> >>>>> integer arguments, we can use assembly for prctl. Since upper 32-bits in
> >>>>> the last 4 arguments of prctl must be cleared to match the x32 prctl
> >>>>> syscall interface where the last 4 arguments are unsigned 64 bit longs,
> >>>>> implement prctl in assembly to clear upper 32-bits in the last 4 arguments
> >>>>> and add a test to verify it.
> >>>>
> >>>> What's the advantage of the assembler implementation over the C
> >>>> implementation? I'm missing the context for this change.
> >>>>
> >>>
> >>> It is inspired by
> >>>
> >>> commit 6a04404521ac4119ae36827eeb288ea84eee7cf6
> >>> Author: Florian Weimer <fweimer@redhat.com>
> >>> Date: Sat Feb 17 09:17:04 2024 +0100
> >>>
> >>> Linux: Switch back to assembly syscall wrapper for prctl (bug 29770)
> >>
> >> The justification for that does not apply to x32, though, because prctl
> >> doesn't take floating point arguments. I don't have a strong opinion,
> >> the C and assembler versions are of similar complexity.
> >
> > The main justification is UB to va_args *all* the arguments without taking
> > in the consideration which option is passed. If x32 requires additional
> > argument handling to clear the upper 32-bits, there is no advantage of
> > using the assembly wrapper.
>
> I'm okay with making this change to avoid UB.
>
> Patch looks okay to me.
>
> Reviewed-by: Florian Weimer <fweimer@redhat.com>
>
> Minor nit:
>
> +weak_alias (__prctl, __prctl_time64)
> +hidden_weak (__prctl_time64)
>
> This isn't necessary because there is no __prctl_time64 on x32.
Fixed in the v3 patch I am checking in.
Thanks.
--
H.J.
[-- Attachment #2: v3-0001-x32-Implement-prctl-in-assembly.patch --]
[-- Type: application/x-patch, Size: 5742 bytes --]
^ permalink raw reply
* Re: [PATCH v2] x32: Implement prctl in assembly
From: Florian Weimer @ 2025-12-08 14:25 UTC (permalink / raw)
To: Adhemerval Zanella Netto
Cc: H.J. Lu, Alejandro Colomar, Thomas Weißschuh, util-linux,
Xi Ruoyao, GNU C Library
In-Reply-To: <ad7ac28b-fa81-48a1-b3f5-e2ab21f83c51@linaro.org>
* Adhemerval Zanella Netto:
> On 08/12/25 06:09, Florian Weimer wrote:
>> * H. J. Lu:
>>
>>> On Mon, Dec 8, 2025 at 4:11 PM Florian Weimer <fweimer@redhat.com> wrote:
>>>>
>>>> * H. J. Lu:
>>>>> Here is the v2 patch to implement prctl in assembly for x32.
>>>>>
>>>>> Since the variadic prctl function takes at most 5 integer arguments which
>>>>> are passed in the same integer registers on x32 as the function with 5
>>>>> integer arguments, we can use assembly for prctl. Since upper 32-bits in
>>>>> the last 4 arguments of prctl must be cleared to match the x32 prctl
>>>>> syscall interface where the last 4 arguments are unsigned 64 bit longs,
>>>>> implement prctl in assembly to clear upper 32-bits in the last 4 arguments
>>>>> and add a test to verify it.
>>>>
>>>> What's the advantage of the assembler implementation over the C
>>>> implementation? I'm missing the context for this change.
>>>>
>>>
>>> It is inspired by
>>>
>>> commit 6a04404521ac4119ae36827eeb288ea84eee7cf6
>>> Author: Florian Weimer <fweimer@redhat.com>
>>> Date: Sat Feb 17 09:17:04 2024 +0100
>>>
>>> Linux: Switch back to assembly syscall wrapper for prctl (bug 29770)
>>
>> The justification for that does not apply to x32, though, because prctl
>> doesn't take floating point arguments. I don't have a strong opinion,
>> the C and assembler versions are of similar complexity.
>
> The main justification is UB to va_args *all* the arguments without taking
> in the consideration which option is passed. If x32 requires additional
> argument handling to clear the upper 32-bits, there is no advantage of
> using the assembly wrapper.
I'm okay with making this change to avoid UB.
Patch looks okay to me.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
Minor nit:
+weak_alias (__prctl, __prctl_time64)
+hidden_weak (__prctl_time64)
This isn't necessary because there is no __prctl_time64 on x32.
Thanks,
Florian
^ permalink raw reply
* v2.41.3 planning
From: Karel Zak @ 2025-12-08 14:00 UTC (permalink / raw)
To: util-linux
Hi all,
I'd like to release the stable update v2.41.3, primarily to provide an
upstream tarball with the fixed CVE-2025-14104 and to fix compilation
with gcc-15, along with some other minor fixes.
Do you see anything in the master branch that we need to include in
this stable maintenance update?
For the current state, see the stable/2.41 branch.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply
* Re: [PATCH v2] x32: Implement prctl in assembly
From: Adhemerval Zanella Netto @ 2025-12-08 11:47 UTC (permalink / raw)
To: Florian Weimer, H.J. Lu
Cc: Alejandro Colomar, Thomas Weißschuh, util-linux, Xi Ruoyao,
GNU C Library
In-Reply-To: <lhuqzt5l4pk.fsf@oldenburg.str.redhat.com>
On 08/12/25 06:09, Florian Weimer wrote:
> * H. J. Lu:
>
>> On Mon, Dec 8, 2025 at 4:11 PM Florian Weimer <fweimer@redhat.com> wrote:
>>>
>>> * H. J. Lu:
>>>> Here is the v2 patch to implement prctl in assembly for x32.
>>>>
>>>> Since the variadic prctl function takes at most 5 integer arguments which
>>>> are passed in the same integer registers on x32 as the function with 5
>>>> integer arguments, we can use assembly for prctl. Since upper 32-bits in
>>>> the last 4 arguments of prctl must be cleared to match the x32 prctl
>>>> syscall interface where the last 4 arguments are unsigned 64 bit longs,
>>>> implement prctl in assembly to clear upper 32-bits in the last 4 arguments
>>>> and add a test to verify it.
>>>
>>> What's the advantage of the assembler implementation over the C
>>> implementation? I'm missing the context for this change.
>>>
>>
>> It is inspired by
>>
>> commit 6a04404521ac4119ae36827eeb288ea84eee7cf6
>> Author: Florian Weimer <fweimer@redhat.com>
>> Date: Sat Feb 17 09:17:04 2024 +0100
>>
>> Linux: Switch back to assembly syscall wrapper for prctl (bug 29770)
>
> The justification for that does not apply to x32, though, because prctl
> doesn't take floating point arguments. I don't have a strong opinion,
> the C and assembler versions are of similar complexity.
The main justification is UB to va_args *all* the arguments without taking
in the consideration which option is passed. If x32 requires additional
argument handling to clear the upper 32-bits, there is no advantage of
using the assembly wrapper.
^ permalink raw reply
* Re: [PATCH v2] x32: Implement prctl in assembly
From: Florian Weimer @ 2025-12-08 9:09 UTC (permalink / raw)
To: H.J. Lu
Cc: Adhemerval Zanella Netto, Alejandro Colomar,
Thomas Weißschuh, util-linux, Xi Ruoyao, GNU C Library
In-Reply-To: <CAMe9rOq6mx_ZQs_z2QazC2pbvJZDZzD7kLCo=_o9eTj3cUh8nA@mail.gmail.com>
* H. J. Lu:
> On Mon, Dec 8, 2025 at 4:11 PM Florian Weimer <fweimer@redhat.com> wrote:
>>
>> * H. J. Lu:
>> > Here is the v2 patch to implement prctl in assembly for x32.
>> >
>> > Since the variadic prctl function takes at most 5 integer arguments which
>> > are passed in the same integer registers on x32 as the function with 5
>> > integer arguments, we can use assembly for prctl. Since upper 32-bits in
>> > the last 4 arguments of prctl must be cleared to match the x32 prctl
>> > syscall interface where the last 4 arguments are unsigned 64 bit longs,
>> > implement prctl in assembly to clear upper 32-bits in the last 4 arguments
>> > and add a test to verify it.
>>
>> What's the advantage of the assembler implementation over the C
>> implementation? I'm missing the context for this change.
>>
>
> It is inspired by
>
> commit 6a04404521ac4119ae36827eeb288ea84eee7cf6
> Author: Florian Weimer <fweimer@redhat.com>
> Date: Sat Feb 17 09:17:04 2024 +0100
>
> Linux: Switch back to assembly syscall wrapper for prctl (bug 29770)
The justification for that does not apply to x32, though, because prctl
doesn't take floating point arguments. I don't have a strong opinion,
the C and assembler versions are of similar complexity.
Thanks,
Florian
^ permalink raw reply
* Re: [PATCH v2] x32: Implement prctl in assembly
From: H.J. Lu @ 2025-12-08 9:01 UTC (permalink / raw)
To: Florian Weimer
Cc: Adhemerval Zanella Netto, Alejandro Colomar,
Thomas Weißschuh, util-linux, Xi Ruoyao, GNU C Library
In-Reply-To: <lhuzf7tl7fz.fsf@oldenburg.str.redhat.com>
On Mon, Dec 8, 2025 at 4:11 PM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu:
> > Here is the v2 patch to implement prctl in assembly for x32.
> >
> > Since the variadic prctl function takes at most 5 integer arguments which
> > are passed in the same integer registers on x32 as the function with 5
> > integer arguments, we can use assembly for prctl. Since upper 32-bits in
> > the last 4 arguments of prctl must be cleared to match the x32 prctl
> > syscall interface where the last 4 arguments are unsigned 64 bit longs,
> > implement prctl in assembly to clear upper 32-bits in the last 4 arguments
> > and add a test to verify it.
>
> What's the advantage of the assembler implementation over the C
> implementation? I'm missing the context for this change.
>
It is inspired by
commit 6a04404521ac4119ae36827eeb288ea84eee7cf6
Author: Florian Weimer <fweimer@redhat.com>
Date: Sat Feb 17 09:17:04 2024 +0100
Linux: Switch back to assembly syscall wrapper for prctl (bug 29770)
The difference is
00000000 <__GI___prctl>:
0: f3 0f 1e fa endbr64
4: 8d 44 24 08 lea 0x8(%rsp),%eax
8: 48 89 74 24 d0 mov %rsi,-0x30(%rsp)
d: 48 63 ff movslq %edi,%rdi
10: 8b 74 24 d0 mov -0x30(%rsp),%esi
14: 89 44 24 c0 mov %eax,-0x40(%rsp)
18: 8d 44 24 c8 lea -0x38(%rsp),%eax
1c: 48 89 54 24 d8 mov %rdx,-0x28(%rsp)
21: 8b 54 24 d8 mov -0x28(%rsp),%edx
25: 48 89 4c 24 e0 mov %rcx,-0x20(%rsp)
2a: 44 8b 54 24 e0 mov -0x20(%rsp),%r10d
2f: 4c 89 44 24 e8 mov %r8,-0x18(%rsp)
34: 44 8b 44 24 e8 mov -0x18(%rsp),%r8d
39: 89 44 24 c4 mov %eax,-0x3c(%rsp)
3d: b8 9d 00 00 40 mov $0x4000009d,%eax
42: c7 44 24 b8 08 00 00 00 movl $0x8,-0x48(%rsp)
4a: 0f 05 syscall
4c: 3d 00 f0 ff ff cmp $0xfffff000,%eax
51: 77 05 ja 58 <__GI___prctl+0x58>
53: c3 ret
54: 0f 1f 40 00 nopl 0x0(%rax)
58: f7 d8 neg %eax
5a: 64 8b 14 25 00 00 00 00 mov %fs:0x0,%edx
62: 40 03 15 00 00 00 00 rex add 0x0(%rip),%edx # 69
<__GI___prctl+0x69>
69: 67 89 02 mov %eax,(%edx)
6c: b8 ff ff ff ff mov $0xffffffff,%eax
71: c3 ret
vs
00000000 <__GI___prctl>:
0: 89 f6 mov %esi,%esi
2: 89 d2 mov %edx,%edx
4: 41 89 ca mov %ecx,%r10d
7: 45 89 c0 mov %r8d,%r8d
a: b8 9d 00 00 40 mov $0x4000009d,%eax
f: 0f 05 syscall
11: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax
17: 73 01 jae 1a <__GI___prctl+0x1a>
19: c3 ret
1a: 48 8b 0d 00 00 00 00 mov 0x0(%rip),%rcx # 21 <__GI___prctl+0x21>
21: f7 d8 neg %eax
23: 64 89 01 mov %eax,%fs:(%rcx)
26: 83 c8 ff or $0xffffffff,%eax
29: c3 ret
--
H.J.
^ permalink raw reply
* Re: [PATCH v2] x32: Implement prctl in assembly
From: Florian Weimer @ 2025-12-08 8:10 UTC (permalink / raw)
To: H.J. Lu
Cc: Adhemerval Zanella Netto, Alejandro Colomar,
Thomas Weißschuh, util-linux, Xi Ruoyao, GNU C Library
In-Reply-To: <CAMe9rOqMGabug88Qm7p22Qk+oMOk9YdbAQeyb77rL3ot4HS1UA@mail.gmail.com>
* H. J. Lu:
> Here is the v2 patch to implement prctl in assembly for x32.
>
> Since the variadic prctl function takes at most 5 integer arguments which
> are passed in the same integer registers on x32 as the function with 5
> integer arguments, we can use assembly for prctl. Since upper 32-bits in
> the last 4 arguments of prctl must be cleared to match the x32 prctl
> syscall interface where the last 4 arguments are unsigned 64 bit longs,
> implement prctl in assembly to clear upper 32-bits in the last 4 arguments
> and add a test to verify it.
What's the advantage of the assembler implementation over the C
implementation? I'm missing the context for this change.
Thanks,
Florian
^ permalink raw reply
* [PATCH v2] x32: Implement prctl in assembly
From: H.J. Lu @ 2025-12-08 1:48 UTC (permalink / raw)
To: Florian Weimer
Cc: Adhemerval Zanella Netto, Alejandro Colomar,
Thomas Weißschuh, util-linux, Xi Ruoyao, GNU C Library
In-Reply-To: <lhuh5u2aat0.fsf@oldenburg.str.redhat.com>
[-- Attachment #1: Type: text/plain, Size: 1680 bytes --]
On Sun, Dec 7, 2025 at 5:41 PM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu:
>
> > On Thu, Dec 4, 2025 at 10:06 PM Adhemerval Zanella Netto
> > <adhemerval.zanella@linaro.org> wrote:
> >>
> >> The x32 and or1k (which also uses similar implementation) does seems broken
> >> without checking the 'option' argument to see which arg we can va_arg.
> >>
> >> The problem is adding this logic on libc will add some forward-compatibility
> >> that we try to avoid (newer kernel prctl additions might now work correctly).
> >>
> >> I am not sure why we haven't switch x32 back to the assembly wrappers
> >> with 6a04404521ac4119ae36827eeb288ea84eee7cf6 fix (BZ#29770). H.J, can
> >> use remove the x32 C version (and also or1k as well)?
> >
> > Since the variadic prctl function takes at most 5 integer arguments which
> > are passed in the same integer registers on x32 as the function with 5
> > integer arguments, we can safely use assembly syscall wrapper for prctl
> > for x32.
>
> The C implementation clears the upper 32 bits of registers. Does the
> assembler wrapper do the same?
>
Here is the v2 patch to implement prctl in assembly for x32.
Since the variadic prctl function takes at most 5 integer arguments which
are passed in the same integer registers on x32 as the function with 5
integer arguments, we can use assembly for prctl. Since upper 32-bits in
the last 4 arguments of prctl must be cleared to match the x32 prctl
syscall interface where the last 4 arguments are unsigned 64 bit longs,
implement prctl in assembly to clear upper 32-bits in the last 4 arguments
and add a test to verify it.
--
H.J.
[-- Attachment #2: v2-0001-x32-Implement-prctl-in-assembly.patch --]
[-- Type: text/x-patch, Size: 5782 bytes --]
From 20f922113e65f4806db724935f7a747db639db42 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 7 Dec 2025 11:33:33 +0800
Subject: [PATCH v2] x32: Implement prctl in assembly
Since the variadic prctl function takes at most 5 integer arguments which
are passed in the same integer registers on x32 as the function with 5
integer arguments, we can use assembly for prctl. Since upper 32-bits in
the last 4 arguments of pcrtl must be cleared to match the x32 prctl
syscall interface where the last 4 arguments are unsigned 64 bit longs,
implement prctl in assembly to clear upper 32-bits in the last 4 arguments
and add a test to verify it.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
sysdeps/unix/sysv/linux/x86_64/x32/Makefile | 6 ++
.../linux/x86_64/x32/{prctl.c => prctl.S} | 38 ++++++-----
.../sysv/linux/x86_64/x32/tst-prctl-x32.c | 63 +++++++++++++++++++
3 files changed, 87 insertions(+), 20 deletions(-)
rename sysdeps/unix/sysv/linux/x86_64/x32/{prctl.c => prctl.S} (50%)
create mode 100644 sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/Makefile b/sysdeps/unix/sysv/linux/x86_64/x32/Makefile
index 16b768d8ba..004f449883 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/Makefile
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/Makefile
@@ -3,6 +3,12 @@ default-abi := x32
ifeq ($(subdir),misc)
sysdep_routines += arch_prctl
+
+tests += \
+ tst-prctl-x32 \
+# tests
+
+CFLAGS-tst-prctl-x32.c += $(no-stack-protector)
endif
ifeq ($(subdir),conform)
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c b/sysdeps/unix/sysv/linux/x86_64/x32/prctl.S
similarity index 50%
rename from sysdeps/unix/sysv/linux/x86_64/x32/prctl.c
rename to sysdeps/unix/sysv/linux/x86_64/x32/prctl.S
index 714fd28837..41f643ea80 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/prctl.S
@@ -1,5 +1,5 @@
-/* prctl - Linux specific syscall. x86-64 x32 version.
- Copyright (C) 2020-2025 Free Software Foundation, Inc.
+/* The prctl system call. Linux/x32 version.
+ Copyright (C) 2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -17,26 +17,24 @@
<https://www.gnu.org/licenses/>. */
#include <sysdep.h>
-#include <stdarg.h>
-#include <sys/prctl.h>
-/* Unconditionally read all potential arguments. This may pass
- garbage values to the kernel, but avoids the need for teaching
- glibc the argument counts of individual options (including ones
- that are added to the kernel in the future). */
+/* Clear upper 32-bits in the last 4 arguments. Since the first argument
+ of prctl is int, leave it alone. */
+#undef DO_CALL
+#define DO_CALL(syscall_name, args, ulong_arg_1, ulong_arg_2) \
+ movl %esi, %esi; \
+ movl %edx, %edx; \
+ movl %ecx, %r10d; \
+ movl %r8d, %r8d; \
+ movl $SYS_ify (syscall_name), %eax; \
+ syscall;
-int
-__prctl (int option, ...)
-{
- va_list arg;
- va_start (arg, option);
- unsigned long int arg2 = va_arg (arg, unsigned long int);
- unsigned long int arg3 = va_arg (arg, unsigned long int);
- unsigned long int arg4 = va_arg (arg, unsigned long int);
- unsigned long int arg5 = va_arg (arg, unsigned long int);
- va_end (arg);
- return INLINE_SYSCALL_CALL (prctl, option, arg2, arg3, arg4, arg5);
-}
+PSEUDO (__prctl, prctl, 5)
+ ret
+PSEUDO_END (__prctl)
libc_hidden_def (__prctl)
weak_alias (__prctl, prctl)
+hidden_weak (prctl)
+weak_alias (__prctl, __prctl_time64)
+hidden_weak (__prctl_time64)
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c b/sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c
new file mode 100644
index 0000000000..295b09e364
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/tst-prctl-x32.c
@@ -0,0 +1,63 @@
+/* Smoke test for prctl.
+ Copyright (C) 2021-2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C 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.
+
+ The GNU C 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 the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <sys/prctl.h>
+#include <support/check.h>
+
+/* On x32, when parameters are passed in 64-bit registers, only the lower
+ 32 bits are used and the upper 32 bits must be cleared. */
+typedef union
+{
+ struct
+ {
+ union
+ {
+ const char *ptr;
+ int i1;
+ };
+ int i2;
+ } s;
+ long long ll;
+} parameter_t;
+
+static int
+__attribute__ ((noipa))
+do_prctl (int op, long long arg1, long long arg2, long long arg3,
+ long long arg4)
+{
+ return prctl (op, arg1, arg2, arg3, arg4);
+}
+
+static int
+do_test (void)
+{
+ parameter_t name = { { { "thread name" }, -1 } };
+ parameter_t zero = { { { 0 }, -2 } };
+ TEST_COMPARE (do_prctl (PR_SET_NAME, name.ll, zero.ll, zero.ll,
+ zero.ll), 0);
+ char buffer[16] = { 0, };
+ name.s.ptr = buffer;
+ TEST_COMPARE (do_prctl (PR_GET_NAME, name.ll, zero.ll, zero.ll,
+ zero.ll), 0);
+ char expected[16] = "thread name";
+ TEST_COMPARE_BLOB (buffer, sizeof (buffer), expected, sizeof (expected));
+ return 0;
+}
+
+#include <support/test-driver.c>
--
2.52.0
^ permalink raw reply related
* Re: [PATCH] x32: Switch back to assembly syscall wrapper for prctl
From: Alejandro Colomar @ 2025-12-07 12:34 UTC (permalink / raw)
To: H.J. Lu
Cc: Adhemerval Zanella Netto, Thomas Weißschuh, util-linux,
Xi Ruoyao, GNU C Library
In-Reply-To: <CAMe9rOpqX9cdhvMneHnfvJFG8ixJsdAyd6iK8mh_Th1Lpv4ahQ@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1234 bytes --]
Hi H.J.,
On Sun, Dec 07, 2025 at 11:52:08AM +0800, H.J. Lu wrote:
> On Thu, Dec 4, 2025 at 10:06 PM Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
> >
> > The x32 and or1k (which also uses similar implementation) does seems broken
> > without checking the 'option' argument to see which arg we can va_arg.
> >
> > The problem is adding this logic on libc will add some forward-compatibility
> > that we try to avoid (newer kernel prctl additions might now work correctly).
> >
> > I am not sure why we haven't switch x32 back to the assembly wrappers
> > with 6a04404521ac4119ae36827eeb288ea84eee7cf6 fix (BZ#29770). H.J, can
> > use remove the x32 C version (and also or1k as well)?
>
> Since the variadic prctl function takes at most 5 integer arguments which
> are passed in the same integer registers on x32 as the function with 5
> integer arguments, we can safely use assembly syscall wrapper for prctl
> for x32.
>
> Tested on x32. I leave or1k alone since I don't know if it is safe to
> do the same.
Thanks! Would you mind adding the following tag?
Reported-by: Alejandro Colomar <alx@kernel.org>
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH] x32: Switch back to assembly syscall wrapper for prctl
From: Florian Weimer @ 2025-12-07 9:41 UTC (permalink / raw)
To: H.J. Lu
Cc: Adhemerval Zanella Netto, Alejandro Colomar,
Thomas Weißschuh, util-linux, Xi Ruoyao, GNU C Library
In-Reply-To: <CAMe9rOpqX9cdhvMneHnfvJFG8ixJsdAyd6iK8mh_Th1Lpv4ahQ@mail.gmail.com>
* H. J. Lu:
> On Thu, Dec 4, 2025 at 10:06 PM Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
>>
>> The x32 and or1k (which also uses similar implementation) does seems broken
>> without checking the 'option' argument to see which arg we can va_arg.
>>
>> The problem is adding this logic on libc will add some forward-compatibility
>> that we try to avoid (newer kernel prctl additions might now work correctly).
>>
>> I am not sure why we haven't switch x32 back to the assembly wrappers
>> with 6a04404521ac4119ae36827eeb288ea84eee7cf6 fix (BZ#29770). H.J, can
>> use remove the x32 C version (and also or1k as well)?
>
> Since the variadic prctl function takes at most 5 integer arguments which
> are passed in the same integer registers on x32 as the function with 5
> integer arguments, we can safely use assembly syscall wrapper for prctl
> for x32.
The C implementation clears the upper 32 bits of registers. Does the
assembler wrapper do the same?
Thanks,
Florian
^ permalink raw reply
* [PATCH] x32: Switch back to assembly syscall wrapper for prctl
From: H.J. Lu @ 2025-12-07 3:52 UTC (permalink / raw)
To: Adhemerval Zanella Netto
Cc: Alejandro Colomar, Thomas Weißschuh, util-linux, Xi Ruoyao,
GNU C Library
In-Reply-To: <5272b875-bec8-4b28-84e8-05606db83120@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 961 bytes --]
On Thu, Dec 4, 2025 at 10:06 PM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
> The x32 and or1k (which also uses similar implementation) does seems broken
> without checking the 'option' argument to see which arg we can va_arg.
>
> The problem is adding this logic on libc will add some forward-compatibility
> that we try to avoid (newer kernel prctl additions might now work correctly).
>
> I am not sure why we haven't switch x32 back to the assembly wrappers
> with 6a04404521ac4119ae36827eeb288ea84eee7cf6 fix (BZ#29770). H.J, can
> use remove the x32 C version (and also or1k as well)?
Since the variadic prctl function takes at most 5 integer arguments which
are passed in the same integer registers on x32 as the function with 5
integer arguments, we can safely use assembly syscall wrapper for prctl
for x32.
Tested on x32. I leave or1k alone since I don't know if it is safe to
do the same.
--
H.J.
[-- Attachment #2: 0001-x32-Switch-back-to-assembly-syscall-wrapper-for-prct.patch --]
[-- Type: text/x-patch, Size: 2569 bytes --]
From e6a14154e90e1e6ba2372340b62dae13667bc8ba Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 7 Dec 2025 11:33:33 +0800
Subject: [PATCH] x32: Switch back to assembly syscall wrapper for prctl
Since the variadic prctl function takes at most 5 integer arguments which
are passed in the same integer registers on x32 as the function with 5
integer arguments, we can safely use assembly syscall wrapper for prctl
for x32.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
sysdeps/unix/sysv/linux/x86_64/x32/prctl.c | 42 ----------------------
1 file changed, 42 deletions(-)
delete mode 100644 sysdeps/unix/sysv/linux/x86_64/x32/prctl.c
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c b/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c
deleted file mode 100644
index 714fd28837..0000000000
--- a/sysdeps/unix/sysv/linux/x86_64/x32/prctl.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* prctl - Linux specific syscall. x86-64 x32 version.
- Copyright (C) 2020-2025 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C 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.
-
- The GNU C 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 the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
-
-#include <sysdep.h>
-#include <stdarg.h>
-#include <sys/prctl.h>
-
-/* Unconditionally read all potential arguments. This may pass
- garbage values to the kernel, but avoids the need for teaching
- glibc the argument counts of individual options (including ones
- that are added to the kernel in the future). */
-
-int
-__prctl (int option, ...)
-{
- va_list arg;
- va_start (arg, option);
- unsigned long int arg2 = va_arg (arg, unsigned long int);
- unsigned long int arg3 = va_arg (arg, unsigned long int);
- unsigned long int arg4 = va_arg (arg, unsigned long int);
- unsigned long int arg5 = va_arg (arg, unsigned long int);
- va_end (arg);
- return INLINE_SYSCALL_CALL (prctl, option, arg2, arg3, arg4, arg5);
-}
-
-libc_hidden_def (__prctl)
-weak_alias (__prctl, prctl)
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v1] Call prctl(2) with long integers, specify 5 arguments, and avoid casts
From: Adhemerval Zanella Netto @ 2025-12-04 14:06 UTC (permalink / raw)
To: Alejandro Colomar, Thomas Weißschuh, H.J. Lu
Cc: util-linux, Xi Ruoyao, libc-alpha
In-Reply-To: <mbvtkssza7bvvu45wqivbfd2astvpsu3t7u223a222oizrqznm@rv4rxvvkxzct>
On 01/06/24 09:23, Alejandro Colomar wrote:
> Hi Thomas,
>
> On Sat, Jun 01, 2024 at 01:05:02PM GMT, Thomas Weißschuh wrote:
>> On 2024-06-01 11:31:56+0000, Alejandro Colomar wrote:
>>> Since libc's prctl(2) wrapper is a variadic function, arguments must
>>> have the right width. Otherwise, the behavior is undefined.
>>
>> Ack.
>>
>>> Also, the 5 arguments must be specified always, or the behavior is also
>>> undefined. libc reads 5 values and passes them all to the kernel, so if
>>> one is uninitialized, the kernel will receive garbagge, which could
>>> result in EINVAL (most likely), or worse, a different action.
>>
>> This seems surprising.
>>
>> The kernel should only check the arguments it documents and not more.
>
> Hmmm, some prctl(2) calls don't document a need for passing 0 (probably
> for legacy compatibility; you're right. Only newer prctl(2)s check
> those args.
>
> And see for example these kernel commit:
>
> commit e9d1b4f3c60997fe197bf0243cb4a41a44387a88
> Author: Dave Hansen <dave.hansen@linux.intel.com>
> Date: Thu Jan 8 14:30:22 2015 -0800
>
> x86, mpx: Strictly enforce empty prctl() args
>
> Description from Michael Kerrisk. He suggested an identical patch
> to one I had already coded up and tested.
>
> commit fe3d197f8431 "x86, mpx: On-demand kernel allocation of bounds
> tables" added two new prctl() operations, PR_MPX_ENABLE_MANAGEMENT and
> PR_MPX_DISABLE_MANAGEMENT. However, no checks were included to ensure
> that unused arguments are zero, as is done in many existing prctl()s
> and as should be done for all new prctl()s. This patch adds the
> required checks.
>
> Suggested-by: Andy Lutomirski <luto@amacapital.net>
> Suggested-by: Michael Kerrisk <mtk.manpages@gmail.com>
> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: Dave Hansen <dave@sr71.net>
> Link: http://lkml.kernel.org/r/20150108223022.7F56FD13@viggo.jf.intel.com
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
>
> diff --git a/kernel/sys.c b/kernel/sys.c
> index a8c9f5a7dda6..ea9c88109894 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -2210,9 +2210,13 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> up_write(&me->mm->mmap_sem);
> break;
> case PR_MPX_ENABLE_MANAGEMENT:
> + if (arg2 || arg3 || arg4 || arg5)
> + return -EINVAL;
> error = MPX_ENABLE_MANAGEMENT(me);
> break;
> case PR_MPX_DISABLE_MANAGEMENT:
> + if (arg2 || arg3 || arg4 || arg5)
> + return -EINVAL;
> error = MPX_DISABLE_MANAGEMENT(me);
> break;
> default:
>
> And this one too:
>
> commit 3e91ec89f527b9870fe42dcbdb74fd389d123a95
> Author: Catalin Marinas <catalin.marinas@arm.com>
> Date: Thu Aug 15 16:44:00 2019 +0100
>
> arm64: Tighten the PR_{SET, GET}_TAGGED_ADDR_CTRL prctl() unused arguments
>
> Require that arg{3,4,5} of the PR_{SET,GET}_TAGGED_ADDR_CTRL prctl and
> arg2 of the PR_GET_TAGGED_ADDR_CTRL prctl() are zero rather than ignored
> for future extensions.
>
> Acked-by: Andrey Konovalov <andreyknvl@google.com>
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Will Deacon <will@kernel.org>
>
> diff --git a/kernel/sys.c b/kernel/sys.c
> index c6c4d5358bd3..ec48396b4943 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -2499,9 +2499,13 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> error = PAC_RESET_KEYS(me, arg2);
> break;
> case PR_SET_TAGGED_ADDR_CTRL:
> + if (arg3 || arg4 || arg5)
> + return -EINVAL;
> error = SET_TAGGED_ADDR_CTRL(arg2);
> break;
> case PR_GET_TAGGED_ADDR_CTRL:
> + if (arg2 || arg3 || arg4 || arg5)
> + return -EINVAL;
> error = GET_TAGGED_ADDR_CTRL();
> break;
> default:
>
> In the few calls that util-linux makes without specifying all 5 args,
> the kernel seems to not do the checks (in some old prctl(2)s they didn't
> have that check, and nobody seems to have cared enough to add it), so
> it's more like we're lucky (or unlucky, depending on how you see it).
>
>> glibc itself doesn't even specify all five arguments in its own calls to
>> prctl().
>
> glibc itself is wrong. I'm even surprised that the PR_* macros from the
> kernel UAPI for arg2 work without specifying the L suffix on them, but
> it's probably just luck.
>
> <https://lore.kernel.org/linux-api/20240528114750.106187-1-alx@kernel.org/T/#u>
>
>> If all five arguments are really required then prctl() wouldn't need to
>> be variadic.
>
> Indeed. I guess that's for historic reasons, rather than actual
> necessity; but I don't know for sure.
>
>> How is random non-zero data less valid than a essentially random zero?
>> And if the kernel actually validates this, how has it ever worked before?
>
> They only added validation for (all) new prctl(2) calls, plus maybe some
> old ones, but not all. In the ones used in util-linux that don't
> specify zero, I've checked now that the kernel doesn't validate.
>
> However, a call such as
>
> prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)
>
> (this call exists in util-linux)
> actually means
>
> prctl(PR_SET_NO_NEW_PRIVS, 1L, 0L, random, random)
>
> and it supposedly has been working so far. Those random bits are
> probably 0 most of the time, for some reason. And the kernel does check
> this one:
>
> $ sed -n /PR_SET_NO_NEW_PRIVS/,+2p <kernel/sys.c
> case PR_SET_NO_NEW_PRIVS:
> if (arg2 != 1 || arg3 || arg4 || arg5)
> return -EINVAL;
>
>> Other popular software like systemd or opendjk also don't specify unused arguments.
>
> I've also checked that the ones that systemd uses without specifying all
> 5 args, they are not checked by the kernel.
>
>> So it doesn't really seem "broken".
>> If the patch is more about "being on the safe side", then this should be
>> spelled out.
>
> Still, libc reads those values (on x32) which results in Undefined
> Behavior inside glibc. Which is a bad thing. Not broken, because the
> compiler has little information to exploit that UB, but not a good thing
> either.
>
> $ grepc __prctl .
> ./include/sys/prctl.h:extern int __prctl (int __option, ...);
> ./sysdeps/unix/sysv/linux/x86_64/x32/prctl.c:int
> __prctl (int option, ...)
> {
> va_list arg;
> va_start (arg, option);
> unsigned long int arg2 = va_arg (arg, unsigned long int);
> unsigned long int arg3 = va_arg (arg, unsigned long int);
> unsigned long int arg4 = va_arg (arg, unsigned long int);
> unsigned long int arg5 = va_arg (arg, unsigned long int);
> va_end (arg);
> return INLINE_SYSCALL_CALL (prctl, option, arg2, arg3, arg4, arg5);
> }
>
> It's arguably less broken than the missing 'L', though.
The x32 and or1k (which also uses similar implementation) does seems broken
without checking the 'option' argument to see which arg we can va_arg.
The problem is adding this logic on libc will add some forward-compatibility
that we try to avoid (newer kernel prctl additions might now work correctly).
I am not sure why we haven't switch x32 back to the assembly wrappers
with 6a04404521ac4119ae36827eeb288ea84eee7cf6 fix (BZ#29770). H.J, can
use remove the x32 C version (and also or1k as well)?
>
>> (Plus the cases where documented, required arguments are missing)
>
> None of the cases where we omit the arguments are checked by the kernel.
>
>
> Have a lovely day!
> Alex
>
^ permalink raw reply
* Re: [PATCH v2 0/1] Call prctl(2) with signed long integers, and avoid casts
From: Alejandro Colomar @ 2025-12-03 22:36 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: util-linux, Xi Ruoyao, Karel Zak
In-Reply-To: <0ed6fa4c-7098-474c-99a5-f2c02879b119@t-8ch.de>
[-- Attachment #1: Type: text/plain, Size: 1623 bytes --]
Hi Thomas!
On Wed, Dec 03, 2025 at 11:12:47PM +0100, Thomas Weißschuh wrote:
> Hi!
>
> On 2025-12-03 22:01:18+0100, Alejandro Colomar wrote:
> > On Wed, Dec 03, 2025 at 09:50:27PM +0100, Alejandro Colomar wrote:
> > > Karel reminded me of this old patch. Here's a revision of the patch.
> > > Major changes in v2:
> > >
> > > - Don't specify the 5 arguments unnecessarily.
> > >
> > > BTW, I've developed a header file that might be useful for the general
> > > public. See in a reply to this mail.
> >
> > Here it is. I think it would be useful to provide this in some libprctl
> > library so that everyone can use these, instead of raw prctl(2). What
> > do you think? We could start by including this header file within
> > util-linux, and then consider providing in a separate git repository so
> > that distros can package it as a system library.
>
> What about fixing raw prctl(2) in libc to avoid the issues you are
> fixing in your original patch? prctl() could be a macro which counts its
> passed arguments, dispatching to a set of inline functions which then in
> turn call the underlying prctl() with the correct set of parameters.
> This would be backwards-compatible and safe.
I'm not sure how this would be implementable in a single macro. If
possible at all, I guess such a macro would be easily over 1k lines of
hardly readable code. I think providing these inline functions in libc
would be more reasonable. I can ask glibc and see what they think.
Have a lovely night!
Alex
>
> (...)
>
>
> Thomas
--
<https://www.alejandro-colomar.es>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v2 0/1] Call prctl(2) with signed long integers, and avoid casts
From: Thomas Weißschuh @ 2025-12-03 22:12 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: util-linux, Xi Ruoyao, Karel Zak
In-Reply-To: <xfml2leih5xmokh4vhyyaarsq6ly7ehq5zfdjwwpkgnodiygwp@7tjm4lfqo6is>
Hi!
On 2025-12-03 22:01:18+0100, Alejandro Colomar wrote:
> On Wed, Dec 03, 2025 at 09:50:27PM +0100, Alejandro Colomar wrote:
> > Karel reminded me of this old patch. Here's a revision of the patch.
> > Major changes in v2:
> >
> > - Don't specify the 5 arguments unnecessarily.
> >
> > BTW, I've developed a header file that might be useful for the general
> > public. See in a reply to this mail.
>
> Here it is. I think it would be useful to provide this in some libprctl
> library so that everyone can use these, instead of raw prctl(2). What
> do you think? We could start by including this header file within
> util-linux, and then consider providing in a separate git repository so
> that distros can package it as a system library.
What about fixing raw prctl(2) in libc to avoid the issues you are
fixing in your original patch? prctl() could be a macro which counts its
passed arguments, dispatching to a set of inline functions which then in
turn call the underlying prctl() with the correct set of parameters.
This would be backwards-compatible and safe.
(...)
Thomas
^ permalink raw reply
* Re: [PATCH v2 0/1] Call prctl(2) with signed long integers, and avoid casts
From: Alejandro Colomar @ 2025-12-03 21:01 UTC (permalink / raw)
To: util-linux; +Cc: Xi Ruoyao, Thomas Weißschuh, Karel Zak
In-Reply-To: <cover.1764794880.git.alx@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 10989 bytes --]
Hi,
On Wed, Dec 03, 2025 at 09:50:27PM +0100, Alejandro Colomar wrote:
> Hi!
>
> Karel reminded me of this old patch. Here's a revision of the patch.
> Major changes in v2:
>
> - Don't specify the 5 arguments unnecessarily.
>
> BTW, I've developed a header file that might be useful for the general
> public. See in a reply to this mail.
Here it is. I think it would be useful to provide this in some libprctl
library so that everyone can use these, instead of raw prctl(2). What
do you think? We could start by including this header file within
util-linux, and then consider providing in a separate git repository so
that distros can package it as a system library.
Have a lovely night!
Alex
---
// Copyright 2025, Alejandro Colomar <alx@kernel.org>
// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
#include <linux/filter.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/prctl.h>
#include <sys/types.h>
#if __has_include(<seccomp.h>)
# include <seccomp.h>
#endif
#if !defined(__has_c_attribute)
# define __has_c_attribute(x) 0
#endif
#if __has_attribute(__null_terminated_string_arg__)
# define LIBPRCTL_ATTR_STRING(i) __attribute__((__null_terminated_string_arg__(i)))
#endif
#if __has_attribute(__deprecated__)
# define LIBPRCTL_ATTR_DEPRECATED __attribute__((__deprecated__))
#endif
_Static_assert(sizeof(long) == sizeof(void *), "");
_Static_assert(sizeof(long) == sizeof(size_t), "");
static inline int pr_cap_ambient_raise(int64_t cap) {
return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (long){cap}, 0L, 0L);
}
static inline int pr_cap_ambient_lower(int64_t cap) {
return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, (long){cap}, 0L, 0L);
}
static inline int pr_cap_ambient_is_set(int64_t cap) {
return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, (long){cap}, 0L,0L);
}
static inline int pr_cap_ambient_clear_all(void) {
return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0L, 0L, 0L);
}
static inline int pr_capbset_read(int64_t cap) {
return prctl(PR_CAPBSET_READ, (long){cap});
}
static inline int pr_capbset_drop(int64_t cap) {
return prctl(PR_CAPBSET_DROP, (long){cap});
}
static inline int pr_set_child_subreaper(bool set) {
return prctl(PR_SET_CHILD_SUBREAPER, (long){set});
}
static inline int pr_get_child_subreaper(bool *isset)
{
int ret, x;
ret = prctl(PR_GET_CHILD_SUBREAPER, &x);
*isset = x;
return ret;
}
static inline int pr_set_dumpable(bool set) {
return prctl(PR_SET_DUMPABLE, (long){set});
}
static inline int pr_get_dumpable(void) {
return prctl(PR_GET_DUMPABLE);
}
static inline int pr_set_endian(int endianness) {
return prctl(PR_SET_ENDIAN, (long){endianness});
}
static inline int pr_get_endian(int *endianness) {
return prctl(PR_GET_ENDIAN, endianness);
}
static inline int pr_set_fp_mode(unsigned int mode) {
return prctl(PR_SET_FP_MODE, (unsigned long){mode});
}
static inline int pr_get_fp_mode(void) {
return prctl(PR_GET_FP_MODE);
}
static inline int pr_set_fpemu(int fpemu) {
return prctl(PR_SET_FPEMU, (long){fpemu});
}
static inline int pr_get_fpemu(int *fpemu) {
return prctl(PR_GET_FPEMU, fpemu);
}
static inline int pr_set_fpexec(int mode) {
return prctl(PR_SET_FPEXC, (long){mode});
}
static inline int pr_get_fpexec(int *mode) {
return prctl(PR_GET_FPEXC, mode);
}
static inline int pr_set_io_flusher(bool set) {
return prctl(PR_SET_IO_FLUSHER, (long){set}, 0L, 0L, 0L);
}
static inline int pr_get_io_flusher(void) {
return prctl(PR_GET_IO_FLUSHER, 0L, 0L, 0L, 0L);
}
static inline int pr_set_keepcaps(bool set) {
return prctl(PR_SET_KEEPCAPS, (long){set});
}
static inline int pr_get_keepcaps(void) {
return prctl(PR_GET_KEEPCAPS);
}
static inline int pr_mce_kill_clear(void) {
return prctl(PR_MCE_KILL, PR_MCE_KILL_CLEAR, 0L, 0L, 0L);
}
static inline int pr_mce_kill_set(int policy) {
return prctl(PR_MCE_KILL, PR_MCE_KILL_SET, (long){policy}, 0L, 0L);
}
static inline int pr_mce_kill_get(void) {
return prctl(PR_MCE_KILL_GET, 0L, 0L, 0L, 0L);
}
static inline int pr_set_mm_start_code(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_START_CODE, addr, 0L, 0L);
}
static inline int pr_set_mm_end_code(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_END_CODE, addr, 0L, 0L);
}
static inline int pr_set_mm_start_data(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_START_DATA, addr, 0L, 0L);
}
static inline int pr_set_mm_end_data(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_END_DATA, addr, 0L, 0L);
}
static inline int pr_set_mm_start_stack(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_START_STACK, addr, 0L, 0L);
}
static inline int pr_set_mm_start_brk(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_START_BRK, addr, 0L, 0L);
}
static inline int pr_set_mm_brk(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_BRK, addr, 0L, 0L);
}
static inline int pr_set_mm_arg_start(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_ARG_START, addr, 0L, 0L);
}
static inline int pr_set_mm_arg_end(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_ARG_END, addr, 0L, 0L);
}
static inline int pr_set_mm_env_start(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_ENV_START, addr, 0L, 0L);
}
static inline int pr_set_mm_env_end(const void *addr) {
return prctl(PR_SET_MM, PR_SET_MM_ENV_END, addr, 0L, 0L);
}
static inline int pr_set_mm_auxv(const void *addr, size_t size) {
return prctl(PR_SET_MM, PR_SET_MM_AUXV, addr, size, 0L);
}
static inline int pr_set_mm_exe_file(int fd) {
return prctl(PR_SET_MM, PR_SET_MM_EXE_FILE, (long){fd}, 0L, 0L);
}
static inline int pr_set_mm_map(struct prctl_mm_map *map)
{
return prctl(PR_SET_MM, PR_SET_MM_MAP, map,
sizeof(struct prctl_mm_map), 0L);
}
static inline int pr_set_mm_map_size(size_t *size)
{
int ret, x;
ret = prctl(PR_SET_MM, PR_SET_MM_MAP_SIZE, &x, 0L, 0L);
*size = x;
return ret;
}
LIBPRCTL_ATTR_STRING(3)
static inline int
pr_set_vma_anon_name(const void *addr, size_t size, const char *name)
{
return prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, name);
}
LIBPRCTL_ATTR_DEPRECATED
static inline int pr_mpx_enable_management(void) {
return prctl(PR_MPX_ENABLE_MANAGEMENT, 0L, 0L, 0L, 0L);
}
LIBPRCTL_ATTR_DEPRECATED
static inline int pr_mpx_disable_management(void) {
return prctl(PR_MPX_DISABLE_MANAGEMENT, 0L, 0L, 0L, 0L);
}
LIBPRCTL_ATTR_STRING(1)
static inline int pr_set_name(const char *name) {
return prctl(PR_SET_NAME, name);
}
LIBPRCTL_ATTR_STRING(1)
static inline int pr_get_name(char name[16]) {
return prctl(PR_GET_NAME, name);
}
static inline int pr_set_no_new_privs(void) {
return prctl(PR_SET_NO_NEW_PRIVS, 1L, 0L, 0L, 0L);
}
static inline int pr_get_no_new_privs(void) {
return prctl(PR_GET_NO_NEW_PRIVS, 0L, 0L, 0L, 0L);
}
static inline int pr_pac_reset_keys(unsigned long keys) {
return prctl(PR_PAC_RESET_KEYS, keys, 0L, 0L, 0L);
}
static inline int pr_set_pdeathsig(int sig) {
return prctl(PR_SET_PDEATHSIG, (long){sig});
}
static inline int pr_get_pdeathsig(int *sig) {
return prctl(PR_GET_PDEATHSIG, sig);
}
static inline int pr_set_ptracer(pid_t pid) {
return prctl(PR_SET_PTRACER, (long){pid});
}
#if __has_include(<seccomp.h>)
LIBPRCTL_ATTR_DEPRECATED
static inline int pr_set_seccomp_mode_strict(void) {
return prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
}
LIBPRCTL_ATTR_DEPRECATED
static inline int pr_set_seccomp_mode_filter(const struct sock_fprog *filter) {
return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, filter);
}
#endif
static inline int pr_get_seccomp(void) {
return prctl(PR_GET_SECCOMP);
}
static inline int pr_set_securebits(unsigned int securebits) {
return prctl(PR_SET_SECUREBITS, (unsigned long){securebits});
}
static inline int pr_get_securebits(void) {
return prctl(PR_GET_SECUREBITS);
}
static inline int pr_get_speculation_ctrl(long misfeature) {
return prctl(PR_GET_SPECULATION_CTRL, misfeature, 0L, 0L, 0L);
}
static inline int pr_set_speculation_ctrl(long misfeature, int ctrl) {
return prctl(PR_SET_SPECULATION_CTRL, misfeature, (long){ctrl}, 0L, 0L);
}
static inline int pr_sve_set_vl(unsigned long val) {
return prctl(PR_SVE_SET_VL, val);
}
static inline int pr_sve_get_vl(void) {
return prctl(PR_SVE_GET_VL);
}
static inline int pr_sys_dispatch_on(size_t off, size_t size, int8_t *sw)
{
return prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON,
off, size, sw);
}
static inline int pr_sys_dispatch_off(void) {
return prctl(PR_SET_SYSCALL_USER_DISPATCH,PR_SYS_DISPATCH_OFF,0L,0L,0L);
}
static inline int pr_set_tagged_addr_ctrl(int mode) {
return prctl(PR_SET_TAGGED_ADDR_CTRL, (long){mode}, 0L, 0L, 0L);
}
static inline int pr_get_tagged_addr_ctrl(void) {
return prctl(PR_GET_TAGGED_ADDR_CTRL, 0L, 0L, 0L, 0L);
}
static inline int pr_task_perf_events_enable(void) {
return prctl(PR_TASK_PERF_EVENTS_ENABLE);
}
static inline int pr_task_perf_events_disable(void) {
return prctl(PR_TASK_PERF_EVENTS_DISABLE);
}
static inline int pr_set_thp_disable(bool set, unsigned int flags)
{
return prctl(PR_SET_THP_DISABLE, (long){set},
(unsigned long){flags}, 0L, 0L);
}
static inline int pr_get_thp_disable(void) {
return prctl(PR_GET_THP_DISABLE, 0L, 0L, 0L, 0L);
}
static inline int pr_get_tid_address(int **addrp) {
return prctl(PR_GET_TID_ADDRESS, addrp);
}
static inline int pr_set_timerslack(unsigned int slack) {
return prctl(PR_SET_TIMERSLACK, (unsigned long){slack});
}
static inline int pr_get_timerslack(void) {
return prctl(PR_GET_TIMERSLACK);
}
static inline int pr_set_timing(int mode) {
return prctl(PR_SET_TIMING, (long){mode});
}
static inline int pr_get_timing(void) {
return prctl(PR_GET_TIMING);
}
static inline int pr_set_tsc(int mode) {
return prctl(PR_SET_TSC, (long){mode});
}
static inline int pr_get_tsc(int *mode) {
return prctl(PR_GET_TSC, mode);
}
static inline int pr_set_unalign(unsigned int bits) {
return prctl(PR_SET_UNALIGN, (long){bits});
}
static inline int pr_get_unalign(unsigned int *bits) {
return prctl(PR_GET_UNALIGN, bits);
}
static inline int pr_get_auxv(void *auxv, size_t size) {
return prctl(PR_GET_AUXV, auxv, size, 0L, 0L);
}
static inline int pr_set_mdwe(unsigned int mask) {
return prctl(PR_SET_MDWE, mask, 0L, 0L, 0L);
}
static inline int pr_get_mdwe(void) {
return prctl(PR_GET_MDWE, 0L, 0L, 0L, 0L);
}
static inline int pr_riscv_set_icache_flush_ctx(int ctx, int scope) {
return prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, (long){ctx}, (long){scope});
}
static inline int pr_futex_hash_get_slots(void) {
return prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_GET_SLOTS);
}
static inline int pr_futex_hash_set_slots(size_t size) {
return prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_SET_SLOTS, size, 0L);
}
--
<https://www.alejandro-colomar.es>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH v2 1/1] Call prctl(2) with signed long integers, and avoid casts
From: Alejandro Colomar @ 2025-12-03 20:50 UTC (permalink / raw)
To: util-linux; +Cc: Alejandro Colomar, Xi Ruoyao, Thomas Weißschuh, Karel Zak
In-Reply-To: <cover.1764794880.git.alx@kernel.org>
Since libc's prctl(2) wrapper is a variadic function, arguments must
have the right width. Otherwise, the behavior is undefined. The kernel
expects long arguments, so let's provide them.
Also, avoid some casts to unsigned long, by changing the type of the
parameter in some local wrappers.
And use consistently 0L. 0UL is basically the same, and uses one more
character. Keep it short. Also, unsigned integer literals are
dangerous, as the compiler can't diagnose mistakes such as overflow.
- Casts are evil.
- prctl(2) expects long integers, and
Link: <https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/commit/?id=6698b096a6f5342cb9b338c237ed875a8635497a>
Link: <https://lore.kernel.org/linux-man/ddbdyaiptesjalgfmztxideej67e3yaob7ucsmbf6qvriwxiif@dohhxrqgwhrf/T/#med306b5b003f9cc7cc2de69fcdd7ee2d056d0954>
Link: <https://lore.kernel.org/util-linux/20240601093150.16912-1-alx@kernel.org/T/#u>
Link: <https://github.com/util-linux/util-linux/pull/3085>
Cc: Xi Ruoyao <xry111@xry111.site>
Cc: Thomas Weißschuh <thomas@t-8ch.de>
Cc: Karel Zak <kzak@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
lib/caputils.c | 6 +++---
lib/env.c | 4 ++--
misc-utils/enosys.c | 2 +-
schedutils/coresched.c | 6 +++---
sys-utils/setpriv-landlock.c | 2 +-
sys-utils/setpriv.c | 27 +++++++++++++--------------
tests/helpers/test_mkfds.c | 2 +-
7 files changed, 24 insertions(+), 25 deletions(-)
diff --git a/lib/caputils.c b/lib/caputils.c
index 6c71c06b8..ea885ac62 100644
--- a/lib/caputils.c
+++ b/lib/caputils.c
@@ -25,10 +25,10 @@
#include "procfs.h"
#include "nls.h"
-static int test_cap(unsigned int cap)
+static int test_cap(unsigned long cap)
{
/* prctl returns 0 or 1 for valid caps, -1 otherwise */
- return prctl(PR_CAPBSET_READ, cap, 0, 0, 0) >= 0;
+ return prctl(PR_CAPBSET_READ, cap, 0L, 0L, 0L) >= 0;
}
static int cap_last_by_bsearch(int *ret)
@@ -119,7 +119,7 @@ void cap_permitted_to_ambient(void)
continue;
if ((effective & (1ULL << cap))
- && prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0)
+ && prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0L, 0L) < 0)
err(EXIT_FAILURE, _("prctl(PR_CAP_AMBIENT) failed"));
}
}
diff --git a/lib/env.c b/lib/env.c
index 039fad0dc..7669a17b8 100644
--- a/lib/env.c
+++ b/lib/env.c
@@ -263,11 +263,11 @@ char *safe_getenv(const char *arg)
if (is_privileged_execution())
return NULL;
#ifdef HAVE_PRCTL
- if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+ if (prctl(PR_GET_DUMPABLE, 0L, 0L, 0L, 0L) == 0)
return NULL;
#else
#if (defined(linux) && defined(SYS_prctl))
- if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+ if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0L, 0L, 0L, 0L) == 0)
return NULL;
#endif
#endif
diff --git a/misc-utils/enosys.c b/misc-utils/enosys.c
index f1438b8e8..11f183901 100644
--- a/misc-utils/enosys.c
+++ b/misc-utils/enosys.c
@@ -298,7 +298,7 @@ int main(int argc, char **argv)
if (prctl(PR_GET_SECCOMP) == -1 && errno == EINVAL)
err(EXIT_NOTSUPP, _("Seccomp non-functional"));
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1L, 0L, 0L, 0L))
err_nosys(EXIT_FAILURE, _("Could not run prctl(PR_SET_NO_NEW_PRIVS)"));
if (ul_set_seccomp_filter_spec_allow(&prog))
diff --git a/schedutils/coresched.c b/schedutils/coresched.c
index 419745897..aaacf4027 100644
--- a/schedutils/coresched.c
+++ b/schedutils/coresched.c
@@ -122,20 +122,20 @@ static sched_core_cookie core_sched_get_cookie(pid_t pid)
static void core_sched_create_cookie(pid_t pid, sched_core_scope type)
{
- if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, pid, type, 0))
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, pid, type, 0L))
err(EXIT_FAILURE, _("Failed to create cookie for PID %d"), pid);
}
static void core_sched_pull_cookie(pid_t from)
{
if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_FROM, from,
- PR_SCHED_CORE_SCOPE_THREAD, 0))
+ PR_SCHED_CORE_SCOPE_THREAD, 0L))
err(EXIT_FAILURE, _("Failed to pull cookie from PID %d"), from);
}
static void core_sched_push_cookie(pid_t to, sched_core_scope type)
{
- if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, to, type, 0))
+ if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, to, type, 0L))
err(EXIT_FAILURE, _("Failed to push cookie to PID %d"), to);
}
diff --git a/sys-utils/setpriv-landlock.c b/sys-utils/setpriv-landlock.c
index 90ab8954b..9089a3c95 100644
--- a/sys-utils/setpriv-landlock.c
+++ b/sys-utils/setpriv-landlock.c
@@ -191,7 +191,7 @@ void do_landlock(const struct setpriv_landlock_opts *opts)
err(SETPRIV_EXIT_PRIVERR, _("adding landlock rule failed"));
}
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1L, 0L, 0L, 0L) == -1)
err(SETPRIV_EXIT_PRIVERR, _("disallow granting new privileges for landlock failed"));
if (landlock_restrict_self(fd, 0) == -1)
diff --git a/sys-utils/setpriv.c b/sys-utils/setpriv.c
index c218be8e5..f0f423819 100644
--- a/sys-utils/setpriv.c
+++ b/sys-utils/setpriv.c
@@ -171,7 +171,7 @@ static void __attribute__((__noreturn__)) usage(void)
exit(EXIT_SUCCESS);
}
-static int has_cap(enum cap_type which, unsigned int i)
+static int has_cap(enum cap_type which, unsigned long i)
{
switch (which) {
case CAP_TYPE_EFFECTIVE:
@@ -180,8 +180,7 @@ static int has_cap(enum cap_type which, unsigned int i)
case CAP_TYPE_PERMITTED:
return capng_have_capability((capng_type_t)which, i);
case CAP_TYPE_AMBIENT:
- return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET,
- (unsigned long) i, 0UL, 0UL);
+ return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0L, 0L);
default:
warnx(_("invalid capability type"));
return -1;
@@ -229,7 +228,7 @@ static void dump_one_secbit(int *first, int *bits, int bit, const char *name)
static void dump_securebits(void)
{
int first = 1;
- int bits = prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
+ int bits = prctl(PR_GET_SECUREBITS, 0L, 0L, 0L, 0L);
if (bits < 0) {
warnx(_("getting process secure bits failed"));
@@ -369,7 +368,7 @@ static void dump(int dumplevel)
dump_groups();
- x = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
+ x = prctl(PR_GET_NO_NEW_PRIVS, 0L, 0L, 0L, 0L);
if (0 <= x)
printf("no_new_privs: %d\n", x);
else
@@ -513,7 +512,7 @@ static void bump_cap(unsigned int cap)
}
static int cap_update(capng_act_t action,
- enum cap_type type, unsigned int cap)
+ enum cap_type type, unsigned long cap)
{
switch (type) {
case CAP_TYPE_EFFECTIVE:
@@ -527,10 +526,10 @@ static int cap_update(capng_act_t action,
if (action == CAPNG_ADD)
ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE,
- (unsigned long) cap, 0UL, 0UL);
+ cap, 0L, 0L);
else
ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER,
- (unsigned long) cap, 0UL, 0UL);
+ cap, 0L, 0L);
return ret;
}
@@ -584,7 +583,7 @@ static void parse_securebits(struct privctx *opts, const char *arg)
char *c;
opts->have_securebits = 1;
- opts->securebits = prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
+ opts->securebits = prctl(PR_GET_SECUREBITS, 0L, 0L, 0L, 0L);
if (opts->securebits < 0)
err(SETPRIV_EXIT_PRIVERR, _("getting process secure bits failed"));
@@ -709,7 +708,7 @@ static void do_seccomp_filter(const char *file)
if (prctl(PR_GET_SECCOMP) == -1 && errno == EINVAL)
err(SETPRIV_EXIT_PRIVERR, _("Seccomp non-functional"));
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1L, 0L, 0L, 0L))
err(SETPRIV_EXIT_PRIVERR, _("Could not run prctl(PR_SET_NO_NEW_PRIVS)"));
if (ul_set_seccomp_filter_spec_allow(&prog))
@@ -1086,7 +1085,7 @@ int main(int argc, char **argv)
do_reset_environ(pw);
}
- if (opts.nnp && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
+ if (opts.nnp && prctl(PR_SET_NO_NEW_PRIVS, 1L, 0L, 0L, 0L) == -1)
err(EXIT_FAILURE, _("disallow granting new privileges failed"));
if (opts.selinux_label)
@@ -1096,7 +1095,7 @@ int main(int argc, char **argv)
if (opts.seccomp_filter)
do_seccomp_filter(opts.seccomp_filter);
- if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
+ if (prctl(PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L) == -1)
err(EXIT_FAILURE, _("keep process capabilities failed"));
/* We're going to want CAP_SETPCAP, CAP_SETUID, and CAP_SETGID if
@@ -1129,7 +1128,7 @@ int main(int argc, char **argv)
err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
}
- if (opts.have_securebits && prctl(PR_SET_SECUREBITS, opts.securebits, 0, 0, 0) != 0)
+ if (opts.have_securebits && prctl(PR_SET_SECUREBITS, opts.securebits, 0L, 0L, 0L) != 0)
err(SETPRIV_EXIT_PRIVERR, _("set process securebits failed"));
if (opts.bounding_set) {
@@ -1150,7 +1149,7 @@ int main(int argc, char **argv)
}
/* Clear or set parent death signal */
- if (opts.pdeathsig && prctl(PR_SET_PDEATHSIG, opts.pdeathsig < 0 ? 0 : opts.pdeathsig) != 0)
+ if (opts.pdeathsig && prctl(PR_SET_PDEATHSIG, opts.pdeathsig < 0 ? 0L : opts.pdeathsig) != 0)
err(SETPRIV_EXIT_PRIVERR, _("set parent death signal failed"));
if (opts.have_ptracer) {
diff --git a/tests/helpers/test_mkfds.c b/tests/helpers/test_mkfds.c
index 57f99e5a3..ee2d95da8 100644
--- a/tests/helpers/test_mkfds.c
+++ b/tests/helpers/test_mkfds.c
@@ -4413,7 +4413,7 @@ static void list_output_values(const char *factory_name)
static void rename_self(const char *comm)
{
- if (prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0) < 0)
+ if (prctl(PR_SET_NAME, (unsigned long)comm, 0L, 0L, 0L) < 0)
err(EXIT_FAILURE, "failed to rename self via prctl: %s", comm);
}
--
2.51.0
^ permalink raw reply related
* [PATCH v2 0/1] Call prctl(2) with signed long integers, and avoid casts
From: Alejandro Colomar @ 2025-12-03 20:50 UTC (permalink / raw)
To: util-linux; +Cc: Alejandro Colomar, Xi Ruoyao, Thomas Weißschuh, Karel Zak
In-Reply-To: <20240601093150.16912-1-alx@kernel.org>
Hi!
Karel reminded me of this old patch. Here's a revision of the patch.
Major changes in v2:
- Don't specify the 5 arguments unnecessarily.
BTW, I've developed a header file that might be useful for the general
public. See in a reply to this mail.
Have a lovely night!
Alex
Alejandro Colomar (1):
c4fc41abf Call prctl(2) with signed long integers, and avoid casts
lib/caputils.c | 6 +++---
lib/env.c | 4 ++--
misc-utils/enosys.c | 2 +-
schedutils/coresched.c | 6 +++---
sys-utils/setpriv-landlock.c | 2 +-
sys-utils/setpriv.c | 27 +++++++++++++--------------
tests/helpers/test_mkfds.c | 2 +-
7 files changed, 24 insertions(+), 25 deletions(-)
--
2.51.0
^ permalink raw reply
* [PATCH 1/1] copyfilerange: new command to call copy-file-range
From: Dick Marinus @ 2025-12-03 19:25 UTC (permalink / raw)
To: util-linux; +Cc: Dick Marinus
In-Reply-To: <20251203192558.1116470-1-dick@mrns.nl>
This command allows you to call the copy-file range system call which
performs an in-kernel copy between two files without the additional cost
of transferring data from the kernel to user space and then back into
the kernel.
It gives filesystems an opportunity to implement "copy acceleration"
techniques, such as the use of reflinks (i.e., two or more inodes that
share pointers to the same copy-on-write disk blocks) or
server-side-copy (in the case of NFS).
A purpose of this command is to in-place deduplicate equal file blocks
in two different files.
When calling this command the source and destination file are required
and ranges can be supplied using command line arguments or from a
commands file. The source and destination filename can be supplied using
the optional --source and --destination options.
A file range contains the offset in the source and destination file and
the length of the range in bytes. The offsets can be omitted so that the
current file pointer is used. When the size is omitted or set to zero
the remainder of the file is copied.
If the file range is too long to fit in SIZE_MAX subsequential calls to
copy_file_range will be performed to copy the whole range.
The following command will copy/reflink a file:
$ copyfilerange file1 file2 0::
The following command will copy the second block from file1 into file2:
$ copyfilerange file1 file2 4096:4096:4096
Signed-off-by: Dick Marinus <dick@mrns.nl>
---
.gitignore | 1 +
configure.ac | 3 +
meson.build | 14 ++
meson_options.txt | 2 +
misc-utils/Makemodule.am | 9 +
misc-utils/copyfilerange.1.adoc | 78 +++++++
misc-utils/copyfilerange.c | 226 +++++++++++++++++++++
misc-utils/meson.build | 5 +
tests/commands.sh | 1 +
tests/expected/copyfilerange/copyfilerange | 4 +
tests/ts/copyfilerange/copyfilerange | 40 ++++
11 files changed, 383 insertions(+)
create mode 100644 misc-utils/copyfilerange.1.adoc
create mode 100644 misc-utils/copyfilerange.c
create mode 100644 tests/expected/copyfilerange/copyfilerange
create mode 100755 tests/ts/copyfilerange/copyfilerange
diff --git a/.gitignore b/.gitignore
index 14d320cf3..06fb8ddc1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,6 +99,7 @@ ylwrap
/colcrt
/colrm
/column
+/copyfilerange
/coresched
/ctrlaltdel
/delpart
diff --git a/configure.ac b/configure.ac
index cf415f5ed..0975f8e50 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2650,6 +2650,9 @@ UL_REQUIRES_HAVE([write], [utmpx_h], [utmpx.h header])
UL_REQUIRES_HAVE([write], [gnu_utmpx], [GNU utmpx functions])
AM_CONDITIONAL([BUILD_WRITE], [test "x$build_write" = xyes])
+UL_BUILD_INIT([copyfilerange], [check])
+UL_REQUIRES_LINUX([copyfilerange])
+AM_CONDITIONAL([BUILD_COPYFILERANGE], [test "x$build_copyfilerange" = xyes])
AC_ARG_WITH([btrfs],
AS_HELP_STRING([--without-btrfs], [do not build with btrfs support]),
diff --git a/meson.build b/meson.build
index cac8bb578..e23804ef3 100644
--- a/meson.build
+++ b/meson.build
@@ -3076,6 +3076,20 @@ if opt and not is_disabler(exe)
exes += exe
endif
+opt = opt and 'copyfilerange' in static_programs
+exe = executable(
+ 'copyfilerange',
+ copyfilerange_sources,
+ include_directories : includes,
+ link_with : [lib_common],
+ dependencies : [copyfilerange_dep],
+ install_dir : sbindir,
+ install : opt,
+ build_by_default : opt)
+if opt and not is_disabler(exe)
+ exes += exe
+endif
+
exe = executable(
'sample-mkfs',
'libblkid/samples/mkfs.c',
diff --git a/meson_options.txt b/meson_options.txt
index 1ec904668..f023a4c27 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -259,6 +259,8 @@ option('build-hexdump', type : 'feature',
description : 'build hexdump')
option('build-findfs', type : 'feature',
description : 'build findfs')
+option('build-copyfilerange', type : 'feature',
+ description : 'build copyfilerange')
# static programs
diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am
index d0bc8d806..afa9e6eec 100644
--- a/misc-utils/Makemodule.am
+++ b/misc-utils/Makemodule.am
@@ -337,3 +337,12 @@ lsclocks_SOURCES = misc-utils/lsclocks.c
lsclocks_LDADD = $(LDADD) libcommon.la libsmartcols.la
lsclocks_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
endif
+
+if BUILD_COPYFILERANGE
+usrbin_exec_PROGRAMS += copyfilerange
+MANPAGES += misc-utils/copyfilerange.1
+dist_noinst_DATA += misc-utils/copyfilerange.1.adoc
+copyfilerange_SOURCES = misc-utils/copyfilerange.c
+copyfilerange_LDADD = $(LDADD) libcommon.la
+copyfilerange_CFLAGS = $(AM_CFLAGS)
+endif
diff --git a/misc-utils/copyfilerange.1.adoc b/misc-utils/copyfilerange.1.adoc
new file mode 100644
index 000000000..52a03ca09
--- /dev/null
+++ b/misc-utils/copyfilerange.1.adoc
@@ -0,0 +1,78 @@
+//po4a: entry man manual
+= copyfilerange(1)
+:doctype: manpage
+:man manual: User Commands
+:man source: util-linux {release-version}
+:page-layout: base
+:command: copyfilerange
+
+== NAME
+
+copyfilerange - Copy file ranges from source to destination file.
+
+== SYNOPSIS
+
+*copyfilerange* [options] [<source>] [<destination>] [<command>...]
+
+== DESCRIPTION
+
+*copyfilerange* copy file ranges from source to destination file
+*copyfilerange* is a simple utility to call the copy_file_range() system call.
+
+== OPTIONS
+
+*-s*, *--source*::
+Source filename
+
+*-d*, *--destination*::
+Destination filename
+
+*-c*, *--commands*::
+Commands filename
+
+*source*::
+Source filename
+
+*destination*::
+Destination filename
+
+*source_offset:dest_offset:length*::
+All values are in bytes, if length is set to 0 copy as much as available.
+Multiple commands can be supplied.
+
+When one or more of the offsets are omitted the operation will use the last used location, starting with 0
+
+include::man-common/help-version.adoc[]
+
+== EXIT STATUS
+
+*copyfilerange* has the following exit status values:
+
+*0*::
+success
+*1*::
+unspecified failure
+*2*::
+(some) range failed
+*3*::
+unspecified failure and (some) range failed
+
+== NOTES
+
+The copy_file_range() system call has some serious caveats, the source and destination files must use the same filesystem type and some virtual filesystems (like procfs) won't work. copy_file_range() will use reflinks when the filesystem supports this. To use reflinks the file range most often needs to align with the filesystem block size on both the source and destination file.
+
+== AUTHORS
+
+mailto:dick@mrns.nl[Dick Marinus]
+
+== SEE ALSO
+
+*copy_file_range*(2)
+
+include::man-common/bugreports.adoc[]
+
+include::man-common/footer.adoc[]
+
+ifdef::translation[]
+include::man-common/translation.adoc[]
+endif::[]
diff --git a/misc-utils/copyfilerange.c b/misc-utils/copyfilerange.c
new file mode 100644
index 000000000..d3e0a0521
--- /dev/null
+++ b/misc-utils/copyfilerange.c
@@ -0,0 +1,226 @@
+/*
+ * copyfilerange - utility to use the copy_file_range(2) system call
+ *
+ * Copyright (C) 2025 Dick Marinus <dick@mrns.nl>
+ *
+ * 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, see <https://gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+
+#include "c.h"
+#include "nls.h"
+#include "closestream.h"
+#include "xalloc.h"
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+ FILE *out = stdout;
+ fputs(USAGE_HEADER, out);
+ fprintf(out,
+ _(" %1$s [options] [<source>] [<destination>] [<command>...]\n"),
+ program_invocation_short_name);
+
+ fputs(USAGE_SEPARATOR, out);
+ fputsln(_("Copy file ranges from source to destination file."), out);
+
+ fputs(USAGE_OPTIONS, out);
+ fputsln(_(" --source, -s filename source filename"), out);
+ fputsln(_(" --destination, -d filename destination filename"), out);
+ fputsln(_(" --commands, -c filename read command(s) seperated by newlines from filename"), out);
+ fputsln(_(" source source filename"), out);
+ fputsln(_(" destination destination filename"), out);
+ fputsln(_(" command source_offset:dest_offset:length, all values are in bytes"), out);
+ fputsln(_(" if length is set to 0 as much as available will be copied"), out);
+ fputsln(_(" when the offset is omitted the last file position is used"), out);
+
+ fputs(USAGE_SEPARATOR, out);
+ fprintf(out, USAGE_HELP_OPTIONS(16));
+
+ fprintf(out, USAGE_MAN_TAIL("copyfilerange(1)"));
+ exit(EXIT_SUCCESS);
+}
+
+static int parse_range(const char *range_str, off_t *src_off, off_t *dst_off, size_t *len)
+{
+ char *copy = strdup(range_str);
+ if (!copy) return -1;
+
+ char *start;
+
+ start = copy;
+ char *token;
+ token = strchr(start, ':');
+ if (!token) goto fail;
+ *token = 0;
+ if (*start) *src_off = atoll(start);
+
+ start = token + 1;
+ token = strchr(start, ':');
+ if (!token) goto fail;
+ *token = 0;
+ if (*start) *dst_off = atoll(start);
+
+ start = token + 1;
+ if (*start) *len = atoll(start);
+ else *len = 0;
+
+ free(copy);
+ return 0;
+
+fail:
+ free(copy);
+ return -1;
+
+}
+
+static int handle_command(int fd_src, int fd_dst, off_t* src_off, off_t* dst_off, char* command)
+{
+ size_t len;
+ int rc = 0;
+ if (parse_range(command, src_off, dst_off, &len) != 0) {
+ fprintf(stderr, _("invalid range format: %s\n"), command);
+ return 1;
+ }
+
+ if (len == 0) {
+ off_t src_size = lseek(fd_src, 0, SEEK_END);
+ if (src_size == -1)
+ err(EXIT_FAILURE, _("cannot determine size of source file"));
+ len = src_size - *src_off;
+ }
+
+ size_t remaining = len;
+ while (remaining > 0) {
+ size_t chunk = remaining > SIZE_MAX ? SIZE_MAX : remaining;
+ ssize_t copied = copy_file_range(fd_src, src_off, fd_dst, dst_off, chunk, 0);
+ if (copied < 0) {
+ fprintf(stderr, _("failed copy file range %s at source offset %ld: %m\n"), command, *src_off);
+ rc |= 2;
+ break;
+ }
+ if (copied == 0) break;
+ remaining -= copied;
+ }
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+ char **command_files = NULL;
+ size_t ncommand_files = 0;
+ char *source_filename = NULL;
+ char *destination_filename = NULL;
+ int fd_src, fd_dst;
+ int rc = 0;
+
+ static const struct option longopts[] = {
+ { "commands", required_argument, NULL, 'c' },
+ { "source", required_argument, NULL, 's' },
+ { "destination", required_argument, NULL, 'd' },
+ { "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();
+
+ int c;
+ while ((c = getopt_long (argc, argv, "c:s:d:Vh", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'c':
+ if (!command_files)
+ command_files = xmalloc(sizeof(char *) * argc);
+ command_files[ncommand_files++] = xstrdup(optarg);
+ break;
+ case 's':
+ if (source_filename)
+ errx(EXIT_FAILURE, _("only one source file is allowed (%s already supplied)"), source_filename);
+ source_filename = xstrdup(optarg);
+ break;
+ case 'd':
+ if (destination_filename)
+ errx(EXIT_FAILURE, _("only one destination file is allowed (%s already supplied)"), destination_filename);
+ destination_filename = xstrdup(optarg);
+ break;
+ case 'V':
+ print_version(EXIT_SUCCESS);
+ case 'h':
+ usage();
+ }
+ }
+
+ int rem_optind;
+ for (rem_optind = optind; rem_optind < argc; rem_optind++) {
+ if (source_filename && destination_filename) break;
+ if (!source_filename)
+ source_filename = xstrdup(argv[rem_optind]);
+ else if (!destination_filename)
+ destination_filename = xstrdup(argv[rem_optind]);
+ }
+
+ if (!source_filename)
+ errx(EXIT_FAILURE, _("source file is required"));
+
+ if (!destination_filename)
+ errx(EXIT_FAILURE, _("destination file is required"));
+
+ if ((fd_src = open(source_filename, O_RDONLY)) < 0)
+ err(EXIT_FAILURE, _("cannot open source %s"), argv[1]);
+ free(source_filename);
+
+ if ((fd_dst = open(destination_filename, O_WRONLY | O_CREAT, 0666)) < 0)
+ err(EXIT_FAILURE, _("cannot open destination %s"), argv[2]);
+ free(destination_filename);
+
+ off_t src_off, dst_off;
+
+ for (size_t i = 0; i < ncommand_files; i++) {
+ FILE *f = NULL;
+
+ if (!(f = fopen(command_files[i], "r")))
+ err(EXIT_FAILURE, _("cannot open command file %s"), command_files[i]);
+ free(command_files[i]);
+
+ char *line = NULL;
+ size_t len = 0;
+
+ while (getline(&line, &len, f) != -1) {
+ rc |= handle_command(fd_src, fd_dst, &src_off, &dst_off, line);
+ }
+
+ free(line);
+ fclose(f);
+ }
+ free(command_files);
+
+ for (; rem_optind < argc; rem_optind++) {
+ rc |= handle_command(fd_src, fd_dst, &src_off, &dst_off, argv[rem_optind]);
+ }
+
+ close(fd_src);
+ close(fd_dst);
+ return rc;
+}
diff --git a/misc-utils/meson.build b/misc-utils/meson.build
index 1cd4713ce..50ec84ad8 100644
--- a/misc-utils/meson.build
+++ b/misc-utils/meson.build
@@ -229,3 +229,8 @@ lsclocks_sources = files(
'lsclocks.c',
)
lsclocks_manadocs = files('lsclocks.1.adoc')
+
+copyfilerange_sources = files(
+ 'copyfilerange.c',
+)
+copyfilerange_manadocs = files('copyfilerange.1.adoc')
diff --git a/tests/commands.sh b/tests/commands.sh
index 19f51529c..2e98cabdd 100644
--- a/tests/commands.sh
+++ b/tests/commands.sh
@@ -78,6 +78,7 @@ TS_CMD_COLCRT=${TS_CMD_COLCRT:-"${ts_commandsdir}colcrt"}
TS_CMD_COLRM=${TS_CMD_COLRM:-"${ts_commandsdir}colrm"}
TS_CMD_COL=${TS_CMD_COL:-"${ts_commandsdir}col"}
TS_CMD_COLUMN=${TS_CMD_COLUMN:-"${ts_commandsdir}column"}
+TS_CMD_COPYFILERANGE=${TS_CMD_COPYFILERANGE:-"${ts_commandsdir}copyfilerange"}
TS_CMD_CORESCHED=${TS_CMD_CORESCHED:-"${ts_commandsdir}coresched"}
TS_CMD_ENOSYS=${TS_CMD_ENOSYS-"${ts_commandsdir}enosys"}
TS_CMD_EJECT=${TS_CMD_EJECT-"${ts_commandsdir}eject"}
diff --git a/tests/expected/copyfilerange/copyfilerange b/tests/expected/copyfilerange/copyfilerange
new file mode 100644
index 000000000..240327782
--- /dev/null
+++ b/tests/expected/copyfilerange/copyfilerange
@@ -0,0 +1,4 @@
+float
+
+float
+aloof
diff --git a/tests/ts/copyfilerange/copyfilerange b/tests/ts/copyfilerange/copyfilerange
new file mode 100755
index 000000000..c81a55413
--- /dev/null
+++ b/tests/ts/copyfilerange/copyfilerange
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# Copyright (C) 2025 Dick Marinus <dick@mrns.nl>
+#
+# This file is part of util-linux.
+#
+# 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.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="copyfilerange"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_COPYFILERANGE"
+
+ts_cd "$TS_OUTDIR"
+
+{
+ echo float > a
+ echo > b
+
+ cat a # float
+ cat b # empty
+
+ "$TS_CMD_COPYFILERANGE" a b 3::1 1::2 2::1 0::1 5::1
+
+ cat a # float
+ cat b # aloof, tribe to Donald Knuth five letter words
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
--
2.51.1
^ permalink raw reply related
* [PATCH 0/1] copyfilerange: new command to call copy-file-range
From: Dick Marinus @ 2025-12-03 19:25 UTC (permalink / raw)
To: util-linux; +Cc: Dick Marinus
In-Reply-To: <20251202201500.1029349-1-dick@mrns.nl>
Hello!
Sorry for the repost, I noticed my previous mail wasn't properly signed
and was probably blocked as spam.
I finally finished my work on a command to create reflinked files. Since
my last post on this mailing list I found the copy_file_range system
call and I named this command after it.
I decided to contribute this command first, when this is done I will
post another command to find duplicate blocks in two files, which can
serve as input of this command.
This command should be usable for other use cases as well, it's also
possible to create sparse files and it can be used instead of how many
people use dd if= of= skip= count=
I tried to implement everything in a similar way as used by the other
sources in this project (and I learned a lot from it).
Nothing is set in stone although I want to keep to the Unix philosophy
and not any wild features to this command.
Please let me know what can (or must) be added or improved.
Dick Marinus (1):
copyfilerange: new command to call copy-file-range
.gitignore | 1 +
configure.ac | 3 +
meson.build | 14 ++
meson_options.txt | 2 +
misc-utils/Makemodule.am | 9 +
misc-utils/copyfilerange.1.adoc | 78 +++++++
misc-utils/copyfilerange.c | 226 +++++++++++++++++++++
misc-utils/meson.build | 5 +
tests/commands.sh | 1 +
tests/expected/copyfilerange/copyfilerange | 4 +
tests/ts/copyfilerange/copyfilerange | 40 ++++
11 files changed, 383 insertions(+)
create mode 100644 misc-utils/copyfilerange.1.adoc
create mode 100644 misc-utils/copyfilerange.c
create mode 100644 tests/expected/copyfilerange/copyfilerange
create mode 100755 tests/ts/copyfilerange/copyfilerange
--
2.51.1
^ permalink raw reply
* [PATCH 0/1] copyfilerange: new command to call copy-file-range
From: Dick Marinus @ 2025-12-02 20:14 UTC (permalink / raw)
To: util-linux; +Cc: Dick Marinus
Hello!
I finally finished my work on a command to create reflinked files. Since
my last post on this mailing list I found the copy_file_range system
call and I named this command after it.
I decided to contribute this command first, when this is done I will
post another command to find duplicate blocks in two files, which can
serve as input of this command.
This command should be usable for other use cases as well, it's also
possible to create sparse files and it can be used instead of how many
people use dd if= of= skip= count=
I tried to implement everything in a similar way as used by the other
sources in this project (and I learned a lot from it).
Nothing is set in stone although I want to keep to the Unix philosophy
and not any wild features to this command.
Please let me know what can (or must) be added or improved.
Dick Marinus (1):
copyfilerange: new command to call copy-file-range
.gitignore | 1 +
configure.ac | 3 +
meson.build | 14 ++
meson_options.txt | 2 +
misc-utils/Makemodule.am | 9 +
misc-utils/copyfilerange.1.adoc | 78 +++++++
misc-utils/copyfilerange.c | 226 +++++++++++++++++++++
misc-utils/meson.build | 5 +
tests/commands.sh | 1 +
tests/expected/copyfilerange/copyfilerange | 4 +
tests/ts/copyfilerange/copyfilerange | 40 ++++
11 files changed, 383 insertions(+)
create mode 100644 misc-utils/copyfilerange.1.adoc
create mode 100644 misc-utils/copyfilerange.c
create mode 100644 tests/expected/copyfilerange/copyfilerange
create mode 100755 tests/ts/copyfilerange/copyfilerange
--
2.51.1
^ permalink raw reply
* [PATCH 1/1] copyfilerange: new command to call copy-file-range
From: Dick Marinus @ 2025-12-02 20:14 UTC (permalink / raw)
To: util-linux; +Cc: Dick Marinus
In-Reply-To: <20251202201500.1029349-1-dick@mrns.nl>
This command allows you to call the copy-file range system call which
performs an in-kernel copy between two files without the additional cost
of transferring data from the kernel to user space and then back into
the kernel.
It gives filesystems an opportunity to implement "copy acceleration"
techniques, such as the use of reflinks (i.e., two or more inodes that
share pointers to the same copy-on-write disk blocks) or
server-side-copy (in the case of NFS).
A purpose of this command is to in-place deduplicate equal file blocks
in two different files.
When calling this command the source and destination file are required
and ranges can be supplied using command line arguments or from a
commands file. The source and destination filename can be supplied using
the optional --source and --destination options.
A file range contains the offset in the source and destination file and
the length of the range in bytes. The offsets can be omitted so that the
current file pointer is used. When the size is omitted or set to zero
the remainder of the file is copied.
If the file range is too long to fit in SIZE_MAX subsequential calls to
copy_file_range will be performed to copy the whole range.
The following command will copy/reflink a file:
$ copyfilerange file1 file2 0::
The following command will copy the second block from file1 into file2:
$ copyfilerange file1 file2 4096:4096:4096
Signed-off-by: Dick Marinus <dick@mrns.nl>
---
.gitignore | 1 +
configure.ac | 3 +
meson.build | 14 ++
meson_options.txt | 2 +
misc-utils/Makemodule.am | 9 +
misc-utils/copyfilerange.1.adoc | 78 +++++++
misc-utils/copyfilerange.c | 226 +++++++++++++++++++++
misc-utils/meson.build | 5 +
tests/commands.sh | 1 +
tests/expected/copyfilerange/copyfilerange | 4 +
tests/ts/copyfilerange/copyfilerange | 40 ++++
11 files changed, 383 insertions(+)
create mode 100644 misc-utils/copyfilerange.1.adoc
create mode 100644 misc-utils/copyfilerange.c
create mode 100644 tests/expected/copyfilerange/copyfilerange
create mode 100755 tests/ts/copyfilerange/copyfilerange
diff --git a/.gitignore b/.gitignore
index 14d320cf3..06fb8ddc1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,6 +99,7 @@ ylwrap
/colcrt
/colrm
/column
+/copyfilerange
/coresched
/ctrlaltdel
/delpart
diff --git a/configure.ac b/configure.ac
index cf415f5ed..0975f8e50 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2650,6 +2650,9 @@ UL_REQUIRES_HAVE([write], [utmpx_h], [utmpx.h header])
UL_REQUIRES_HAVE([write], [gnu_utmpx], [GNU utmpx functions])
AM_CONDITIONAL([BUILD_WRITE], [test "x$build_write" = xyes])
+UL_BUILD_INIT([copyfilerange], [check])
+UL_REQUIRES_LINUX([copyfilerange])
+AM_CONDITIONAL([BUILD_COPYFILERANGE], [test "x$build_copyfilerange" = xyes])
AC_ARG_WITH([btrfs],
AS_HELP_STRING([--without-btrfs], [do not build with btrfs support]),
diff --git a/meson.build b/meson.build
index cac8bb578..e23804ef3 100644
--- a/meson.build
+++ b/meson.build
@@ -3076,6 +3076,20 @@ if opt and not is_disabler(exe)
exes += exe
endif
+opt = opt and 'copyfilerange' in static_programs
+exe = executable(
+ 'copyfilerange',
+ copyfilerange_sources,
+ include_directories : includes,
+ link_with : [lib_common],
+ dependencies : [copyfilerange_dep],
+ install_dir : sbindir,
+ install : opt,
+ build_by_default : opt)
+if opt and not is_disabler(exe)
+ exes += exe
+endif
+
exe = executable(
'sample-mkfs',
'libblkid/samples/mkfs.c',
diff --git a/meson_options.txt b/meson_options.txt
index 1ec904668..f023a4c27 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -259,6 +259,8 @@ option('build-hexdump', type : 'feature',
description : 'build hexdump')
option('build-findfs', type : 'feature',
description : 'build findfs')
+option('build-copyfilerange', type : 'feature',
+ description : 'build copyfilerange')
# static programs
diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am
index d0bc8d806..afa9e6eec 100644
--- a/misc-utils/Makemodule.am
+++ b/misc-utils/Makemodule.am
@@ -337,3 +337,12 @@ lsclocks_SOURCES = misc-utils/lsclocks.c
lsclocks_LDADD = $(LDADD) libcommon.la libsmartcols.la
lsclocks_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
endif
+
+if BUILD_COPYFILERANGE
+usrbin_exec_PROGRAMS += copyfilerange
+MANPAGES += misc-utils/copyfilerange.1
+dist_noinst_DATA += misc-utils/copyfilerange.1.adoc
+copyfilerange_SOURCES = misc-utils/copyfilerange.c
+copyfilerange_LDADD = $(LDADD) libcommon.la
+copyfilerange_CFLAGS = $(AM_CFLAGS)
+endif
diff --git a/misc-utils/copyfilerange.1.adoc b/misc-utils/copyfilerange.1.adoc
new file mode 100644
index 000000000..52a03ca09
--- /dev/null
+++ b/misc-utils/copyfilerange.1.adoc
@@ -0,0 +1,78 @@
+//po4a: entry man manual
+= copyfilerange(1)
+:doctype: manpage
+:man manual: User Commands
+:man source: util-linux {release-version}
+:page-layout: base
+:command: copyfilerange
+
+== NAME
+
+copyfilerange - Copy file ranges from source to destination file.
+
+== SYNOPSIS
+
+*copyfilerange* [options] [<source>] [<destination>] [<command>...]
+
+== DESCRIPTION
+
+*copyfilerange* copy file ranges from source to destination file
+*copyfilerange* is a simple utility to call the copy_file_range() system call.
+
+== OPTIONS
+
+*-s*, *--source*::
+Source filename
+
+*-d*, *--destination*::
+Destination filename
+
+*-c*, *--commands*::
+Commands filename
+
+*source*::
+Source filename
+
+*destination*::
+Destination filename
+
+*source_offset:dest_offset:length*::
+All values are in bytes, if length is set to 0 copy as much as available.
+Multiple commands can be supplied.
+
+When one or more of the offsets are omitted the operation will use the last used location, starting with 0
+
+include::man-common/help-version.adoc[]
+
+== EXIT STATUS
+
+*copyfilerange* has the following exit status values:
+
+*0*::
+success
+*1*::
+unspecified failure
+*2*::
+(some) range failed
+*3*::
+unspecified failure and (some) range failed
+
+== NOTES
+
+The copy_file_range() system call has some serious caveats, the source and destination files must use the same filesystem type and some virtual filesystems (like procfs) won't work. copy_file_range() will use reflinks when the filesystem supports this. To use reflinks the file range most often needs to align with the filesystem block size on both the source and destination file.
+
+== AUTHORS
+
+mailto:dick@mrns.nl[Dick Marinus]
+
+== SEE ALSO
+
+*copy_file_range*(2)
+
+include::man-common/bugreports.adoc[]
+
+include::man-common/footer.adoc[]
+
+ifdef::translation[]
+include::man-common/translation.adoc[]
+endif::[]
diff --git a/misc-utils/copyfilerange.c b/misc-utils/copyfilerange.c
new file mode 100644
index 000000000..d3e0a0521
--- /dev/null
+++ b/misc-utils/copyfilerange.c
@@ -0,0 +1,226 @@
+/*
+ * copyfilerange - utility to use the copy_file_range(2) system call
+ *
+ * Copyright (C) 2025 Dick Marinus <dick@mrns.nl>
+ *
+ * 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, see <https://gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+
+#include "c.h"
+#include "nls.h"
+#include "closestream.h"
+#include "xalloc.h"
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+ FILE *out = stdout;
+ fputs(USAGE_HEADER, out);
+ fprintf(out,
+ _(" %1$s [options] [<source>] [<destination>] [<command>...]\n"),
+ program_invocation_short_name);
+
+ fputs(USAGE_SEPARATOR, out);
+ fputsln(_("Copy file ranges from source to destination file."), out);
+
+ fputs(USAGE_OPTIONS, out);
+ fputsln(_(" --source, -s filename source filename"), out);
+ fputsln(_(" --destination, -d filename destination filename"), out);
+ fputsln(_(" --commands, -c filename read command(s) seperated by newlines from filename"), out);
+ fputsln(_(" source source filename"), out);
+ fputsln(_(" destination destination filename"), out);
+ fputsln(_(" command source_offset:dest_offset:length, all values are in bytes"), out);
+ fputsln(_(" if length is set to 0 as much as available will be copied"), out);
+ fputsln(_(" when the offset is omitted the last file position is used"), out);
+
+ fputs(USAGE_SEPARATOR, out);
+ fprintf(out, USAGE_HELP_OPTIONS(16));
+
+ fprintf(out, USAGE_MAN_TAIL("copyfilerange(1)"));
+ exit(EXIT_SUCCESS);
+}
+
+static int parse_range(const char *range_str, off_t *src_off, off_t *dst_off, size_t *len)
+{
+ char *copy = strdup(range_str);
+ if (!copy) return -1;
+
+ char *start;
+
+ start = copy;
+ char *token;
+ token = strchr(start, ':');
+ if (!token) goto fail;
+ *token = 0;
+ if (*start) *src_off = atoll(start);
+
+ start = token + 1;
+ token = strchr(start, ':');
+ if (!token) goto fail;
+ *token = 0;
+ if (*start) *dst_off = atoll(start);
+
+ start = token + 1;
+ if (*start) *len = atoll(start);
+ else *len = 0;
+
+ free(copy);
+ return 0;
+
+fail:
+ free(copy);
+ return -1;
+
+}
+
+static int handle_command(int fd_src, int fd_dst, off_t* src_off, off_t* dst_off, char* command)
+{
+ size_t len;
+ int rc = 0;
+ if (parse_range(command, src_off, dst_off, &len) != 0) {
+ fprintf(stderr, _("invalid range format: %s\n"), command);
+ return 1;
+ }
+
+ if (len == 0) {
+ off_t src_size = lseek(fd_src, 0, SEEK_END);
+ if (src_size == -1)
+ err(EXIT_FAILURE, _("cannot determine size of source file"));
+ len = src_size - *src_off;
+ }
+
+ size_t remaining = len;
+ while (remaining > 0) {
+ size_t chunk = remaining > SIZE_MAX ? SIZE_MAX : remaining;
+ ssize_t copied = copy_file_range(fd_src, src_off, fd_dst, dst_off, chunk, 0);
+ if (copied < 0) {
+ fprintf(stderr, _("failed copy file range %s at source offset %ld: %m\n"), command, *src_off);
+ rc |= 2;
+ break;
+ }
+ if (copied == 0) break;
+ remaining -= copied;
+ }
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+ char **command_files = NULL;
+ size_t ncommand_files = 0;
+ char *source_filename = NULL;
+ char *destination_filename = NULL;
+ int fd_src, fd_dst;
+ int rc = 0;
+
+ static const struct option longopts[] = {
+ { "commands", required_argument, NULL, 'c' },
+ { "source", required_argument, NULL, 's' },
+ { "destination", required_argument, NULL, 'd' },
+ { "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();
+
+ int c;
+ while ((c = getopt_long (argc, argv, "c:s:d:Vh", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'c':
+ if (!command_files)
+ command_files = xmalloc(sizeof(char *) * argc);
+ command_files[ncommand_files++] = xstrdup(optarg);
+ break;
+ case 's':
+ if (source_filename)
+ errx(EXIT_FAILURE, _("only one source file is allowed (%s already supplied)"), source_filename);
+ source_filename = xstrdup(optarg);
+ break;
+ case 'd':
+ if (destination_filename)
+ errx(EXIT_FAILURE, _("only one destination file is allowed (%s already supplied)"), destination_filename);
+ destination_filename = xstrdup(optarg);
+ break;
+ case 'V':
+ print_version(EXIT_SUCCESS);
+ case 'h':
+ usage();
+ }
+ }
+
+ int rem_optind;
+ for (rem_optind = optind; rem_optind < argc; rem_optind++) {
+ if (source_filename && destination_filename) break;
+ if (!source_filename)
+ source_filename = xstrdup(argv[rem_optind]);
+ else if (!destination_filename)
+ destination_filename = xstrdup(argv[rem_optind]);
+ }
+
+ if (!source_filename)
+ errx(EXIT_FAILURE, _("source file is required"));
+
+ if (!destination_filename)
+ errx(EXIT_FAILURE, _("destination file is required"));
+
+ if ((fd_src = open(source_filename, O_RDONLY)) < 0)
+ err(EXIT_FAILURE, _("cannot open source %s"), argv[1]);
+ free(source_filename);
+
+ if ((fd_dst = open(destination_filename, O_WRONLY | O_CREAT, 0666)) < 0)
+ err(EXIT_FAILURE, _("cannot open destination %s"), argv[2]);
+ free(destination_filename);
+
+ off_t src_off, dst_off;
+
+ for (size_t i = 0; i < ncommand_files; i++) {
+ FILE *f = NULL;
+
+ if (!(f = fopen(command_files[i], "r")))
+ err(EXIT_FAILURE, _("cannot open command file %s"), command_files[i]);
+ free(command_files[i]);
+
+ char *line = NULL;
+ size_t len = 0;
+
+ while (getline(&line, &len, f) != -1) {
+ rc |= handle_command(fd_src, fd_dst, &src_off, &dst_off, line);
+ }
+
+ free(line);
+ fclose(f);
+ }
+ free(command_files);
+
+ for (; rem_optind < argc; rem_optind++) {
+ rc |= handle_command(fd_src, fd_dst, &src_off, &dst_off, argv[rem_optind]);
+ }
+
+ close(fd_src);
+ close(fd_dst);
+ return rc;
+}
diff --git a/misc-utils/meson.build b/misc-utils/meson.build
index 1cd4713ce..50ec84ad8 100644
--- a/misc-utils/meson.build
+++ b/misc-utils/meson.build
@@ -229,3 +229,8 @@ lsclocks_sources = files(
'lsclocks.c',
)
lsclocks_manadocs = files('lsclocks.1.adoc')
+
+copyfilerange_sources = files(
+ 'copyfilerange.c',
+)
+copyfilerange_manadocs = files('copyfilerange.1.adoc')
diff --git a/tests/commands.sh b/tests/commands.sh
index 19f51529c..2e98cabdd 100644
--- a/tests/commands.sh
+++ b/tests/commands.sh
@@ -78,6 +78,7 @@ TS_CMD_COLCRT=${TS_CMD_COLCRT:-"${ts_commandsdir}colcrt"}
TS_CMD_COLRM=${TS_CMD_COLRM:-"${ts_commandsdir}colrm"}
TS_CMD_COL=${TS_CMD_COL:-"${ts_commandsdir}col"}
TS_CMD_COLUMN=${TS_CMD_COLUMN:-"${ts_commandsdir}column"}
+TS_CMD_COPYFILERANGE=${TS_CMD_COPYFILERANGE:-"${ts_commandsdir}copyfilerange"}
TS_CMD_CORESCHED=${TS_CMD_CORESCHED:-"${ts_commandsdir}coresched"}
TS_CMD_ENOSYS=${TS_CMD_ENOSYS-"${ts_commandsdir}enosys"}
TS_CMD_EJECT=${TS_CMD_EJECT-"${ts_commandsdir}eject"}
diff --git a/tests/expected/copyfilerange/copyfilerange b/tests/expected/copyfilerange/copyfilerange
new file mode 100644
index 000000000..240327782
--- /dev/null
+++ b/tests/expected/copyfilerange/copyfilerange
@@ -0,0 +1,4 @@
+float
+
+float
+aloof
diff --git a/tests/ts/copyfilerange/copyfilerange b/tests/ts/copyfilerange/copyfilerange
new file mode 100755
index 000000000..c81a55413
--- /dev/null
+++ b/tests/ts/copyfilerange/copyfilerange
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# Copyright (C) 2025 Dick Marinus <dick@mrns.nl>
+#
+# This file is part of util-linux.
+#
+# 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.
+#
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="copyfilerange"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_COPYFILERANGE"
+
+ts_cd "$TS_OUTDIR"
+
+{
+ echo float > a
+ echo > b
+
+ cat a # float
+ cat b # empty
+
+ "$TS_CMD_COPYFILERANGE" a b 3::1 1::2 2::1 0::1 5::1
+
+ cat a # float
+ cat b # aloof, tribe to Donald Knuth five letter words
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize
--
2.51.1
^ permalink raw reply related
* Re: [PATCH 0/3] Consistent shell resolution across util-linux
From: Alessandro Ratti @ 2025-11-26 12:40 UTC (permalink / raw)
To: Karel Zak; +Cc: util-linux, thomas, Alessandro Ratti
In-Reply-To: <wrmeywniicltshcczypjo7or6hnds7wkkgaaiizbsvvzkwaab6@minsmj74e6wm>
On Wed, 26 Nov 2025 at 12:51, Karel Zak <kzak@redhat.com> wrote:
>
>
> Hi Alessandro,
>
> thanks!
>
> On Sun, Nov 23, 2025 at 04:32:43PM +0100, Alessandro Ratti wrote:
> > This patch series addresses inconsistent default shell handling across
> > util-linux tools, which caused user-reported data loss when script(1)
> > defaulted to /bin/sh without respecting the user's configured shell.
> >
> > The series:
> > 1. Introduces ul_default_shell() for consistent shell resolution
> > 2. Updates interactive tools to use the new function
> > 3. Standardizes _PATH_BSHELL usage in security-sensitive tools
> >
> > This implements the solution discussed in:
> > https://github.com/util-linux/util-linux/issues/3865
>
> How about creating a pull request on GitHub? It will help us with the
> review, etc.
Thanks. I opened a PR on GitHub [1] as you suggested.
I’d be grateful for any feedback or pointers on the review.
Thank you for your time and consideration.
Best regards
Alessandro
[1]: https://github.com/util-linux/util-linux/pull/3876
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox