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 --- 28 unchanged lines hidden (view full) --- 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94"; 42#endif /* not lint */ 43#endif 44#include <sys/cdefs.h> |
45__FBSDID("$FreeBSD: head/bin/mv/mv.c 174664 2007-12-16 14:14:31Z dds $"); |
46 47#include <sys/types.h> 48#include <sys/acl.h> 49#include <sys/param.h> 50#include <sys/time.h> 51#include <sys/wait.h> 52#include <sys/stat.h> 53#include <sys/mount.h> --- 296 unchanged lines hidden (view full) --- 350 if (vflg) 351 printf("%s -> %s\n", from, to); 352 return (0); 353} 354 355int 356copy(char *from, char *to) 357{ |
358 struct stat sb; 359 enum clean {CLEAN_SOURCE, CLEAN_DEST, CLEAN_ODEST, CLEAN_MAX}; 360 char *cleanup[CLEAN_MAX]; 361 int pid, status, rval, i; |
362 |
363 rval = 0; 364 for (i = 0; i < CLEAN_MAX; i++) 365 cleanup[i] = NULL; 366 /* 367 * If "to" exists and is a directory, get it out of the way. 368 * When the copy succeeds, delete it. 369 */ 370 if (stat(to, &sb) == 0 && S_ISDIR(sb.st_mode)) { 371 if (asprintf(&cleanup[CLEAN_ODEST], "%s.XXXXXX", to) == -1) { 372 warnx("asprintf failed"); 373 return (1); 374 375 } 376 if (rename(to, cleanup[CLEAN_ODEST]) < 0) { 377 warn("rename of existing target from %s to %s failed", 378 to, cleanup[CLEAN_ODEST]); 379 free(cleanup[CLEAN_ODEST]); 380 return (1); 381 } 382 } 383 /* Copy source to destination. */ 384 cleanup[CLEAN_DEST] = to; |
385 if ((pid = fork()) == 0) { 386 execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to, 387 (char *)NULL); 388 warn("%s", _PATH_CP); 389 _exit(1); 390 } 391 if (waitpid(pid, &status, 0) == -1) { 392 warn("%s: waitpid", _PATH_CP); |
393 rval = 1; 394 goto done; |
395 } 396 if (!WIFEXITED(status)) { 397 warnx("%s: did not terminate normally", _PATH_CP); |
398 rval = 1; 399 goto done; |
400 } 401 if (WEXITSTATUS(status)) { 402 warnx("%s: terminated with %d (non-zero) status", 403 _PATH_CP, WEXITSTATUS(status)); |
404 rval = 1; 405 goto done; |
406 } |
407 /* 408 * The copy succeeded. From now on the destination is where users 409 * will find their files. 410 */ 411 cleanup[CLEAN_DEST] = NULL; 412 cleanup[CLEAN_SOURCE] = from; 413done: 414 /* Clean what needs to be cleaned. */ 415 for (i = 0; i < CLEAN_MAX; i++) { 416 if (cleanup[i] == NULL) 417 continue; 418 if (!(pid = vfork())) { 419 execl(_PATH_RM, "mv", "-rf", "--", cleanup[i], 420 (char *)NULL); 421 warn("%s %s", _PATH_RM, cleanup[i]); 422 _exit(1); 423 } 424 if (waitpid(pid, &status, 0) == -1) { 425 warn("%s %s: waitpid", _PATH_RM, cleanup[i]); 426 rval = 1; 427 continue; 428 } 429 if (!WIFEXITED(status)) { 430 warnx("%s %s: did not terminate normally", 431 _PATH_RM, cleanup[i]); 432 rval = 1; 433 continue; 434 } 435 if (WEXITSTATUS(status)) { 436 warnx("%s %s: terminated with %d (non-zero) status", 437 _PATH_RM, cleanup[i], WEXITSTATUS(status)); 438 rval = 1; 439 continue; 440 } 441 /* 442 * If the copy failed, and we just deleted the copy's trash, 443 * try to salvage the original destination, 444 */ 445 if (i == CLEAN_DEST && cleanup[CLEAN_ODEST]) { 446 if (rename(cleanup[CLEAN_ODEST], to) < 0) { 447 warn("rename back renamed existing target from %s to %s failed", 448 cleanup[CLEAN_ODEST], to); 449 rval = 1; 450 } 451 free(cleanup[CLEAN_ODEST]); 452 cleanup[CLEAN_ODEST] = NULL; 453 } |
454 } |
455 if (cleanup[CLEAN_ODEST]) 456 free(cleanup[CLEAN_ODEST]); 457 return (rval); |
458} 459 460void 461usage(void) 462{ 463 464 (void)fprintf(stderr, "%s\n%s\n", 465 "usage: mv [-f | -i | -n] [-v] source target", 466 " mv [-f | -i | -n] [-v] source ... directory"); 467 exit(EX_USAGE); 468} |