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