date and time created 84/02/17 10:33:57 by ralph
[unix-history] / usr / src / local / local.cmd / dl.c
CommitLineData
07e1a339
RC
1static char *sccsid = "@(#)dl.c 4.1\t%G%";
2
3#include <stdio.h>
4#include <sys/param.h>
5#include <sys/stat.h>
6#include <sys/dir.h>
7#include <errno.h>
8#include <signal.h>
9
10#define DELIM '/'
11#define MODEBITS 07777
12#define ISDIR(st) (((st).st_mode&S_IFMT) == S_IFDIR)
13#define ISLNK(st) (((st).st_mode&S_IFMT) == S_IFLNK)
14#define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG)
15#define ISDEV(st) \
16 (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
17
18struct stat s1, s2, buf;
19extern unsigned errno;
20int errcode;
21char *sprintf();
22char *path;
23char *path2;
24char line[1024];
25int cflag = 0; /* "copy" - same as cp */
26int dflag = 0; /* "debug" - enable trace printf statements */
27int fflag = 0; /* "force" option: override protection, no messages */
28int mflag = 0; /* "move" - same as mv */
29int cs = 0; /* flag used with cflag to prevent endless recursion */
30int ms = 0; /* flag used with mflag to prevent endless recursion */
31int tflag = 0; /* restore original time stamp */
32
33main(argc, argv) /* dl.c - delete, undelete, move, copy */
34char *argv[];
35{
36 register char *arg;
37 char *s;
38 int mode;
39 int aflg = 0; /* "all" option: undelete all deleted files */
40 int iflg = 0; /* "interactive" option: send messages to user */
41 int rflg = 0; /* "recursive" opt., used only with n */
42 int sflg = 0; /* do not delete previous dlsave file */
43 int uflg = 0; /* undelete named files and/or directories */
44 int nflg = 0; /* do not provide back-up files */
45
46 if (isatty(0) == 0) /* if standard i/o is not a terminal, */
47 fflag++; /* turn on the f flag */
48
49 if (strcmp(*argv,"ud") == 0)
50 uflg++;
51
52 if (strcmp(*argv,"copy") == 0)
53 cflag++;
54
55 if (strcmp(*argv,"move") == 0)
56 mflag++;
57
58 while(argc>1 && argv[1][0]=='-') {
59 arg = *++argv;
60 argc--;
61
62 /*
63 * all arguments following a null option (- ) are
64 * treated as file names, so that file names may
65 * begin with a minus sign (-).
66 */
67 if (*(arg+1) == '\0') break;
68
69 while(*++arg != '\0')
70 switch(*arg) {
71 case 'a': /* "all" */
72 aflg++;
73 break;
74 case 'c': /* "copy" */
75 cflag++;
76 break;
77 case 'd': /* "debug" */
78 dflag++;
79 break;
80 case 'f': /* "force" */
81 fflag++;
82 break;
83 case 'i': /* "interactive" */
84 iflg++;
85 break;
86 case 'r': /* "recursive" */
87 rflg++;
88 break;
89 case 's': /* "save" */
90 sflg++;
91 break;
92 case 't': /* "time" stamp */
93 tflag++;
94 break;
95 case 'u': /* "undelete" */
96 uflg++;
97 break;
98 case 'm': /* "move" */
99 mflag++;
100 break;
101 case 'n': /* "not save" */
102 nflg++;
103 break;
104 default:
105 printf("dl: unknown option %s\n", *argv);
106 exit(1);
107 }
108 }
109 if (cflag || mflag || nflg) sflg++;
110 /*
111 * set up home directory pathname
112 */
113 setpath();
114 /*
115 * process "undelete all" request
116 */
117 if(aflg) {
118 undelete_all(iflg);
119 exit;
120 }
121 /*
122 * remove previously saved files unless "save" option,
123 * or ud or rm mode
124 */
125 if(!sflg && !uflg)
126 dldir(path,0);
127 if(!nflg && lstat(path,&buf) != 0) {
128 /*
129 * set up .dlsave directory
130 */
131 mode = 0777;
132 if (mkdir(path,mode) != 0) {
133 fprintf(stderr,"dl: cannot mkdir ~/.dlsave\n");
134 perror(s);
135 exit(1);
136 }
137 }
138 while(--argc > 0) {
139 if(!strcmp(*++argv, "..")) {
140 if(!fflag)
141 fprintf(stderr, "dl: cannot remove `..'\n");
142 continue;
143 }
144 /*
145 * process "undelete" request(s)
146 */
147 if(uflg) {
148 undelete(*argv,iflg);
149 exit;
150 }
151 else {
152 /*
153 * process delete request(s)
154 */
155 if (cflag) {
156 copy(*argv,argv[argc-1],iflg,rflg);
157 exit(errcode);
158 }
159 if (mflag) {
160 move(*argv,argv[argc-1],iflg);
161 exit(errcode);
162 }
163 if (nflg)
164 rm(*argv, iflg, rflg);
165 else
166 dl(*argv, iflg);
167 }
168 }
169 exit(errcode);
170}
171
172setpath()
173{
174 char *home;
175 char *suffix;
176 char *getenv();
177
178 home = "HOME";
179 if ((path=getenv(home)) == NULL) {
180 fprintf(stderr,"dl: getenv failed\n");
181 exit(1);
182 }
183 suffix = "/.dlsave";
184 strcat(path,suffix);
185 return;
186}
187
188package(argu)
189char argu[];
190{
191 register int i, j, k;
192 char *slash, *slashdot;
193 char *place;
194 char line2[512];
195
196 place = line2;
197 strcpy(place,argu);
198 path2 = line;
199 strcpy(path2,path);
200 slashdot = "/.#";
201 strcat(path2,slashdot);
202 i = strlen(argu);
203 slash = "/";
204 k = 0;
205 for (j=0;j<i;j++) {
206 if (place[j] == *slash) {
207 k = j + 1;
208 }
209 }
210 strcat(path2,argu+k);
211 return;
212}
213
214undelete_all(iflg)
215{
216 struct direct *dp;
217 DIR *dirp;
218 char *filename;
219 int x;
220
221 /*
222 * undelete all saved files (a option)
223 */
224 if((dirp = opendir(path)) == NULL) {
225 if(!fflag)
226 printf("uda: cannot read %s?\n", path);
227 exit(1);
228 }
229 while((dp = readdir(dirp)) != NULL) {
230 if(dp->d_ino != 0 && !dotname(dp->d_name)) {
231 filename = (dp->d_name)+2;
232 package(filename);
233 if(iflg) {
234 printf("uda: undelete %s?", filename);
235 if (!yes())
236 goto no;
237 }
238 if(lstat(filename, &buf) == 0) {
239 printf("uda: %s exists. Override?", filename);
240 if(!yes())
241 goto no;
242 }
243 x = move(path2,filename,0);
244 if(iflg) {
245 if (x >= 0)
246 printf("uda: %s undeleted.\n", filename);
247 else
248 printf("uda: unable to undelete %s\n", filename);
249 }
250no: continue;
251 }
252 }
253 closedir(dirp);
254 return;
255}
256
257undelete(arg,iflg)
258char arg[];
259{
260 struct stat buf1, buf2;
261 int x;
262
263 /*
264 * undelete a saved file (u option)
265 */
266 package(arg);
267 if(lstat(path2, &buf1)) {
268 if (!fflag)
269 printf("ud: %s nonexistent\n", path2);
270 ++errcode;
271 return;
272 }
273 if(iflg) {
274 printf("ud: undelete %s?", arg);
275 if(!yes())
276 return;
277 }
278 if(lstat(arg, &buf2) == 0) {
279 printf("ud: %s exists: overwrite?", arg);
280 if(!yes())
281 return;
282 }
283 x = move(path2,arg,0);
284 if(iflg) {
285 if (x >= 0)
286 printf("ud: %s undeleted.\n", arg);
287 else
288 printf("ud: unable to undelete %s\n", arg);
289 }
290 return;
291}
292
293rm(arg, iflg, rflg)
294char arg[];
295{
296 if (dflag) printf("rm entered: arg=%s fflag=%d iflg=%d rflg=%d\n",arg,fflag,iflg,rflg);
297 if(lstat(arg, &buf)) {
298 if (!fflag)
299 printf("rm: %s nonexistent\n", arg);
300 ++errcode;
301 return;
302 }
303 /*
304 * unlink file named by arg
305 */
306 if ((buf.st_mode&S_IFMT) == S_IFDIR || rflg) {
307 if(iflg) {
308 printf("rm: remove directory %s?", arg);
309 if(!yes())
310 return;
311 }
312 dldir(arg, iflg);
313 return;
314 }
315 if (!fflag && iflg) {
316 printf("rm: remove %s?", arg);
317 if (!yes())
318 return;
319 }
320 else if (!fflag) {
321 if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, 02) < 0) {
322 printf("rm: override protection %o for %s?\n",buf.st_mode&0777,arg);
323 if (!yes())
324 return;
325 }
326 }
327 if (unlink(arg) && !fflag) {
328 printf ("rm: %s not removed.\n",arg);
329 ++errcode;
330 }
331 else {
332 if (!fflag && iflg)
333 printf ("rm: %s removed.\n",arg);
334 }
335 return;
336}
337
338dl(arg, iflg)
339char arg[];
340{
341 /*
342 * move the argument (file or directory) to
343 * .dlsave directory in user's home directory
344 */
345 if (dflag) printf("dl entered: arg=%s fflag=%d iflg=%d\n",arg,fflag,iflg);
346 package(arg);
347 move(arg,path2,iflg);
348 return;
349}
350
351dldir(arg, iflg)
352char arg[];
353{
354 struct stat buf1, buf2;
355 struct direct *dp;
356 DIR *dirp;
357 char name[BUFSIZ];
358
359 if (dflag) printf("dldir entered: arg=%s fflag=%d iflg=%d\n",arg,fflag,iflg);
360 if(lstat(arg, &buf1)) {
361 if (!fflag && iflg)
362 printf("dldir: %s nonexistent\n", arg);
363 ++errcode;
364 return;
365 }
366 /*
367 * if the argument is a directory,
368 * recursively remove the directory's contents
369 * and then the directory.
370 */
371 if ((buf1.st_mode&S_IFMT) == S_IFDIR) {
372 if (access(arg, 02) < 0) {
373 if(!fflag) {
374 printf("dldir: %s not accessable\n",arg);
375 }
376 errcode++;
377 return;
378 }
379 if((dirp = opendir(arg)) == NULL)
380 exit(1);
381 while((dp = readdir(dirp)) != NULL) {
382 if(dp->d_ino != 0 && !dotname(dp->d_name)) {
383 sprintf(name, "%s/%s", arg, dp->d_name);
384 if (dflag) printf("dldir: name= %s\n",name);
385 if(lstat(name, &buf2)) {
386 if (!fflag)
387 printf("dldir: %s nonexistent\n", name);
388 ++errcode;
389 return;
390 }
391 if ((buf2.st_mode&S_IFMT) == S_IFDIR) {
392 if(!fflag && iflg) {
393 printf("dldir: delete directory %s?", name);
394 if(!yes())
395 return;
396 }
397 dldir(name, iflg);
398 }
399 else {
400 if(!fflag && iflg) {
401 printf("dldir: delete file %s?", name);
402 if(!yes())
403 return;
404 }
405 /*
406 * permanently remove the file
407 */
408 if (unlink(name)) {
409 if (!fflag)
410 printf("dldir: %s not removed\n", name);
411 ++errcode;
412 }
413 else {
414 if (!fflag && iflg)
415 printf("dldir: %s removed.\n", name);
416 }
417 }
418 }
419 }
420 closedir(dirp);
421 if (dotname(arg))
422 return;
423 if (rmdir(arg) < 0) {
424 if(!fflag && iflg) {
425 fprintf(stderr, "dldir: rmdir:");
426 perror(arg);
427 }
428 errcode++;
429 }
430 else {
431 if(!fflag && iflg)
432 printf("dldir: directory %s removed.\n",arg);
433 }
434 return;
435 }
436}
437
438dotname(s)
439char *s;
440{
441 if(s[0] == '.')
442 if(s[1] == '.')
443 if(s[2] == '\0')
444 return(1);
445 else
446 return(0);
447 else if(s[1] == '\0')
448 return(1);
449 return(0);
450}
451
452yes()
453{
454 int i, b;
455
456 i = b = getchar();
457 while(b != '\n' && b != EOF)
458 b = getchar();
459 return(i == 'y');
460}
461
462move(source, target, iflag)
463 char *source, *target;
464{
465 int targetexists;
466 int sw = 0;
467
468 if (dflag) printf("move entered: source=%s target=%s fflag=%d iflag=%d\n",source,target,fflag,iflag);
469 if (lstat(source, &s1) < 0) {
470 if (!fflag)
471 error("cannot access %s", source);
472 return (1);
473 }
474 if (dflag) printf("move: lstat(%s) successful\n",source);
475 /*
476 * First, try to rename source to target.
477 */
478 targetexists = lstat(target, &s2) >= 0;
479 if (targetexists) {
480 if (dflag) printf("move: lstat(%s) successful\n",target);
481 if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
482 if (!fflag)
483 error("%s and %s are identical", source, target);
484 return (1);
485 }
486 if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) {
487 if (query("override protection %o for %s? ",
488 s2.st_mode & MODEBITS, target) == 0)
489 return (1);
490 sw++;
491 }
492 if (mflag && ms == 0) {
493 if (ISREG(s2)) {
494 if (!fflag && sw == 0) {
495 printf("overwrite file %s?", target);
496 if(!yes())
497 return;
498 }
499 ms = 1;
500 dl (target, 0);
501 }
502 else
503 if (s1.st_dev != s2.st_dev && ISDIR(s2))
504 goto copyit;
505 }
506 }
507 if (!fflag && iflag && !mflag) {
508 if (ISDIR(s1))
509 printf("dl: delete directory %s?", source);
510 else
511 printf("dl: delete file %s?", source);
512 if(!yes())
513 return;
514 }
515 if(dflag) printf("move(1)rename: source=%s, target=%s\n",source, target);
516 if (rename(source, target) >= 0) {
517 if (!fflag && iflag && !mflag)
518 printf("dl: %s deleted. \n",source);
519 if (dflag) printf("move: %s renamed %s.\n",source,target);
520 return (0);
521 }
522 if (dflag) printf("move/rename: errno=%d\n",errno);
523 if (errno != EXDEV) {
524 if (!fflag && iflag) {
525 Perror2(source, "rename");
526 }
527 goto copyit;
528 }
529 if (targetexists && unlink(target) < 0) {
530 if(!fflag)
531 error("cannot unlink %s", target);
532 return (1);
533 }
534 if (dflag) printf("move: target unlinked\n");
535
536 /*
537 * If file or directory cannot be renamed:
538 * If directory, copy it with r option
539 * and delete the source
540 */
541copyit: if (ISDIR(s1)) {
542 if (dflag) printf("move: directory copy %s to %s\n",source,target);
543 copy (source, target, iflag, 1);
544 dldir (source, iflag);
545 return(0);
546 }
547
548 /*
549 * If link, recreate symbolic link
550 */
551 if (ISLNK(s1)) {
552 register m;
553 char symln[MAXPATHLEN];
554
555 if (readlink(source, symln, sizeof (symln)) < 0) {
556 if (!fflag)
557 Perror(source);
558 return (1);
559 }
560 m = umask(~(s1.st_mode & MODEBITS));
561 if (symlink(symln, target) < 0) {
562 if (!fflag)
563 Perror(target);
564 return (1);
565 }
566 if (dflag) printf("move: symlink to target successful\n");
567 (void) umask(m);
568 goto cleanup;
569 }
570
571 /*
572 * If device
573 */
574 if (ISDEV(s1)) {
575 if (mknod(target, s1.st_mode, s1.st_rdev) < 0) {
576 if (!fflag)
577 Perror(target);
578 return (1);
579 }
580 if (dflag) printf("move: mknod for target successful\n");
581 goto cleanup;
582 }
583
584 /*
585 * If regular file, copy it
586 */
587 if (ISREG(s1)) {
588 if(dflag) printf("move: file copy %s to %s\n",source,target);
589 copy(source, target, iflag, 0);
590 goto cleanup;
591 }
592
593 if (!fflag)
594 error("%s: unknown file type %o", source, s1.st_mode);
595 return (1);
596
597 /*
598 * If a move has been successful, erase the source
599 */
600cleanup:
601 if (dflag) printf("move: cleanup\n");
602 if (unlink(source) < 0) {
603 if (!fflag)
604 error("cannot unlink %s", source);
605 return (1);
606 }
607 if (dflag) printf("move: %s unlinked.\n",source);
608 if (!fflag && iflag && !mflag)
609 printf("dl: %s deleted.\n",source);
610 return (0);
611}
612
613/*VARARGS*/
614query(prompt, a1, a2)
615 char *a1;
616{
617 register char i, c;
618
619 fprintf(stderr, prompt, a1, a2);
620 i = c = getchar();
621 while (c != '\n' && c != EOF)
622 c = getchar();
623 return (i == 'y');
624}
625
626error(fmt, a1, a2)
627 char *fmt;
628{
629 fprintf(stderr, "dl: ");
630 fprintf(stderr, fmt, a1, a2);
631 fprintf(stderr, "\n");
632}
633
634Perror(s)
635 char *s;
636{
637 char buf[MAXPATHLEN + 10];
638
639 sprintf(buf, "move: %s", s);
640 perror(buf);
641}
642
643Perror2(s1, s2)
644 char *s1, *s2;
645{
646 char buf[MAXPATHLEN + 20];
647
648 sprintf(buf, "dl: %s: %s", s1, s2);
649 perror(buf);
650}
651
652#define BSIZE 8192
653
654char *rindex();
655
656copy(from, to, iflag, rflag)
657 char *from, *to;
658{
659 int fold, fnew, n;
660 char *last, destname[BSIZE], buf[BSIZE];
661 struct stat stfrom, stto;
662 time_t tv[2];
663
664 if (dflag) printf("copy entered: from=%s to=%s iflag=%d rflag=%d\n",from,to,iflag,rflag);
665 fold = open(from, 0);
666 if (fold < 0) {
667 Cerror(from,fflag);
668 return (1);
669 }
670 if (fstat(fold, &stfrom) < 0) {
671 Cerror(from,fflag);
672 (void) close(fold);
673 return (1);
674 }
675 if (dflag) printf("copy: fstat(%s) OK.\n",from);
676 if (stat(to, &stto) >= 0 &&
677 (stto.st_mode&S_IFMT) == S_IFDIR) {
678 last = rindex(from, '/');
679 if (last) last++; else last = from;
680 if (strlen(to) + strlen(last) >= BSIZE - 1) {
681 fprintf(stderr, "cp: %s/%s: Name too long", to, last);
682 (void) close(fold);
683 return(1);
684 }
685 (void) sprintf(destname, "%s/%s", to, last);
686 if (dflag) printf("copy: stat %s & %s is dir., to=%s.\n",to,to,destname);
687 to = destname;
688 }
689 if (!rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
690 fprintf(stderr, "cp: %s is a directory, and option -r not chosen. Job aborted.\n", from);
691 return(1);
692 }
693 if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
694 (void) close(fold);
695 if (dflag) printf("copy: rflag & from is dir., %s closed.\n",from);
696 if (stat(to, &stto) < 0) {
697 if (mkdir(to, (int)stfrom.st_mode) < 0) {
698 Cerror(to,fflag);
699 return (1);
700 }
701 if (dflag) printf("copy: stat(%s) failed & mkdir % successful.\n",to,to);
702 }
703 else {
704 if (!fflag) {
705 if ((stto.st_mode&S_IFMT) == S_IFDIR) {
706 dl(to, iflag);
707 }
708 else {
709 fprintf(stderr, "cp: %s: Not a directory.\n", to);
710 return (1);
711 }
712 }
713 }
714 if (dflag) printf("copy: return with rcopy(%s,%s,%d,%d)\n",from,to,iflag,rflag);
715 return (rcopy(from, to, iflag, rflag));
716 }
717 if (stat(to, &stto) >= 0) {
718 if (dflag) printf("cp:stat(%s) o.k.\n",to);
719 if (stfrom.st_dev == stto.st_dev &&
720 stfrom.st_ino == stto.st_ino) {
721 fprintf(stderr, "cp: Cannot copy file to itself.\n");
722 (void) close(fold);
723 return (1);
724 }
725 if (cflag && cs == 0) {
726 if (!fflag)
727 fprintf (stderr, "cp: %s exists: overwrite? ", to);
728 if (!yes()) {
729 (void) close(fold);
730 return(1);
731 }
732 dl(to, 0);
733 cs = 1;
734 }
735 }
736 fnew = creat(to, (int)stfrom.st_mode);
737 if (fnew < 0) {
738 Cerror(to,fflag);
739 (void) close(fold); return(1);
740 }
741 if (dflag) printf("copy: creat(%s,%d) successful.\n",to,stfrom.st_mode);
742 for (;;) {
743 n = read(fold, buf, BSIZE);
744 if (n == 0)
745 break;
746 if (n < 0) {
747 Cerror(from,fflag);
748 (void) close(fold); (void) close(fnew); return (1);
749 }
750 if (write(fnew, buf, n) != n) {
751 Cerror(to,fflag);
752 (void) close(fold); (void) close(fnew); return (1);
753 }
754 }
755 if (dflag) printf("copy: %s copied to %s.\n",from,to);
756 if (!tflag) {
757 /* restore original time-stamp */
758 tv[0] = stfrom.st_atime;
759 tv[1] = stfrom.st_mtime;
760 (void) utime(to, tv);
761 if (dflag) printf("copy: tflag on, tv[0]=%d, tv[1]=%d.\n",tv[0], tv[1]);
762 }
763 if (dflag) printf("copy: returning from copy, from=%s, to=%s.\n",from,to);
764 (void) close(fold); (void) close(fnew); return (0);
765}
766
767rcopy(from, to, iflag, rflag)
768 char *from, *to;
769{
770 DIR *fold = opendir(from);
771 struct direct *dp;
772 int errs = 0;
773 char fromname[BUFSIZ];
774
775 if (dflag) printf("rcopy: entered: from=%s, to=%s.\n",from,to);
776 if (fold == 0) {
777 Cerror(from,fflag);
778 return (1);
779 }
780 for (;;) {
781 dp = readdir(fold);
782 if (dp == 0) {
783 closedir(fold);
784 return (errs);
785 }
786 if (dp->d_ino == 0)
787 continue;
788 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
789 continue;
790 if (strlen(from) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
791 if (!fflag) {
792 fprintf(stderr, "cp: %s/%s: Name too long.\n",
793 from, dp->d_name);
794 }
795 errs++;
796 continue;
797 }
798 (void) sprintf(fromname, "%s/%s", from, dp->d_name);
799 if (dflag) printf("rcopy: copy(%s,%s,%d,%d)\n",fromname,to,iflag,rflag);
800 errs += copy(fromname, to, iflag, rflag);
801 }
802}
803
804Cerror(s)
805 char *s;
806{
807 if (!fflag) {
808 fprintf(stderr, "cp: ");
809 perror(s);
810 }
811}