xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/renameat2.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1 // SPDX-License-Identifier: CDDL-1.0
2 /* SPDX-License-Identifier: CDDL-1.0 OR MPL-2.0 */
3 /*
4  * CDDL HEADER START
5  *
6  * The contents of this file are subject to the terms of the
7  * Common Development and Distribution License (the "License").
8  * You may not use this file except in compliance with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or https://opensource.org/licenses/CDDL-1.0.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 
24 /*
25  * Copyright (C) 2019 Aleksa Sarai <cyphar@cyphar.com>
26  * Copyright (C) 2019 SUSE LLC
27  */
28 
29 /*
30  * mv(1) doesn't currently support RENAME_{EXCHANGE,WHITEOUT} so this is a very
31  * simple renameat2(2) wrapper for the OpenZFS self-tests.
32  */
33 
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/syscall.h>
41 
42 #ifndef SYS_renameat2
43 #ifdef __NR_renameat2
44 #define	SYS_renameat2 __NR_renameat2
45 #elif defined(__x86_64__)
46 #define	SYS_renameat2 316
47 #elif defined(__i386__)
48 #define	SYS_renameat2 353
49 #elif defined(__arm__) || defined(__aarch64__)
50 #define	SYS_renameat2 382
51 #else
52 #error "SYS_renameat2 not known for this architecture."
53 #endif
54 #endif
55 
56 #ifndef RENAME_NOREPLACE
57 #define	RENAME_NOREPLACE	(1 << 0) /* Don't overwrite target */
58 #endif
59 #ifndef RENAME_EXCHANGE
60 #define	RENAME_EXCHANGE		(1 << 1) /* Exchange source and dest */
61 #endif
62 #ifndef RENAME_WHITEOUT
63 #define	RENAME_WHITEOUT		(1 << 2) /* Whiteout source */
64 #endif
65 
66 /* glibc doesn't provide renameat2 wrapper, let's use our own */
67 static int
sys_renameat2(int olddirfd,const char * oldpath,int newdirfd,const char * newpath,unsigned int flags)68 sys_renameat2(int olddirfd, const char *oldpath,
69     int newdirfd, const char *newpath, unsigned int flags)
70 {
71 	int ret = syscall(SYS_renameat2, olddirfd, oldpath, newdirfd, newpath,
72 	    flags);
73 	return ((ret < 0) ? -errno : ret);
74 }
75 
76 static void
usage(void)77 usage(void)
78 {
79 	fprintf(stderr, "usage: renameat2 [-Cnwx] src dst\n");
80 	exit(1);
81 }
82 
83 static void
check(void)84 check(void)
85 {
86 	int err = sys_renameat2(AT_FDCWD, ".", AT_FDCWD, ".", RENAME_EXCHANGE);
87 	exit(err == -ENOSYS);
88 }
89 
90 int
main(int argc,char ** argv)91 main(int argc, char **argv)
92 {
93 	char *src, *dst;
94 	int ch, err;
95 	unsigned int flags = 0;
96 
97 	while ((ch = getopt(argc, argv, "Cnwx")) >= 0) {
98 		switch (ch) {
99 			case 'C':
100 				check();
101 				break;
102 			case 'n':
103 				flags |= RENAME_NOREPLACE;
104 				break;
105 			case 'w':
106 				flags |= RENAME_WHITEOUT;
107 				break;
108 			case 'x':
109 				flags |= RENAME_EXCHANGE;
110 				break;
111 			default:
112 				usage();
113 				break;
114 		}
115 	}
116 
117 	argc -= optind;
118 	argv += optind;
119 
120 	if (argc != 2)
121 		usage();
122 	src = argv[0];
123 	dst = argv[1];
124 
125 	err = sys_renameat2(AT_FDCWD, src, AT_FDCWD, dst, flags);
126 	if (err < 0)
127 		fprintf(stderr, "renameat2: %s", strerror(-err));
128 	return (err != 0);
129 }
130