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