00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <errno.h>
00037 #include <fcntl.h>
00038 #include <utime.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <unistd.h>
00042 #include <sys/wait.h>
00043 #include <stdio.h>
00044 #include <dirent.h>
00045
00046 #define NAME_SIZE _DIRENT_NAME_LEN
00047
00048 #undef NARROW
00049 #define COPY_SIZE 4096
00050 #define MAX_ENTRIES 512
00051 #define MAX_PATH 256
00052 #define NONFATAL 0
00053 #define FATAL 1
00054 #define NO_SAVINGS 512
00055 #define OUT_OF_SPACE 2
00056
00057 struct dirent dir_ent[MAX_ENTRIES];
00058 int entries = 0;
00059
00060 struct sorted {
00061 int mode;
00062 char *namep;
00063 long acctime;
00064 long modtime;
00065 } sorted[MAX_ENTRIES];
00066
00067 char copybuf[COPY_SIZE];
00068 char *pname;
00069 int dflag, jflag, mflag, nflag, oflag, rflag, sflag, tflag, vflag, zflag;
00070
00071 extern int errno;
00072 extern char **environ;
00073
00074 _PROTOTYPE(int main, (int argc, char **argv));
00075 _PROTOTYPE(void maketarget, (char *dir2));
00076 _PROTOTYPE(int make_dir, (char *dir));
00077 _PROTOTYPE(int stat_all, (char *dir1, int n));
00078 _PROTOTYPE(void sort_dir, (int m));
00079 _PROTOTYPE(void process, (int m, char *dir1, char *dir2));
00080 _PROTOTYPE(void swap, (struct sorted *sp1, struct sorted *sp2));
00081 _PROTOTYPE(int copy, (char *dir1, struct sorted *sp, char *cbuf2));
00082 _PROTOTYPE(int zcopy, (char *src, char *targ));
00083 _PROTOTYPE(void copydir, (char *dir1, char *dir2, char *namep));
00084 _PROTOTYPE(void newdisk, (char *dir));
00085 _PROTOTYPE(void usage, (void));
00086 _PROTOTYPE(void error, (int type, char *s1, char *s2, char *s3));
00087
00088 int main(argc, argv)
00089 int argc;
00090 char *argv[];
00091 {
00092 int ct, n, m, fd;
00093 char *dir1, *dir2, *cp, c;
00094 struct stat s;
00095 struct dirent *e;
00096 DIR *DIR1, *DIR2;
00097
00098 (void) sync();
00099
00100
00101 if ((pname = strrchr(argv[0], '/')) == (char *)NULL)
00102 pname = argv[0];
00103 else
00104 pname++;
00105 if (argc < 3 || argc > 4) usage();
00106 if (argc == 4) {
00107 cp = argv[1];
00108 if (*cp++ != '-') usage();
00109 while ((c = *cp++) != '\0') {
00110 switch (c) {
00111 case 'd': dflag++; break;
00112 case 'j': jflag++; break;
00113 case 'm': mflag++; break;
00114 case 'n': nflag++; break;
00115 case 'o': oflag++; break;
00116 case 's': sflag++; break;
00117 case 'r': rflag++; break;
00118 case 't': tflag++; break;
00119 case 'v': vflag++; break;
00120 case 'z': zflag++; break;
00121 default: usage();
00122 }
00123 }
00124 dir1 = argv[2];
00125 dir2 = argv[3];
00126 } else {
00127 dir1 = argv[1];
00128 dir2 = argv[2];
00129 }
00130 if (!strcmp(pname, "restore") && !rflag) rflag++;
00131
00132
00133 if (stat(dir1, &s) < 0) error(FATAL, "cannot stat ", dir1, "");
00134 if ((s.st_mode & S_IFMT) != S_IFDIR) error(FATAL, "non-directory ", dir1, "");
00135
00136
00137 if(!(DIR1 = opendir(dir1))) {
00138 perror(dir1);
00139 return 1;
00140 }
00141 while(entries < MAX_ENTRIES && (e=readdir(DIR1)))
00142 memcpy(&dir_ent[entries++], e, sizeof(*e));
00143 closedir(DIR1);
00144 if (entries == MAX_ENTRIES)
00145 error(FATAL, "directory ", dir1, " is too large");
00146
00147
00148 maketarget(dir2);
00149
00150
00151 n = entries;
00152 m = stat_all(dir1, n);
00153
00154
00155 sort_dir(m);
00156
00157
00158 process(m, dir1, dir2);
00159 return(0);
00160 }
00161
00162
00163 void maketarget(dir2)
00164 char *dir2;
00165 {
00166
00167
00168 char *p, c, dbuf[MAX_PATH];
00169
00170 if (access(dir2, 6) == 0)
00171 return;
00172 if (make_dir(dir2) == 0) return;
00173
00174
00175 strcpy(dbuf, dir2);
00176 p = dbuf + 1;
00177 while (1) {
00178 while (*p != '/' && *p != '\0') p++;
00179 c = *p;
00180 *p = 0;
00181 make_dir(dbuf);
00182 if (c == '\0') return;
00183 *p = c;
00184 p++;
00185 }
00186 }
00187
00188 int make_dir(dir)
00189 char *dir;
00190 {
00191
00192 int pid, status;
00193
00194 if ((pid = fork()) < 0)
00195 error(FATAL, "cannot fork off mkdir to create ", dir, "");
00196 if (pid > 0) {
00197
00198 wait(&status);
00199 return(status);
00200 } else {
00201
00202 close(2);
00203 execle("/bin/mkdir", "mkdir", dir, (char *) 0, environ);
00204 execle("/usr/bin/mkdir", "mkdir", dir, (char *) 0, environ);
00205 error(FATAL, "cannot execute mkdir", "", "");
00206 }
00207 return(0);
00208 }
00209
00210
00211 int stat_all(dir1, n)
00212 char *dir1;
00213 int n;
00214 {
00215
00216
00217
00218
00219 int i, j;
00220 char cbuf[MAX_PATH];
00221 struct stat s;
00222
00223 for (i = 0; i < n; i++) {
00224
00225 if (strcmp(dir_ent[i].d_name, ".") == 0) dir_ent[i].d_ino = 0;
00226 if (strcmp(dir_ent[i].d_name, "..") == 0) dir_ent[i].d_ino = 0;
00227 if (dir_ent[i].d_ino == 0) continue;
00228
00229
00230 snprintf(cbuf, sizeof(cbuf), "%s/%s", dir1, dir_ent[i].d_name);
00231 if (stat(cbuf, &s) < 0) {
00232 error(NONFATAL, "cannot stat ", cbuf, "");
00233 dir_ent[i].d_ino = 0;
00234 continue;
00235 }
00236 sorted[i].mode = s.st_mode;
00237 sorted[i].acctime = s.st_atime;
00238 sorted[i].modtime = s.st_mtime;
00239 sorted[i].namep = dir_ent[i].d_name;
00240 sorted[i].namep[NAME_SIZE-1] = '\0';
00241 }
00242
00243
00244 j = 0;
00245 for (i = 0; i < n; i++) {
00246 if (dir_ent[i].d_ino != 0) {
00247 sorted[j] = sorted[i];
00248 j++;
00249 }
00250 }
00251 return(j);
00252 }
00253
00254
00255 void sort_dir(m)
00256 int m;
00257 {
00258
00259
00260 struct sorted *sp1, *sp2;
00261
00262 for (sp1 = &sorted[0]; sp1 < &sorted[m - 1]; sp1++) {
00263 for (sp2 = sp1 + 1; sp2 < &sorted[m]; sp2++) {
00264 if (strcmp(sp1->namep, sp2->namep) > 0)
00265 swap(sp1, sp2);
00266 }
00267 }
00268 }
00269
00270
00271 void process(m, dir1, dir2)
00272 int m;
00273 char *dir1, *dir2;
00274 {
00275
00276
00277
00278
00279
00280 int er, fmode, res;
00281 struct sorted *sp;
00282 struct stat s;
00283 char cbuf[MAX_PATH];
00284
00285 for (sp = &sorted[0]; sp < &sorted[m]; sp++) {
00286 int namlen;
00287 fmode = sp->mode & S_IFMT;
00288 if (fmode == S_IFREG) {
00289
00290 snprintf(cbuf, sizeof(cbuf), "%s/%s", dir2, sp->namep);
00291 namlen = strlen(sp->namep);
00292
00293 if (zflag && !rflag && strncmp((sp->namep + namlen - 2), ".Z", (size_t)2)
00294 && (namlen <= (NAME_SIZE - 2)))
00295 strncat(cbuf, ".Z", (size_t)2);
00296 if (zflag && rflag && !strncmp((sp->namep + namlen - 2), ".Z", (size_t)2))
00297 cbuf[strlen(cbuf) - 2] = '\0';
00298 er = stat(cbuf, &s);
00299 if (er < 0 || sp->modtime > s.st_mtime) {
00300 res = copy(dir1, sp, cbuf);
00301 } else {
00302 res = NONFATAL;
00303 }
00304
00305
00306 if (res == OUT_OF_SPACE) {
00307 printf("Out of space while copying to %s\n", cbuf);
00308
00309 if (mflag == 0)
00310 error(FATAL, "Quitting, disk full", "", "");
00311
00312
00313 newdisk(dir2);
00314 sp--;
00315 continue;
00316 }
00317 } else if (fmode == S_IFDIR) {
00318
00319 copydir(dir1, dir2, sp->namep);
00320 } else if (fmode == S_IFBLK || fmode == S_IFCHR) {
00321
00322 strncpy(cbuf, sp->namep, sizeof(cbuf));
00323 printf("%s is special file. Not backed up.\n", cbuf);
00324 }
00325 }
00326 }
00327
00328
00329
00330
00331 void swap(sp1, sp2)
00332 struct sorted *sp1, *sp2;
00333 {
00334
00335
00336 struct sorted d;
00337
00338 d = *sp1;
00339 *sp1 = *sp2;
00340 *sp2 = d;
00341 }
00342
00343
00344 int copy(dir1, sp, cbuf2)
00345 struct sorted *sp;
00346 char *dir1, *cbuf2;
00347 {
00348
00349
00350 int fd1, fd2, nr, nw, res, n;
00351 char cbuf1[MAX_PATH], *p;
00352 #ifdef NARROW
00353 char *msg = (rflag || strcmp(pname, "backup")) ? "Restored" : "Backing up";
00354 #endif
00355
00356
00357 p = sp->namep;
00358 n = strlen(p);
00359 if (n > NAME_SIZE) n = NAME_SIZE;
00360 if (jflag) {
00361 if (strcmp(p, "a.out") == 0) return(0);
00362 if (strcmp(p, "core") == 0) return (0);
00363 if (strcmp(p + n - 2, ".Z") == 0) return (0);
00364 if (strcmp(p + n - 4, ".bak") == 0) return (0);
00365 if (strcmp(p + n - 4, ".log") == 0) return (0);
00366 }
00367 if (oflag) {
00368 if (strcmp(p + n - 2, ".o") == 0) return(0);
00369 }
00370 if (sflag) {
00371 if (strcmp(p + n - 2, ".s") == 0) return(0);
00372 }
00373 res = 0;
00374 if (dflag) return(0);
00375 strcpy(cbuf1, dir1);
00376 strncat(cbuf1, "/", (size_t)1);
00377 strncat(cbuf1, sp->namep, (size_t)NAME_SIZE);
00378
00379
00380 fd1 = open(cbuf1, O_RDONLY);
00381 if (fd1 < 0) {
00382 error(NONFATAL, "cannot open ", cbuf1, "");
00383 return(res);
00384 }
00385 fd2 = creat(cbuf2, (sp->mode | S_IWUSR) & 07777);
00386 if (fd2 < 0) {
00387 if (errno == ENFILE) {
00388 close(fd1);
00389 return(OUT_OF_SPACE);
00390 }
00391 error(NONFATAL, "cannot create ", cbuf2, "");
00392 close(fd1);
00393 return(res);
00394 }
00395
00396
00397 if (!rflag && strncmp((sp->namep + n - 2), ".Z", (size_t)2) ||
00398 rflag && !strncmp((sp->namep + n - 2), ".Z", (size_t)2)) {
00399 if (zflag && (rflag || (n <= (NAME_SIZE - 2)))) {
00400 close(fd1);
00401 close(fd2);
00402 res = zcopy(cbuf1, cbuf2);
00403 if (tflag) utime(cbuf2, (struct utimbuf *) & (sp->acctime));
00404 if (res != 0) unlink(cbuf2);
00405 #ifdef NARROW
00406 if (vflag && res == 0) printf("%s %s\n", msg, cbuf1);
00407 #else
00408 if (vflag && res == 0) {
00409 printf("%-37.37s -> %-37.37s\n", cbuf1, cbuf2);
00410 if (strlen(cbuf1) > 37 || strlen(cbuf2) > 37)
00411 printf("%37.37s %37.37s\n",
00412 (strlen(cbuf1) > 37) ? (cbuf1 + 37) : "",
00413 (strlen(cbuf2) > 37) ? (cbuf2 + 37) : "");
00414 }
00415 #endif
00416 return(res);
00417 }
00418 }
00419 while (1) {
00420 nr = read(fd1, copybuf, COPY_SIZE);
00421 if (nr == 0) break;
00422 if (nr < 0) {
00423 error(NONFATAL, "read error on ", cbuf1, "");
00424 res = EIO;
00425 break;
00426 }
00427 nw = write(fd2, copybuf, nr);
00428 if (nw < 0) {
00429 if (errno == ENOSPC) {
00430
00431 res = OUT_OF_SPACE;
00432 break;
00433 }
00434
00435
00436 error(NONFATAL, "write error on ", cbuf2, "");
00437 res = EIO;
00438 break;
00439 }
00440 }
00441 if (res == 0) {
00442 #ifdef NARROW
00443 if (vflag) printf("%s %s\n", msg, cbuf1);
00444 #else
00445 if (vflag) {
00446 printf("%-37.37s -> %-37.37s\n", cbuf1, cbuf2);
00447 if (strlen(cbuf1) > 37 || strlen(cbuf2) > 37)
00448 printf("%37.37s %37.37s\n",
00449 (strlen(cbuf1) > 37) ? (cbuf1 + 37) : "",
00450 (strlen(cbuf2) > 37) ? (cbuf2 + 37) : "");
00451 }
00452 #endif
00453 } else {
00454 unlink(cbuf2);
00455 }
00456 close(fd1);
00457 close(fd2);
00458 if (tflag) utime(cbuf2, (struct utimbuf *) & (sp->acctime));
00459 return(res);
00460 }
00461
00462
00463 int zcopy(src, targ)
00464 char *src, *targ;
00465 {
00466
00467 int pid, status, res, s;
00468 char fbuf[20];
00469
00470
00471 strcpy(fbuf, "-c");
00472 if (rflag)
00473 strcat(fbuf, "d");
00474 else
00475 strcat(fbuf, "f");
00476
00477 if ((pid = fork()) < 0) error(FATAL, "cannot fork", "", "");
00478 if (pid > 0) {
00479 wait(&status);
00480
00481
00482 res = (status == 0 || status == NO_SAVINGS ? 0 : OUT_OF_SPACE);
00483 return(res);
00484 } else {
00485
00486 close(1);
00487 s = open(targ, O_RDWR);
00488 if (s < 0) error(FATAL, "cannot write on ", "targ", "");
00489 execle("/usr/bin/gzip", "gzip", fbuf, src, (char *)0, environ);
00490 execle("/usr/local/bin/gzip", "gzip", fbuf, src, (char *)0, environ);
00491 execle("/bin/compress", "compress", fbuf, src, (char *)0, environ);
00492 execle("/usr/bin/compress", "compress", fbuf, src, (char *)0, environ);
00493 error(FATAL, "cannot exec gzip or compress", "", "");
00494 }
00495 return(0);
00496 }
00497
00498
00499 void copydir(dir1, dir2, namep)
00500 char *dir1, *dir2, *namep;
00501 {
00502
00503
00504 int pid, status;
00505 char fbuf[20], d1buf[MAX_PATH], d2buf[MAX_PATH];
00506
00507 if (nflag) return;
00508
00509 fbuf[0] = '\0';
00510
00511
00512 if (jflag || mflag || oflag || rflag || sflag || tflag || vflag || zflag)
00513 strcpy(fbuf, "-");
00514 if (jflag) strcat(fbuf, "j");
00515 if (mflag) strcat(fbuf, "m");
00516 if (oflag) strcat(fbuf, "o");
00517 if (rflag) strcat(fbuf, "r");
00518 if (sflag) strcat(fbuf, "s");
00519 if (tflag) strcat(fbuf, "t");
00520 if (vflag) strcat(fbuf, "v");
00521 if (zflag) strcat(fbuf, "z");
00522 snprintf(d1buf, sizeof(d1buf), "%s/%s", dir1, namep);
00523 snprintf(d2buf, sizeof(d2buf), "%s/%s", dir2, namep);
00524
00525 if ((pid = fork()) < 0) error(FATAL, "cannot fork", "", "");
00526 if (pid > 0) {
00527
00528 wait(&status);
00529 return;
00530 }
00531
00532 if (fbuf[0] == '-') {
00533 execle(pname, pname, fbuf, d1buf, d2buf, (char *) 0, environ);
00534 execle("/bin/backup", "backup", fbuf, d1buf, d2buf, (char *)0,environ);
00535 execle("/usr/bin/backup","backup",fbuf,d1buf,d2buf,(char *)0,environ);
00536 error(FATAL, "cannot recursively exec backup", "", "");
00537 } else {
00538 execle(pname, pname, d1buf, d2buf, (char *) 0, environ);
00539 execle("/bin/backup", "backup", d1buf, d2buf, (char *)0,environ);
00540 execle("/usr/bin/backup","backup", d1buf, d2buf, (char *)0,environ);
00541 error(FATAL, "cannot recursively exec backup", "", "");
00542 }
00543 }
00544
00545 void newdisk(dir)
00546 char *dir;
00547 {
00548
00549
00550
00551
00552
00553 int pid, status;
00554
00555 printf("\nDiskette full. Please do the following:\n");
00556 printf(" 1. Unmount the diskette using /etc/umount\n");
00557 printf(" 2. Physically replace the diskette by the next one.\n");
00558 printf(" 3. Mount the new diskette using /etc/mount\n");
00559 printf(" 4. Type CTRL-D to return to the backup/restore program\n");
00560
00561 if ((pid = fork()) < 0) error(FATAL, "cannot fork", "", "");
00562 if (pid > 0) {
00563 wait(&status);
00564 maketarget(dir);
00565 } else {
00566 execle("/bin/sh", "sh", "-i", (char *) 0, environ);
00567 execle("/usr/bin/sh", "sh", "-i", (char *) 0, environ);
00568 error(FATAL, "cannot execute shell to ask for new diskette", "", "");
00569 }
00570 }
00571
00572 void usage()
00573 {
00574 fprintf(stderr, "Usage: %s [-djmnorstvz] dir1 dir2\n", pname);
00575 exit(2);
00576 }
00577
00578
00579 void error(type, s1, s2, s3)
00580 int type;
00581 char *s1, *s2, *s3;
00582 {
00583 fprintf(stderr, "%s: %s%s%s\n", pname, s1, s2, s3);
00584
00585 if (type == NONFATAL)
00586 return;
00587 else
00588 exit(type);
00589 }