1/* 2 * Copyright (c) 1989, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ken Smith of The State University of New York at Buffalo. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static char const copyright[] = 39"@(#) Copyright (c) 1989, 1993, 1994\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44#if 0 45static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94"; 46#endif 47static const char rcsid[] =
| 1/* 2 * Copyright (c) 1989, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ken Smith of The State University of New York at Buffalo. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static char const copyright[] = 39"@(#) Copyright (c) 1989, 1993, 1994\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44#if 0 45static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94"; 46#endif 47static const char rcsid[] =
|
120 for (rval = 0; --argc; ++argv) { 121 /* 122 * Find the last component of the source pathname. It 123 * may have trailing slashes. 124 */ 125 p = *argv + strlen(*argv); 126 while (p != *argv && p[-1] == '/') 127 --p; 128 while (p != *argv && p[-1] != '/') 129 --p; 130 131 if ((baselen + (len = strlen(p))) >= MAXPATHLEN) { 132 warnx("%s: destination pathname too long", *argv); 133 rval = 1; 134 } else { 135 memmove(endp, p, len + 1); 136 if (do_move(*argv, path)) 137 rval = 1; 138 } 139 } 140 exit(rval); 141} 142 143int 144do_move(from, to) 145 char *from, *to; 146{ 147 struct stat sb; 148 int ask, ch, first; 149 char modep[15]; 150 151 /* 152 * Check access. If interactive and file exists, ask user if it 153 * should be replaced. Otherwise if file exists but isn't writable 154 * make sure the user wants to clobber it. 155 */ 156 if (!fflg && !access(to, F_OK)) { 157 158 /* prompt only if source exist */ 159 if (lstat(from, &sb) == -1) { 160 warn("%s", from); 161 return (1); 162 } 163 164#define YESNO "(y/n [n]) " 165 ask = 0; 166 if (iflg) { 167 (void)fprintf(stderr, "overwrite %s? %s", to, YESNO); 168 ask = 1; 169 } else if (access(to, W_OK) && !stat(to, &sb)) { 170 strmode(sb.st_mode, modep); 171 (void)fprintf(stderr, "override %s%s%s/%s for %s? %s", 172 modep + 1, modep[9] == ' ' ? "" : " ", 173 user_from_uid(sb.st_uid, 0), 174 group_from_gid(sb.st_gid, 0), to, YESNO); 175 ask = 1; 176 } 177 if (ask) { 178 first = ch = getchar(); 179 while (ch != '\n' && ch != EOF) 180 ch = getchar(); 181 if (first != 'y' && first != 'Y') { 182 (void)fprintf(stderr, "not overwritten\n"); 183 return (0); 184 } 185 } 186 } 187 if (!rename(from, to)) 188 return (0); 189 190 if (errno == EXDEV) { 191 struct statfs sfs; 192 char path[MAXPATHLEN]; 193 194 /* Can't mv(1) a mount point. */ 195 if (realpath(from, path) == NULL) { 196 warnx("cannot resolve %s: %s", from, path); 197 return (1); 198 } 199 if (!statfs(path, &sfs) && !strcmp(path, sfs.f_mntonname)) { 200 warnx("cannot rename a mount point"); 201 return (1); 202 } 203 } else { 204 warn("rename %s to %s", from, to); 205 return (1); 206 } 207 208 /* 209 * If rename fails because we're trying to cross devices, and 210 * it's a regular file, do the copy internally; otherwise, use 211 * cp and rm. 212 */ 213 if (stat(from, &sb)) { 214 warn("%s", from); 215 return (1); 216 } 217 return (S_ISREG(sb.st_mode) ? 218 fastcopy(from, to, &sb) : copy(from, to)); 219} 220 221int 222fastcopy(from, to, sbp) 223 char *from, *to; 224 struct stat *sbp; 225{ 226 struct timeval tval[2]; 227 static u_int blen; 228 static char *bp; 229 mode_t oldmode; 230 register int nread, from_fd, to_fd; 231 232 if ((from_fd = open(from, O_RDONLY, 0)) < 0) { 233 warn("%s", from); 234 return (1); 235 } 236 if (blen < sbp->st_blksize) { 237 if (bp != NULL) 238 free(bp); 239 if ((bp = malloc(sbp->st_blksize)) == NULL) { 240 blen = 0; 241 warnx("malloc failed"); 242 return (1); 243 } 244 blen = sbp->st_blksize; 245 } 246 while ((to_fd = 247 open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) { 248 if (errno == EEXIST && unlink(to) == 0) 249 continue; 250 warn("%s", to); 251 (void)close(from_fd); 252 return (1); 253 } 254 while ((nread = read(from_fd, bp, blen)) > 0) 255 if (write(to_fd, bp, nread) != nread) { 256 warn("%s", to); 257 goto err; 258 } 259 if (nread < 0) { 260 warn("%s", from); 261err: if (unlink(to)) 262 warn("%s: remove", to); 263 (void)close(from_fd); 264 (void)close(to_fd); 265 return (1); 266 } 267 (void)close(from_fd); 268 269 oldmode = sbp->st_mode & ALLPERMS; 270 if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) { 271 warn("%s: set owner/group (was: %u/%u)", to, sbp->st_uid, 272 sbp->st_gid); 273 if (oldmode & (S_ISUID | S_ISGID)) { 274 warnx( 275"%s: owner/group changed; clearing suid/sgid (mode was 0%03o)", 276 to, oldmode); 277 sbp->st_mode &= ~(S_ISUID | S_ISGID); 278 } 279 } 280 if (fchmod(to_fd, sbp->st_mode)) 281 warn("%s: set mode (was: 0%03o)", to, oldmode); 282 283 tval[0].tv_sec = sbp->st_atime; 284 tval[1].tv_sec = sbp->st_mtime; 285 tval[0].tv_usec = tval[1].tv_usec = 0; 286 if (utimes(to, tval)) 287 warn("%s: set times", to); 288 289 if (close(to_fd)) { 290 warn("%s", to); 291 return (1); 292 } 293 294 if (unlink(from)) { 295 warn("%s: remove", from); 296 return (1); 297 } 298 return (0); 299} 300 301int 302copy(from, to) 303 char *from, *to; 304{ 305 int pid, status; 306 307 if ((pid = vfork()) == 0) { 308 execl(_PATH_CP, "mv", "-PRp", from, to, NULL); 309 warn("%s", _PATH_CP); 310 _exit(1); 311 } 312 if (waitpid(pid, &status, 0) == -1) { 313 warn("%s: waitpid", _PATH_CP); 314 return (1); 315 } 316 if (!WIFEXITED(status)) { 317 warn("%s: did not terminate normally", _PATH_CP); 318 return (1); 319 } 320 if (WEXITSTATUS(status)) { 321 warn("%s: terminated with %d (non-zero) status", 322 _PATH_CP, WEXITSTATUS(status)); 323 return (1); 324 } 325 if (!(pid = vfork())) { 326 execl(_PATH_RM, "mv", "-rf", from, NULL); 327 warn("%s", _PATH_RM); 328 _exit(1); 329 } 330 if (waitpid(pid, &status, 0) == -1) { 331 warn("%s: waitpid", _PATH_RM); 332 return (1); 333 } 334 if (!WIFEXITED(status)) { 335 warn("%s: did not terminate normally", _PATH_RM); 336 return (1); 337 } 338 if (WEXITSTATUS(status)) { 339 warn("%s: terminated with %d (non-zero) status", 340 _PATH_RM, WEXITSTATUS(status)); 341 return (1); 342 } 343 return (0); 344} 345 346void 347usage() 348{ 349 (void)fprintf(stderr, "%s\n%s\n", 350 "usage: mv [-f | -i] source target", 351 " mv [-f | -i] source ... directory"); 352 exit(1); 353}
| 122 for (rval = 0; --argc; ++argv) { 123 /* 124 * Find the last component of the source pathname. It 125 * may have trailing slashes. 126 */ 127 p = *argv + strlen(*argv); 128 while (p != *argv && p[-1] == '/') 129 --p; 130 while (p != *argv && p[-1] != '/') 131 --p; 132 133 if ((baselen + (len = strlen(p))) >= MAXPATHLEN) { 134 warnx("%s: destination pathname too long", *argv); 135 rval = 1; 136 } else { 137 memmove(endp, p, len + 1); 138 if (do_move(*argv, path)) 139 rval = 1; 140 } 141 } 142 exit(rval); 143} 144 145int 146do_move(from, to) 147 char *from, *to; 148{ 149 struct stat sb; 150 int ask, ch, first; 151 char modep[15]; 152 153 /* 154 * Check access. If interactive and file exists, ask user if it 155 * should be replaced. Otherwise if file exists but isn't writable 156 * make sure the user wants to clobber it. 157 */ 158 if (!fflg && !access(to, F_OK)) { 159 160 /* prompt only if source exist */ 161 if (lstat(from, &sb) == -1) { 162 warn("%s", from); 163 return (1); 164 } 165 166#define YESNO "(y/n [n]) " 167 ask = 0; 168 if (iflg) { 169 (void)fprintf(stderr, "overwrite %s? %s", to, YESNO); 170 ask = 1; 171 } else if (access(to, W_OK) && !stat(to, &sb)) { 172 strmode(sb.st_mode, modep); 173 (void)fprintf(stderr, "override %s%s%s/%s for %s? %s", 174 modep + 1, modep[9] == ' ' ? "" : " ", 175 user_from_uid(sb.st_uid, 0), 176 group_from_gid(sb.st_gid, 0), to, YESNO); 177 ask = 1; 178 } 179 if (ask) { 180 first = ch = getchar(); 181 while (ch != '\n' && ch != EOF) 182 ch = getchar(); 183 if (first != 'y' && first != 'Y') { 184 (void)fprintf(stderr, "not overwritten\n"); 185 return (0); 186 } 187 } 188 } 189 if (!rename(from, to)) 190 return (0); 191 192 if (errno == EXDEV) { 193 struct statfs sfs; 194 char path[MAXPATHLEN]; 195 196 /* Can't mv(1) a mount point. */ 197 if (realpath(from, path) == NULL) { 198 warnx("cannot resolve %s: %s", from, path); 199 return (1); 200 } 201 if (!statfs(path, &sfs) && !strcmp(path, sfs.f_mntonname)) { 202 warnx("cannot rename a mount point"); 203 return (1); 204 } 205 } else { 206 warn("rename %s to %s", from, to); 207 return (1); 208 } 209 210 /* 211 * If rename fails because we're trying to cross devices, and 212 * it's a regular file, do the copy internally; otherwise, use 213 * cp and rm. 214 */ 215 if (stat(from, &sb)) { 216 warn("%s", from); 217 return (1); 218 } 219 return (S_ISREG(sb.st_mode) ? 220 fastcopy(from, to, &sb) : copy(from, to)); 221} 222 223int 224fastcopy(from, to, sbp) 225 char *from, *to; 226 struct stat *sbp; 227{ 228 struct timeval tval[2]; 229 static u_int blen; 230 static char *bp; 231 mode_t oldmode; 232 register int nread, from_fd, to_fd; 233 234 if ((from_fd = open(from, O_RDONLY, 0)) < 0) { 235 warn("%s", from); 236 return (1); 237 } 238 if (blen < sbp->st_blksize) { 239 if (bp != NULL) 240 free(bp); 241 if ((bp = malloc(sbp->st_blksize)) == NULL) { 242 blen = 0; 243 warnx("malloc failed"); 244 return (1); 245 } 246 blen = sbp->st_blksize; 247 } 248 while ((to_fd = 249 open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) { 250 if (errno == EEXIST && unlink(to) == 0) 251 continue; 252 warn("%s", to); 253 (void)close(from_fd); 254 return (1); 255 } 256 while ((nread = read(from_fd, bp, blen)) > 0) 257 if (write(to_fd, bp, nread) != nread) { 258 warn("%s", to); 259 goto err; 260 } 261 if (nread < 0) { 262 warn("%s", from); 263err: if (unlink(to)) 264 warn("%s: remove", to); 265 (void)close(from_fd); 266 (void)close(to_fd); 267 return (1); 268 } 269 (void)close(from_fd); 270 271 oldmode = sbp->st_mode & ALLPERMS; 272 if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) { 273 warn("%s: set owner/group (was: %u/%u)", to, sbp->st_uid, 274 sbp->st_gid); 275 if (oldmode & (S_ISUID | S_ISGID)) { 276 warnx( 277"%s: owner/group changed; clearing suid/sgid (mode was 0%03o)", 278 to, oldmode); 279 sbp->st_mode &= ~(S_ISUID | S_ISGID); 280 } 281 } 282 if (fchmod(to_fd, sbp->st_mode)) 283 warn("%s: set mode (was: 0%03o)", to, oldmode); 284 285 tval[0].tv_sec = sbp->st_atime; 286 tval[1].tv_sec = sbp->st_mtime; 287 tval[0].tv_usec = tval[1].tv_usec = 0; 288 if (utimes(to, tval)) 289 warn("%s: set times", to); 290 291 if (close(to_fd)) { 292 warn("%s", to); 293 return (1); 294 } 295 296 if (unlink(from)) { 297 warn("%s: remove", from); 298 return (1); 299 } 300 return (0); 301} 302 303int 304copy(from, to) 305 char *from, *to; 306{ 307 int pid, status; 308 309 if ((pid = vfork()) == 0) { 310 execl(_PATH_CP, "mv", "-PRp", from, to, NULL); 311 warn("%s", _PATH_CP); 312 _exit(1); 313 } 314 if (waitpid(pid, &status, 0) == -1) { 315 warn("%s: waitpid", _PATH_CP); 316 return (1); 317 } 318 if (!WIFEXITED(status)) { 319 warn("%s: did not terminate normally", _PATH_CP); 320 return (1); 321 } 322 if (WEXITSTATUS(status)) { 323 warn("%s: terminated with %d (non-zero) status", 324 _PATH_CP, WEXITSTATUS(status)); 325 return (1); 326 } 327 if (!(pid = vfork())) { 328 execl(_PATH_RM, "mv", "-rf", from, NULL); 329 warn("%s", _PATH_RM); 330 _exit(1); 331 } 332 if (waitpid(pid, &status, 0) == -1) { 333 warn("%s: waitpid", _PATH_RM); 334 return (1); 335 } 336 if (!WIFEXITED(status)) { 337 warn("%s: did not terminate normally", _PATH_RM); 338 return (1); 339 } 340 if (WEXITSTATUS(status)) { 341 warn("%s: terminated with %d (non-zero) status", 342 _PATH_RM, WEXITSTATUS(status)); 343 return (1); 344 } 345 return (0); 346} 347 348void 349usage() 350{ 351 (void)fprintf(stderr, "%s\n%s\n", 352 "usage: mv [-f | -i] source target", 353 " mv [-f | -i] source ... directory"); 354 exit(1); 355}
|