]>
Commit | Line | Data |
---|---|---|
cd094a05 | 1 | /* |
8380ce72 | 2 | * SPDX-License-Identifier: GPL-2.0-or-later |
cd094a05 MY |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
8380ce72 KZ |
9 | * Copyright (C) 2023 Red Hat, Inc. All rights reserved. |
10 | * Written by Masatake YAMATO <yamato@redhat.com> | |
cd094a05 | 11 | * |
8380ce72 | 12 | * exch(1) - a command line interface for RENAME_EXCHANGE of renameat2(2). |
cd094a05 | 13 | */ |
cd094a05 MY |
14 | #include "c.h" |
15 | #include "nls.h" | |
16 | ||
17 | #include <fcntl.h> | |
18 | #include <getopt.h> | |
19 | ||
20 | #ifndef HAVE_RENAMEAT2 | |
8380ce72 KZ |
21 | # include <sys/syscall.h> |
22 | # include <unistd.h> | |
23 | #endif | |
cd094a05 MY |
24 | |
25 | #ifndef RENAME_EXCHANGE | |
8380ce72 | 26 | # define RENAME_EXCHANGE (1 << 1) |
cd094a05 MY |
27 | #endif |
28 | ||
8a7c8803 | 29 | #if !defined(HAVE_RENAMEAT2) && defined(SYS_renameat2) |
cd094a05 MY |
30 | static inline int renameat2(int olddirfd, const char *oldpath, |
31 | int newdirfd, const char *newpath, unsigned int flags) | |
32 | { | |
33 | return syscall (SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags); | |
34 | } | |
cd094a05 MY |
35 | #endif |
36 | ||
37 | static void __attribute__((__noreturn__)) usage(void) | |
38 | { | |
39 | FILE *out = stdout; | |
40 | ||
41 | fputs(USAGE_HEADER, out); | |
42 | fprintf(out, _(" %s [options] oldpath newpath\n"), program_invocation_short_name); | |
8380ce72 KZ |
43 | fputs(USAGE_SEPARATOR, out); |
44 | fputs(_("Atomically exchanges paths between two files.\n"), out); | |
cd094a05 MY |
45 | |
46 | fputs(USAGE_OPTIONS, out); | |
47 | fprintf(out, USAGE_HELP_OPTIONS(30)); | |
48 | ||
49 | fprintf(out, USAGE_MAN_TAIL("exch(1)")); | |
50 | ||
51 | exit(EXIT_SUCCESS); | |
52 | } | |
53 | ||
54 | int main(int argc, char **argv) | |
55 | { | |
56 | int c; | |
57 | int rc; | |
58 | ||
59 | static const struct option longopts[] = { | |
60 | { "version", no_argument, NULL, 'V' }, | |
61 | { "help", no_argument, NULL, 'h' }, | |
75f4d809 | 62 | { NULL } |
cd094a05 MY |
63 | }; |
64 | ||
65 | setlocale(LC_ALL, ""); | |
66 | bindtextdomain(PACKAGE, LOCALEDIR); | |
67 | textdomain(PACKAGE); | |
68 | ||
69 | while ((c = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1) { | |
70 | switch (c) { | |
71 | case 'V': | |
72 | print_version(EXIT_SUCCESS); | |
73 | case 'h': | |
74 | usage(); | |
75 | default: | |
76 | errtryhelp(EXIT_FAILURE); | |
77 | } | |
78 | } | |
79 | ||
80 | if (argc - optind < 2) { | |
81 | warnx(_("too few arguments")); | |
82 | errtryhelp(EXIT_FAILURE); | |
83 | } else if (argc - optind > 2) { | |
84 | warnx(_("too many arguments")); | |
85 | errtryhelp(EXIT_FAILURE); | |
86 | } | |
87 | ||
88 | rc = renameat2(AT_FDCWD, argv[optind], | |
89 | AT_FDCWD, argv[optind + 1], RENAME_EXCHANGE); | |
90 | if (rc) | |
91 | warn(_("failed to exchange \"%s\" and \"%s\""), | |
92 | argv[optind], argv[optind + 1]); | |
93 | ||
94 | return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; | |
95 | } |