if BUILD_COLUMN
dist_bashcompletion_DATA += bash-completion/column
endif
+if BUILD_EXCH
+dist_bashcompletion_DATA += bash-completion/exch
+endif
if BUILD_FINCORE
dist_bashcompletion_DATA += bash-completion/fincore
endif
--- /dev/null
+_exch_module()
+{
+ local cur prev OPTS
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ case $prev in
+ '-h'|'--help'|'-V'|'--version')
+ return 0
+ ;;
+ esac
+ case $cur in
+ -*)
+ OPTS='
+ --help
+ --version'
+ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
+ return 0
+ ;;
+ esac
+ local IFS=$'\n'
+ compopt -o filenames
+ COMPREPLY=( $(compgen -f -- $cur) )
+ return 0
+}
+complete -F _exch_module exch
prctl \
qsort_r \
reallocarray \
+ renameat2 \
rpmatch \
scandirat \
sched_setattr \
UL_CHECK_SYSCALL([pidfd_send_signal])
UL_CHECK_SYSCALL([close_range])
+have_renameat2_syscall="yes"
+UL_CHECK_SYSCALL([renameat2])
+AS_IF([test "x$ul_cv_syscall_renameat2" = xno], [
+ have_renameat2_syscall="no"
+])
+
UL_CHECK_SYSCALL([fsconfig])
UL_CHECK_SYSCALL([fsmount])
UL_CHECK_SYSCALL([fsopen])
UL_REQUIRES_HAVE([ctrlaltdel], [reboot], [reboot function])
AM_CONDITIONAL([BUILD_CTRLALTDEL], [test "x$build_ctrlaltdel" = xyes])
+enable_exch=$have_renameat2_syscall
+UL_BUILD_INIT([exch])
+UL_REQUIRES_LINUX([exch])
+AM_CONDITIONAL([BUILD_EXCH], [test "x$build_exch" = xyes])
+
UL_BUILD_INIT([fincore], [check])
UL_REQUIRES_LINUX([fincore])
UL_REQUIRES_BUILD([fincore], [libsmartcols])
prctl
qsort_r
reallocarray
+ renameat2
rpmatch
scandirat
setprogname
bashcompletions += ['lsclocks']
endif
+if conf.get('HAVE_RENAMEAT2').to_string() == '1'
+exe = executable(
+ 'exch',
+ exch_sources,
+ include_directories : includes,
+ link_with : [lib_common],
+ install_dir : usrbin_exec_dir,
+ install : true)
+if not is_disabler(exe)
+ exes += exe
+ manadocs += ['misc-utils/exch.1.adoc']
+ bashcompletions += ['exch']
+endif
+endif
+
############################################################
opt = not get_option('build-schedutils').disabled()
misc-utils/getopt-example.tcsh
endif
+if BUILD_EXCH
+usrbin_exec_PROGRAMS += exch
+MANPAGES += misc-utils/exch.1
+dist_noinst_DATA += misc-utils/exch.1.adoc
+exch_SOURCES = misc-utils/exch.c
+exch_LDADD = $(LDADD) libcommon.la
+exch_CFLAGS = $(AM_CFLAGS)
+endif
+
if BUILD_FINCORE
usrbin_exec_PROGRAMS += fincore
MANPAGES += misc-utils/fincore.1
--- /dev/null
+//po4a: entry man manual
+= exch(1)
+:doctype: manpage
+:man manual: User Commands
+:man source: util-linux {release-version}
+:page-layout: base
+:command: exch
+
+== NAME
+
+exch - a command line interface for RENAME_EXCHANGE of renameat2(2)
+
+== SYNOPSIS
+
+*exch* _oldpath_ _newpath_
+
+== DESCRIPTION
+
+*exch* atomically exchanges oldpath and newpath.
+*exch* is a simple command wrapping *RENAME_EXCHANGE* of *renameat2*
+system call.
+
+
+== OPTIONS
+
+include::man-common/help-version.adoc[]
+
+== EXIT STATUS
+
+*exch* has the following exit status values:
+
+*0*::
+success
+*1*::
+unspecified failure
+
+== AUTHORS
+
+mailto:yamato@redhat.com[Masatake YAMATO]
+
+== SEE ALSO
+
+*renameat2*(2)
+
+include::man-common/bugreports.adoc[]
+
+include::man-common/footer.adoc[]
+
+ifdef::translation[]
+include::man-common/translation.adoc[]
+endif::[]
--- /dev/null
+/*
+ * exch(1) - a command line interface for RENAME_EXCHANGE of renameat2(2).
+ *
+ * Copyright (C) 2023 Red Hat, Inc. All rights reserved.
+ * Written by Masatake YAMATO <yamato@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "c.h"
+#include "nls.h"
+
+#include <fcntl.h>
+#include <getopt.h>
+
+#ifndef HAVE_RENAMEAT2
+
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#ifndef RENAME_EXCHANGE
+#define RENAME_EXCHANGE (1 << 1)
+#endif
+
+static inline int renameat2(int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath, unsigned int flags)
+{
+ return syscall (SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags);
+}
+
+#endif
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+ FILE *out = stdout;
+
+ fputs(USAGE_HEADER, out);
+ fprintf(out, _(" %s [options] oldpath newpath\n"), program_invocation_short_name);
+
+ fputs(USAGE_OPTIONS, out);
+ fprintf(out, USAGE_HELP_OPTIONS(30));
+
+ fprintf(out, USAGE_MAN_TAIL("exch(1)"));
+
+ exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int rc;
+
+ static const struct option longopts[] = {
+ { "version", no_argument, NULL, 'V' },
+ { "help", no_argument, NULL, 'h' },
+ };
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ while ((c = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'V':
+ print_version(EXIT_SUCCESS);
+ case 'h':
+ usage();
+ default:
+ errtryhelp(EXIT_FAILURE);
+ }
+ }
+
+ if (argc - optind < 2) {
+ warnx(_("too few arguments"));
+ errtryhelp(EXIT_FAILURE);
+ } else if (argc - optind > 2) {
+ warnx(_("too many arguments"));
+ errtryhelp(EXIT_FAILURE);
+ }
+
+ rc = renameat2(AT_FDCWD, argv[optind],
+ AT_FDCWD, argv[optind + 1], RENAME_EXCHANGE);
+ if (rc)
+ warn(_("failed to exchange \"%s\" and \"%s\""),
+ argv[optind], argv[optind + 1]);
+
+ return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
install_dir : docdir,
install_mode: 'rwxr-xr-x')
+exch_sources = files(
+ 'exch.c',
+)
+
fincore_sources = files(
'fincore.c',
)
TS_CMD_COLUMN=${TS_CMD_COLUMN:-"${ts_commandsdir}column"}
TS_CMD_ENOSYS=${TS_CMD_ENOSYS-"${ts_commandsdir}enosys"}
TS_CMD_EJECT=${TS_CMD_EJECT-"${ts_commandsdir}eject"}
+TS_CMD_EXCH=${TS_CMD_EXCH-"${ts_commandsdir}exch"}
TS_CMD_FALLOCATE=${TS_CMD_FALLOCATE-"${ts_commandsdir}fallocate"}
TS_CMD_FDISK=${TS_CMD_FDISK-"${ts_commandsdir}fdisk"}
TS_CMD_FLOCK=${TS_CMD_FLOCK-"${ts_commandsdir}flock"}
--- /dev/null
+A
+B
+B
+A
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2023 Masatake YAMATO <yamato@redhat.com>
+#
+# 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="exch"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_EXCH"
+
+ts_cd "$TS_OUTDIR"
+
+{
+ echo A > a
+ echo B > b
+
+ cat a
+ cat b
+
+ "$TS_CMD_EXCH" a b
+
+ cat a
+ cat b
+} > "$TS_OUTPUT" 2>&1
+
+ts_finalize