1: #ifndef lint
   2: static  char *sccsid = "@(#)mv.c	4.4 (Berkeley) 81/04/26";
   3: #endif
   4: /*
   5:  * mv file1 file2
   6:  */
   7: 
   8: #include <stdio.h>
   9: #include <sys/types.h>
  10: #include <sys/stat.h>
  11: #include <sys/dir.h>
  12: #include <signal.h>
  13: 
  14: #define DOT "."
  15: #define DOTDOT  ".."
  16: #define DELIM   '/'
  17: #define SDELIM "/"
  18: #define MAXN    100
  19: #define MODEBITS 07777
  20: #define ROOTINO 2
  21: 
  22: char    *pname();
  23: char    *sprintf();
  24: char    *dname();
  25: struct  stat s1, s2;
  26: int iflag = 0;  /* interactive flag. If this flag is set,
  27: 			 * the user is queried before files are
  28: 			 * destroyed by cp.
  29: 			 */
  30: int fflag = 0;  /* force flag. supercedes all restrictions */
  31: 
  32: main(argc, argv)
  33: register char *argv[];
  34: {
  35:     register i, r;
  36:     register char *arg;
  37: 
  38:     /* get the flag(s) */
  39: 
  40:     if (argc < 2)
  41:         goto usage;
  42:     while (argc>1 && *argv[1] == '-') {
  43:         argc--;
  44:         arg = *++argv;
  45: 
  46:         /*
  47: 		 *  all files following a null option are considered file names
  48: 		 */
  49:         if (*(arg+1) == '\0') break;
  50: 
  51:         while (*++arg != '\0')
  52:             switch (*arg) {
  53: 
  54:             /* interactive mode */
  55:             case 'i':
  56:                 iflag++;
  57:                 break;
  58: 
  59:             /* force moves */
  60:             case 'f':
  61:                 fflag++;
  62:                 break;
  63: 
  64:             /* don't live with bad options */
  65:             default:
  66:                 goto usage;
  67:             }
  68:     }
  69:     if (argc < 3)
  70:         goto usage;
  71:     if (stat(argv[1], &s1) < 0) {
  72:         fprintf(stderr, "mv: cannot access %s\n", argv[1]);
  73:         return(1);
  74:     }
  75:     if ((s1.st_mode & S_IFMT) == S_IFDIR) {
  76:         if (argc != 3)
  77:             goto usage;
  78:         return mvdir(argv[1], argv[2]);
  79:     }
  80:     setuid(getuid());
  81:     if (argc > 3)
  82:         if (stat(argv[argc-1], &s2) < 0 || (s2.st_mode & S_IFMT) != S_IFDIR)
  83:             goto usage;
  84:     r = 0;
  85:     for (i=1; i<argc-1; i++)
  86:         r |= move(argv[i], argv[argc-1]);
  87:     return(r);
  88: usage:
  89:     fprintf(stderr, "usage: mv [-if] f1 f2; or mv [-if] d1 d2; or mv [-if] f1 ... fn d1\n");
  90:     return(1);
  91: }
  92: 
  93: move(source, target)
  94: char *source, *target;
  95: {
  96:     register c, i;
  97:     int status;
  98:     char    buf[MAXN];
  99: 
 100:     if (stat(source, &s1) < 0) {
 101:         fprintf(stderr, "mv: cannot access %s\n", source);
 102:         return(1);
 103:     }
 104:     if ((s1.st_mode & S_IFMT) == S_IFDIR) {
 105:         fprintf(stderr, "mv: directory rename only\n");
 106:         return(1);
 107:     }
 108:     if (stat(target, &s2) >= 0) {
 109:         if ((s2.st_mode & S_IFMT) == S_IFDIR) {
 110:             sprintf(buf, "%s/%s", target, dname(source));
 111:             target = buf;
 112:         }
 113:         if (stat(target, &s2) >= 0) {
 114:             if ((s2.st_mode & S_IFMT) == S_IFDIR) {
 115:                 fprintf(stderr, "mv: %s is a directory\n", target);
 116:                 return(1);
 117:             } else if (iflag && !fflag) {
 118:                 fprintf(stderr, "remove %s? ", target);
 119:                 i = c = getchar();
 120:                 while (c != '\n' && c != EOF)
 121:                     c = getchar();
 122:                 if (i != 'y')
 123:                     return(1);
 124:             }
 125:             if (s1.st_dev==s2.st_dev && s1.st_ino==s2.st_ino) {
 126:                 fprintf(stderr, "mv: %s and %s are identical\n",
 127:                         source, target);
 128:                 return(1);
 129:             }
 130:             if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) {
 131:                 fprintf(stderr, "override protection %o for %s? ",
 132:                     s2.st_mode & MODEBITS, target);
 133:                 i = c = getchar();
 134:                 while (c != '\n' && c != EOF)
 135:                     c = getchar();
 136:                 if (i != 'y')
 137:                     return(1);
 138:             }
 139:             if (unlink(target) < 0) {
 140:                 fprintf(stderr, "mv: cannot unlink %s\n", target);
 141:                 return(1);
 142:             }
 143:         }
 144:     }
 145:     if (link(source, target) < 0) {
 146:         i = fork();
 147:         if (i == -1) {
 148:             fprintf(stderr, "mv: try again\n");
 149:             return(1);
 150:         }
 151:         if (i == 0) {
 152:             execl("/bin/cp", "cp", source, target, 0);
 153:             fprintf(stderr, "mv: cannot exec cp\n");
 154:             exit(1);
 155:         }
 156:         while ((c = wait(&status)) != i && c != -1)
 157:             ;
 158:         if (status != 0)
 159:             return(1);
 160:         utime(target, &s1.st_atime);
 161:     }
 162:     if (unlink(source) < 0) {
 163:         fprintf(stderr, "mv: cannot unlink %s\n", source);
 164:         return(1);
 165:     }
 166:     return(0);
 167: }
 168: 
 169: mvdir(source, target)
 170: char *source, *target;
 171: {
 172:     register char *p;
 173:     register i;
 174:     char buf[MAXN];
 175: 
 176:     if (stat(target, &s2) >= 0) {
 177:         if ((s2.st_mode&S_IFMT) != S_IFDIR) {
 178:             fprintf(stderr, "mv: %s exists\n", target);
 179:             return(1);
 180:         }
 181:         if (strlen(target) > MAXN-DIRSIZ-2) {
 182:             fprintf(stderr, "mv :target name too long\n");
 183:             return(1);
 184:         }
 185:         strcpy(buf, target);
 186:         target = buf;
 187:         strcat(buf, SDELIM);
 188:         strcat(buf, dname(source));
 189:         if (stat(target, &s2) >= 0) {
 190:             fprintf(stderr, "mv: %s exists\n", buf);
 191:             return(1);
 192:         }
 193:     }
 194:     if (strcmp(source, target) == 0) {
 195:         fprintf(stderr, "mv: ?? source == target, source exists and target doesnt\n");
 196:         return(1);
 197:     }
 198:     p = dname(source);
 199:     if (!strcmp(p, DOT) || !strcmp(p, DOTDOT) || !strcmp(p, "") || p[strlen(p)-1]=='/') {
 200:         fprintf(stderr, "mv: cannot rename %s\n", p);
 201:         return(1);
 202:     }
 203:     if (stat(pname(source), &s1) < 0 || stat(pname(target), &s2) < 0) {
 204:         fprintf(stderr, "mv: cannot locate parent\n");
 205:         return(1);
 206:     }
 207:     if (access(pname(target), 2) < 0) {
 208:         fprintf(stderr, "mv: no write access to %s\n", pname(target));
 209:         return(1);
 210:     }
 211:     if (access(pname(source), 2) < 0) {
 212:         fprintf(stderr, "mv: no write access to %s\n", pname(source));
 213:         return(1);
 214:     }
 215:     if (s1.st_dev != s2.st_dev) {
 216:         fprintf(stderr, "mv: cannot move directories across devices\n");
 217:         return(1);
 218:     }
 219:     if (s1.st_ino != s2.st_ino) {
 220:         char dst[MAXN+5];
 221: 
 222:         if (chkdot(source) || chkdot(target)) {
 223:             fprintf(stderr, "mv: Sorry, path names including %s aren't allowed\n", DOTDOT);
 224:             return(1);
 225:         }
 226:         stat(source, &s1);
 227:         if (check(pname(target), s1.st_ino))
 228:             return(1);
 229:         for (i = 1; i <= NSIG; i++)
 230:             signal(i, SIG_IGN);
 231:         if (link(source, target) < 0) {
 232:             fprintf(stderr, "mv: cannot link %s to %s\n", target, source);
 233:             return(1);
 234:         }
 235:         if (unlink(source) < 0) {
 236:             fprintf(stderr, "mv: %s: cannot unlink\n", source);
 237:             unlink(target);
 238:             return(1);
 239:         }
 240:         strcpy(dst, target);
 241:         strcat(dst, "/");
 242:         strcat(dst, DOTDOT);
 243:         if (unlink(dst) < 0) {
 244:             fprintf(stderr, "mv: %s: cannot unlink\n", dst);
 245:             if (link(target, source) >= 0)
 246:                 unlink(target);
 247:             return(1);
 248:         }
 249:         if (link(pname(target), dst) < 0) {
 250:             fprintf(stderr, "mv: cannot link %s to %s\n",
 251:                 dst, pname(target));
 252:             if (link(pname(source), dst) >= 0)
 253:                 if (link(target, source) >= 0)
 254:                     unlink(target);
 255:             return(1);
 256:         }
 257:         return(0);
 258:     }
 259:     if (link(source, target) < 0) {
 260:         fprintf(stderr, "mv: cannot link %s and %s\n",
 261:             source, target);
 262:         return(1);
 263:     }
 264:     if (unlink(source) < 0) {
 265:         fprintf(stderr, "mv: ?? cannot unlink %s\n", source);
 266:         return(1);
 267:     }
 268:     return(0);
 269: }
 270: 
 271: char *
 272: pname(name)
 273: register char *name;
 274: {
 275:     register c;
 276:     register char *p, *q;
 277:     static  char buf[MAXN];
 278: 
 279:     p = q = buf;
 280:     while (c = *p++ = *name++)
 281:         if (c == DELIM)
 282:             q = p-1;
 283:     if (q == buf && *q == DELIM)
 284:         q++;
 285:     *q = 0;
 286:     return buf[0]? buf : DOT;
 287: }
 288: 
 289: char *
 290: dname(name)
 291: register char *name;
 292: {
 293:     register char *p;
 294: 
 295:     p = name;
 296:     while (*p)
 297:         if (*p++ == DELIM && *p)
 298:             name = p;
 299:     return name;
 300: }
 301: 
 302: check(spth, dinode)
 303: char *spth;
 304: ino_t dinode;
 305: {
 306:     char nspth[MAXN];
 307:     struct stat sbuf;
 308: 
 309:     sbuf.st_ino = 0;
 310: 
 311:     strcpy(nspth, spth);
 312:     while (sbuf.st_ino != ROOTINO) {
 313:         if (stat(nspth, &sbuf) < 0) {
 314:             fprintf(stderr, "mv: cannot access %s\n", nspth);
 315:             return(1);
 316:         }
 317:         if (sbuf.st_ino == dinode) {
 318:             fprintf(stderr, "mv: cannot move a directory into itself\n");
 319:             return(1);
 320:         }
 321:         if (strlen(nspth) > MAXN-2-sizeof(DOTDOT)) {
 322:             fprintf(stderr, "mv: name too long\n");
 323:             return(1);
 324:         }
 325:         strcat(nspth, SDELIM);
 326:         strcat(nspth, DOTDOT);
 327:     }
 328:     return(0);
 329: }
 330: 
 331: chkdot(s)
 332: register char *s;
 333: {
 334:     do {
 335:         if (strcmp(dname(s), DOTDOT) == 0)
 336:             return(1);
 337:         s = pname(s);
 338:     } while (strcmp(s, DOT) != 0 && strcmp(s, SDELIM) != 0);
 339:     return(0);
 340: }

Defined functions

check defined in line 302; used 1 times
chkdot defined in line 331; used 2 times
  • in line 222(2)
dname defined in line 289; used 5 times
main defined in line 32; never used
move defined in line 93; used 1 times
  • in line 86
mvdir defined in line 169; used 1 times
  • in line 78
pname defined in line 271; used 12 times

Defined variables

fflag defined in line 30; used 3 times
iflag defined in line 26; used 2 times
s1 defined in line 25; used 12 times
s2 defined in line 25; used 15 times
sccsid defined in line 2; never used

Defined macros

DELIM defined in line 16; used 3 times
DOT defined in line 14; used 3 times
DOTDOT defined in line 15; used 6 times
MAXN defined in line 18; used 7 times
MODEBITS defined in line 19; used 1 times
ROOTINO defined in line 20; used 1 times
SDELIM defined in line 17; used 3 times
Last modified: 1982-09-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1059
Valid CSS Valid XHTML 1.0 Strict