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