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 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 77 usage(void) 78 { 79 fprintf(stderr, "usage: renameat2 [-Cnwx] src dst\n"); 80 exit(1); 81 } 82 83 static void 84 check(void) 85 { 86 int err = sys_renameat2(AT_FDCWD, ".", AT_FDCWD, ".", RENAME_EXCHANGE); 87 exit(err == -ENOSYS); 88 } 89 90 int 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