119845Sdist /* 239246Sbostic * Copyright (c) 1989 The Regents of the University of California. 339246Sbostic * All rights reserved. 439246Sbostic * 539246Sbostic * This code is derived from software contributed to Berkeley by 639246Sbostic * Ken Smith of The State University of New York at Buffalo. 739246Sbostic * 8*42536Sbostic * %sccs.include.redist.c% 919845Sdist */ 1019845Sdist 1110047Ssam #ifndef lint 1219845Sdist char copyright[] = 1339246Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 1419845Sdist All rights reserved.\n"; 1534045Sbostic #endif /* not lint */ 168839Smckusick 1719845Sdist #ifndef lint 18*42536Sbostic static char sccsid[] = "@(#)mv.c 5.9 (Berkeley) 05/31/90"; 1934045Sbostic #endif /* not lint */ 2019845Sdist 2110047Ssam #include <sys/param.h> 2239246Sbostic #include <sys/time.h> 2339246Sbostic #include <sys/wait.h> 2410047Ssam #include <sys/stat.h> 2533382Sbostic #include <sys/file.h> 2639246Sbostic #include <sys/errno.h> 271216Sbill #include <stdio.h> 2839246Sbostic #include <string.h> 2939246Sbostic #include "pathnames.h" 301216Sbill 3139246Sbostic extern int errno; 3239246Sbostic int fflg, iflg; 331216Sbill 341216Sbill main(argc, argv) 3539246Sbostic int argc; 3639246Sbostic char **argv; 371216Sbill { 3839246Sbostic extern char *optarg; 3934045Sbostic extern int optind; 4039246Sbostic register int baselen, exitval, len; 4139246Sbostic register char *p, *endp; 4239246Sbostic struct stat sbuf; 4339246Sbostic int ch; 4439246Sbostic char path[MAXPATHLEN + 1]; 451216Sbill 4639246Sbostic while (((ch = getopt(argc, argv, "-if")) != EOF)) 4734045Sbostic switch((char)ch) { 4839246Sbostic case 'i': 4939246Sbostic ++iflg; 5039246Sbostic break; 5134045Sbostic case 'f': 5239246Sbostic ++fflg; 5310047Ssam break; 5439246Sbostic case '-': /* undocumented; for compatibility */ 5539246Sbostic goto endarg; 5634045Sbostic case '?': 5710047Ssam default: 5834045Sbostic usage(); 5910047Ssam } 6039246Sbostic endarg: argc -= optind; 6139246Sbostic argv += optind; 6234045Sbostic 6334045Sbostic if (argc < 2) 6434045Sbostic usage(); 6539246Sbostic 6639246Sbostic /* 6739246Sbostic * if stat fails on target, it doesn't exist (or can't be accessed 6839246Sbostic * by the user, doesn't matter which) try the move. If target exists, 6939246Sbostic * and isn't a directory, try the move. More than 2 arguments is an 7039246Sbostic * error. 7139246Sbostic */ 7239246Sbostic if (stat(argv[argc - 1], &sbuf) || !S_ISDIR(sbuf.st_mode)) { 7339246Sbostic if (argc > 2) 7439246Sbostic usage(); 7539246Sbostic exit(do_move(argv[0], argv[1])); 761216Sbill } 771216Sbill 7839246Sbostic /* got a directory, move each file into it */ 7939246Sbostic (void)strcpy(path, argv[argc - 1]); 8039246Sbostic baselen = strlen(path); 8139246Sbostic endp = &path[baselen]; 8239246Sbostic *endp++ = '/'; 8339246Sbostic ++baselen; 8439246Sbostic for (exitval = 0; --argc; ++argv) { 8539246Sbostic if ((p = rindex(*argv, '/')) == NULL) 8639246Sbostic p = *argv; 8739246Sbostic else 8839246Sbostic ++p; 8939246Sbostic if ((baselen + (len = strlen(p))) >= MAXPATHLEN) 9039246Sbostic (void)fprintf(stderr, 9139246Sbostic "mv: %s: destination pathname too long\n", *argv); 9239246Sbostic else { 9339246Sbostic bcopy(p, endp, len + 1); 9439246Sbostic exitval |= do_move(*argv, path); 9539246Sbostic } 9610047Ssam } 9739246Sbostic exit(exitval); 9810047Ssam } 9910047Ssam 10039246Sbostic do_move(from, to) 10139246Sbostic char *from, *to; 1021216Sbill { 10339246Sbostic struct stat sbuf; 10439246Sbostic int ask, ch; 1051216Sbill 10610047Ssam /* 10739246Sbostic * Check access. If interactive and file exists ask user if it 10839246Sbostic * should be replaced. Otherwise if file exists but isn't writable 10939246Sbostic * make sure the user wants to clobber it. 11010047Ssam */ 11139246Sbostic if (!fflg && !access(to, F_OK)) { 11239246Sbostic ask = 0; 11339246Sbostic if (iflg) { 11439246Sbostic (void)fprintf(stderr, "overwrite %s? ", to); 11539246Sbostic ask = 1; 1161216Sbill } 11739246Sbostic else if (access(to, W_OK) && !stat(to, &sbuf)) { 11839246Sbostic (void)fprintf(stderr, "override mode %o on %s? ", 11939246Sbostic sbuf.st_mode & 07777, to); 12039246Sbostic ask = 1; 12139246Sbostic } 12239246Sbostic if (ask) { 12339246Sbostic if ((ch = getchar()) != EOF && ch != '\n') 12439246Sbostic while (getchar() != '\n'); 12539246Sbostic if (ch != 'y') 12639246Sbostic return(0); 12739246Sbostic } 1281216Sbill } 12939246Sbostic if (!rename(from, to)) 13039246Sbostic return(0); 13111642Ssam if (errno != EXDEV) { 13239246Sbostic (void)fprintf(stderr, 13339246Sbostic "mv: rename %s to %s: %s\n", from, to, strerror(errno)); 13439246Sbostic return(1); 13511642Ssam } 13610047Ssam /* 13739246Sbostic * if rename fails, and it's a regular file, do the copy 13839246Sbostic * internally; otherwise, use cp and rm. 13910047Ssam */ 14039246Sbostic if (stat(from, &sbuf)) { 14139246Sbostic (void)fprintf(stderr, 14239246Sbostic "mv: %s: %s\n", from, strerror(errno)); 14339246Sbostic return(1); 14410047Ssam } 14539246Sbostic return(S_ISREG(sbuf.st_mode) ? 14639246Sbostic fastcopy(from, to, &sbuf) : copy(from, to)); 14739246Sbostic } 14810166Ssam 14939246Sbostic fastcopy(from, to, sbp) 15039246Sbostic char *from, *to; 15139246Sbostic struct stat *sbp; 15239246Sbostic { 15339246Sbostic struct timeval tval[2]; 15439246Sbostic static u_int blen; 15539246Sbostic static char *bp; 15639246Sbostic register int nread, from_fd, to_fd; 15739246Sbostic char *malloc(); 15822601Sserge 15939246Sbostic if ((from_fd = open(from, O_RDONLY, 0)) < 0) { 16039246Sbostic (void)fprintf(stderr, 16139246Sbostic "mv: %s: %s\n", from, strerror(errno)); 16239246Sbostic return(1); 16310047Ssam } 16439246Sbostic if ((to_fd = open(to, O_WRONLY|O_CREAT|O_TRUNC, sbp->st_mode)) < 0) { 16539246Sbostic (void)fprintf(stderr, 16639246Sbostic "mv: %s: %s\n", to, strerror(errno)); 16739246Sbostic (void)close(from_fd); 16839246Sbostic return(1); 16939246Sbostic } 17039246Sbostic if (!blen && !(bp = malloc(blen = sbp->st_blksize))) { 17139246Sbostic (void)fprintf(stderr, "mv: %s: out of memory.\n", from); 17239246Sbostic return(1); 17339246Sbostic } 17439246Sbostic while ((nread = read(from_fd, bp, blen)) > 0) 17539246Sbostic if (write(to_fd, bp, nread) != nread) { 17639246Sbostic (void)fprintf(stderr, "mv: %s: %s\n", 17739246Sbostic to, strerror(errno)); 17839246Sbostic goto err; 1791216Sbill } 18039246Sbostic if (nread < 0) { 18139246Sbostic (void)fprintf(stderr, "mv: %s: %s\n", from, strerror(errno)); 18239246Sbostic err: (void)unlink(to); 18339246Sbostic (void)close(from_fd); 18439246Sbostic (void)close(to_fd); 18539246Sbostic return(1); 1861216Sbill } 18739246Sbostic (void)fchown(to_fd, sbp->st_uid, sbp->st_gid); 18839246Sbostic (void)fchmod(to_fd, sbp->st_mode); 1891216Sbill 19039246Sbostic (void)close(from_fd); 19139246Sbostic (void)close(to_fd); 1921216Sbill 19339246Sbostic tval[0].tv_sec = sbp->st_atime; 19439246Sbostic tval[1].tv_sec = sbp->st_mtime; 19539246Sbostic tval[0].tv_usec = tval[1].tv_usec = 0; 19639246Sbostic (void)utimes(to, tval); 19739246Sbostic (void)unlink(from); 19839246Sbostic return(0); 1991216Sbill } 2001216Sbill 20139246Sbostic copy(from, to) 20239246Sbostic char *from, *to; 2031216Sbill { 20439246Sbostic int pid, status; 2051216Sbill 20639246Sbostic if (!(pid = vfork())) { 20739246Sbostic execlp(_PATH_CP, "mv", "-pr", from, to); 20839246Sbostic (void)fprintf(stderr, "mv: can't exec %s.\n", _PATH_CP); 20939246Sbostic _exit(1); 21039246Sbostic } 21139246Sbostic (void)waitpid(pid, &status, 0); 21239246Sbostic if (!WIFEXITED(status) || WEXITSTATUS(status)) 21339246Sbostic return(1); 21439246Sbostic if (!(pid = vfork())) { 21539246Sbostic execlp(_PATH_RM, "mv", "-rf", from); 21639246Sbostic (void)fprintf(stderr, "mv: can't exec %s.\n", _PATH_RM); 21739246Sbostic _exit(1); 21839246Sbostic } 21939246Sbostic (void)waitpid(pid, &status, 0); 22039246Sbostic return(!WIFEXITED(status) || WEXITSTATUS(status)); 2211216Sbill } 2221216Sbill 22334045Sbostic usage() 22434045Sbostic { 22539246Sbostic (void)fprintf(stderr, 22639246Sbostic "usage: mv [-if] src target;\n or: mv [-if] src1 ... srcN directory\n"); 22734045Sbostic exit(1); 22834045Sbostic } 229