fstests: Add an auxiliary program to create an AF_UNIX socket
[xfstests-dev.git] / src / renameat2.c
1 /*
2  * Copyright (c) 2014, Miklos Szeredi <mszeredi@suse.cz>
3  * This file is published under GPL2+.
4  *
5  * This is a trivial wrapper around the renameat2 syscall.
6  */
7
8 #include "global.h"
9
10 #ifndef HAVE_RENAMEAT2
11 #include <sys/syscall.h>
12
13 #if !defined(SYS_renameat2) && defined(__x86_64__)
14 #define SYS_renameat2 316
15 #endif
16
17 #if !defined(SYS_renameat2) && defined(__i386__)
18 #define SYS_renameat2 353
19 #endif
20
21 #if !defined(SYS_renameat2) && defined(__i386__)
22 #define SYS_renameat2 353
23 #endif
24
25 static int renameat2(int dfd1, const char *path1,
26                      int dfd2, const char *path2,
27                      unsigned int flags)
28 {
29 #ifdef SYS_renameat2
30         return syscall(SYS_renameat2, dfd1, path1, dfd2, path2, flags);
31 #else
32         errno = ENOSYS;
33         return -1;
34 #endif
35 }
36 #endif
37
38 #ifndef RENAME_NOREPLACE
39 #define RENAME_NOREPLACE        (1 << 0)        /* Don't overwrite target */
40 #endif
41 #ifndef RENAME_EXCHANGE
42 #define RENAME_EXCHANGE         (1 << 1)        /* Exchange source and dest */
43 #endif
44 #ifndef RENAME_WHITEOUT
45 #define RENAME_WHITEOUT         (1 << 2)        /* Whiteout source */
46 #endif
47
48 int main(int argc, char *argv[])
49 {
50         int ret;
51         int c;
52         const char *path1 = NULL;
53         const char *path2 = NULL;
54         unsigned int flags = 0;
55         int test = 0;
56
57         for (c = 1; c < argc; c++) {
58                 if (argv[c][0] == '-') {
59                         switch (argv[c][1]) {
60                         case 't':
61                                 test = 1;
62                                 break;
63                         case 'n':
64                                 flags |= RENAME_NOREPLACE;
65                                 break;
66                         case 'x':
67                                 flags |= RENAME_EXCHANGE;
68                                 break;
69                         case 'w':
70                                 flags |= RENAME_WHITEOUT;
71                                 break;
72                         default:
73                                 goto usage;
74                         }
75                 } else if (!path1) {
76                         path1 = argv[c];
77                 } else if (!path2) {
78                         path2 = argv[c];
79                 } else {
80                         goto usage;
81                 }
82         }
83
84         if (!test && (!path1 || !path2))
85                 goto usage;
86
87         ret = renameat2(AT_FDCWD, path1, AT_FDCWD, path2, flags);
88         if (ret == -1) {
89                 if (test) {
90                         if (errno == ENOSYS || errno == EINVAL)
91                                 return 1;
92                         else
93                                 return 0;
94                 }
95                 /*
96                  * Turn EEXIST into ENOTEMPTY.  E.g. XFS uses EEXIST, and that
97                  * is also accepted by the standards.
98                  *
99                  * This applies only to plain rename and RENAME_WHITEOUT
100                  */
101                 if (errno == EEXIST && (!flags || (flags & RENAME_WHITEOUT)))
102                         errno = ENOTEMPTY;
103
104                 perror("");
105                 return 1;
106         }
107
108         return 0;
109
110 usage:
111         fprintf(stderr,
112                 "usage: %s [-t] [-n|-x|-w] path1 path2\n"
113                 "  -t  test\n"
114                 "  -n  noreplace\n"
115                 "  -x  exchange\n"
116                 "  -w  whiteout\n", argv[0]);
117
118         return 1;
119 }