dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / backup / restore / interactive.c
blobae086a1a94301448875934b3fe440f481a68decc
1 /*
2 * Copyright 1998,2001-2003 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1985 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #include <setjmp.h>
16 #include <euc.h>
17 #include <widec.h>
18 #include "restore.h"
19 #include <ctype.h>
20 #include <limits.h>
21 #include <sys/wait.h>
23 extern eucwidth_t wp;
25 #define round(a, b) ((((a) + (b) - 1) / (b)) * (b))
28 * Things to handle interruptions.
30 static jmp_buf reset;
31 static int reset_OK;
32 static char *nextarg = NULL;
34 static int dontexpand; /* co-routine state set in getnext, used in expandarg */
36 #ifdef __STDC__
37 static void getcmd(char *, char *, size_t, char *, size_t, struct arglist *);
38 static void expandarg(char *, struct arglist *);
39 static void printlist(char *, ino_t, char *, int);
40 static void formatf(struct arglist *);
41 static char *copynext(char *, char *, size_t);
42 static int fcmp(struct afile *, struct afile *);
43 static char *fmtentry(struct afile *);
44 static void setpagercmd(void);
45 static uint_t setpagerargs(char **);
46 #else
47 static void getcmd();
48 static void expandarg();
49 static void printlist();
50 static void formatf();
51 static char *copynext();
52 static int fcmp();
53 static char *fmtentry();
54 static void setpagercmd();
55 static uint_t setpagerargs();
56 #endif
59 * Read and execute commands from the terminal.
61 void
62 #ifdef __STDC__
63 runcmdshell(void)
64 #else
65 runcmdshell()
66 #endif
68 struct entry *np;
69 ino_t ino;
70 static struct arglist alist = { 0, 0, 0, 0, 0 };
71 char curdir[MAXCOMPLEXLEN];
72 char name[MAXCOMPLEXLEN];
73 char cmd[BUFSIZ];
76 canon("/", curdir, sizeof (curdir));
77 loop:
78 if (setjmp(reset) != 0) {
79 for (; alist.head < alist.last; alist.head++)
80 freename(alist.head->fname);
81 nextarg = NULL;
82 volno = 0;
83 goto loop; /* make sure jmpbuf is up-to-date */
85 reset_OK = 1;
86 getcmd(curdir, cmd, sizeof (cmd), name, sizeof (name), &alist);
89 * Using strncmp() to catch unique prefixes.
91 switch (cmd[0]) {
93 * Add elements to the extraction list.
95 case 'a':
96 if (strncmp(cmd, "add", strlen(cmd)) != 0)
97 goto bad;
98 if (name[0] == '\0')
99 break;
100 ino = dirlookup(name);
101 if (ino == 0)
102 break;
103 if (mflag)
104 pathcheck(name);
105 treescan(name, ino, addfile);
106 break;
108 * Change working directory.
110 case 'c':
111 if (strncmp(cmd, "cd", strlen(cmd)) != 0)
112 goto bad;
113 if (name[0] == '\0')
114 break;
115 ino = dirlookup(name);
116 if (ino == 0)
117 break;
118 if (inodetype(ino) == LEAF) {
119 (void) fprintf(stderr,
120 gettext("%s: not a directory\n"), name);
121 break;
124 /* No need to canon(name), getcmd() did it for us */
125 (void) strncpy(curdir, name, sizeof (curdir));
126 curdir[sizeof (curdir) - 1] = '\0';
127 break;
129 * Delete elements from the extraction list.
131 case 'd':
132 if (strncmp(cmd, "delete", strlen(cmd)) != 0)
133 goto bad;
134 if (name[0] == '\0')
135 break;
136 np = lookupname(name);
137 if (np == NIL || (np->e_flags & NEW) == 0) {
138 (void) fprintf(stderr,
139 gettext("%s: not on extraction list\n"), name);
140 break;
142 treescan(name, np->e_ino, deletefile);
143 break;
145 * Extract the requested list.
147 case 'e':
148 if (strncmp(cmd, "extract", strlen(cmd)) != 0)
149 goto bad;
150 attrscan(0, addfile);
151 createfiles();
152 createlinks();
153 setdirmodes();
154 if (dflag)
155 checkrestore();
156 volno = 0;
157 break;
159 * List available commands.
161 case 'h':
162 if (strncmp(cmd, "help", strlen(cmd)) != 0)
163 goto bad;
164 /*FALLTHROUGH*/
165 case '?':
166 /* ANSI string catenation, to shut cstyle up */
167 (void) fprintf(stderr, "%s",
168 gettext("Available commands are:\n"
169 "\tls [arg] - list directory\n"
170 "\tmarked [arg] - list items marked for extraction from directory\n"
171 "\tcd arg - change directory\n"
172 "\tpwd - print current directory\n"
173 "\tadd [arg] - add `arg' to list of files to be extracted\n"
174 "\tdelete [arg] - delete `arg' from list of files to be extracted\n"
175 "\textract - extract requested files\n"
176 "\tsetmodes - set modes of requested directories\n"
177 "\tquit - immediately exit program\n"
178 "\twhat - list dump header information\n"
179 "\tverbose - toggle verbose flag (useful with ``ls'')\n"
180 "\tpaginate - toggle pagination flag (affects ``ls'' and ``marked'')\n"
181 "\tsetpager - set pagination command and arguments\n"
182 "\thelp or `?' - print this list\n"
183 "If no `arg' is supplied, the current directory is used\n"));
184 break;
186 * List a directory.
188 case 'l':
189 case 'm':
190 if ((strncmp(cmd, "ls", strlen(cmd)) != 0) &&
191 (strncmp(cmd, "marked", strlen(cmd)) != 0))
192 goto bad;
193 if (name[0] == '\0')
194 break;
195 ino = dirlookup(name);
196 if (ino == 0)
197 break;
198 printlist(name, ino, curdir, *cmd == 'm');
199 break;
201 * Print current directory or enable pagination.
203 case 'p':
204 if (strlen(cmd) < 2)
205 goto ambiguous;
206 if (strncmp(cmd, "pwd", strlen(cmd)) == 0) {
207 if (curdir[1] == '\0') {
208 (void) fprintf(stderr, "/\n");
209 } else {
210 (void) fprintf(stderr, "%s\n", &curdir[1]);
212 } else if (strncmp(cmd, "paginate", strlen(cmd)) == 0) {
213 if (paginating) {
214 (void) fprintf(stderr,
215 gettext("paging disabled\n"));
216 paginating = 0;
217 break;
219 if (vflag) {
220 (void) fprintf(stderr,
221 gettext("paging enabled (%s)\n"),
222 pager_catenated);
223 } else {
224 (void) fprintf(stderr,
225 gettext("paging enabled\n"));
227 if (dflag) {
228 int index = 0;
230 while (index < pager_len) {
231 (void) fprintf(stderr,
232 ">>>pager_vector[%d] = `%s'\n",
233 index,
234 pager_vector[index] ?
235 pager_vector[index] : "(null)");
236 index += 1;
239 paginating = 1;
240 } else {
241 goto bad;
243 break;
245 * Quit.
247 case 'q':
248 if (strncmp(cmd, "quit", strlen(cmd)) != 0)
249 goto bad;
250 reset_OK = 0;
251 return;
252 case 'x':
253 if (strncmp(cmd, "xit", strlen(cmd)) != 0)
254 goto bad;
255 reset_OK = 0;
256 return;
258 * Toggle verbose mode.
260 case 'v':
261 if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
262 goto bad;
263 if (vflag) {
264 (void) fprintf(stderr, gettext("verbose mode off\n"));
265 vflag = 0;
266 break;
268 (void) fprintf(stderr, gettext("verbose mode on\n"));
269 vflag = 1;
270 break;
272 * Just restore requested directory modes, or set pagination command.
274 case 's':
275 if (strlen(cmd) < 4)
276 goto ambiguous;
277 if (strncmp(cmd, "setmodes", strlen(cmd)) == 0) {
278 setdirmodes();
279 } else if (strncmp(cmd, "setpager", strlen(cmd)) == 0) {
280 setpagercmd();
281 } else {
282 goto bad;
284 break;
286 * Print out dump header information.
288 case 'w':
289 if (strncmp(cmd, "what", strlen(cmd)) != 0)
290 goto bad;
291 printdumpinfo();
292 break;
294 * Turn on debugging.
296 case 'D':
297 if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
298 goto bad;
299 if (dflag) {
300 (void) fprintf(stderr, gettext("debugging mode off\n"));
301 dflag = 0;
302 break;
304 (void) fprintf(stderr, gettext("debugging mode on\n"));
305 dflag++;
306 break;
308 * Unknown command.
310 default:
311 bad:
312 (void) fprintf(stderr,
313 gettext("%s: unknown command; type ? for help\n"), cmd);
314 break;
315 ambiguous:
316 (void) fprintf(stderr,
317 gettext("%s: ambiguous command; type ? for help\n"), cmd);
318 break;
320 goto loop;
323 static char input[MAXCOMPLEXLEN]; /* shared by getcmd() and setpagercmd() */
324 #define rawname input /* save space by reusing input buffer */
327 * Read and parse an interactive command.
328 * The first word on the line is assigned to "cmd". If
329 * there are no arguments on the command line, then "curdir"
330 * is returned as the argument. If there are arguments
331 * on the line they are returned one at a time on each
332 * successive call to getcmd. Each argument is first assigned
333 * to "name". If it does not start with "/" the pathname in
334 * "curdir" is prepended to it. Finally "canon" is called to
335 * eliminate any embedded ".." components.
337 /* ARGSUSED */
338 static void
339 getcmd(curdir, cmd, cmdsiz, name, namesiz, ap)
340 char *curdir, *cmd, *name;
341 size_t cmdsiz, namesiz;
342 struct arglist *ap;
344 char *cp;
345 char output[MAXCOMPLEXLEN];
348 * Check to see if still processing arguments.
350 if (ap->head != ap->last) {
351 (void) strncpy(name, ap->head->fname, namesiz);
352 name[namesiz - 1] = '\0';
353 /* double null terminate string */
354 if ((strlen(name) + 2) > namesiz) {
355 fprintf(stderr, gettext("name is too long, ignoring"));
356 memset(name, 0, namesiz);
357 } else {
358 name[strlen(name) + 1] = '\0';
360 freename(ap->head->fname);
361 ap->head++;
362 return;
364 if (nextarg != NULL)
365 goto getnext;
367 * Read a command line and trim off trailing white space.
369 readagain:
370 do {
371 (void) fprintf(stderr, "%s > ", progname);
372 (void) fflush(stderr);
373 (void) fgets(input, sizeof (input), terminal);
374 } while (!feof(terminal) && input[0] == '\n');
375 if (feof(terminal)) {
376 (void) strncpy(cmd, "quit", cmdsiz);
377 return;
379 /* trim off trailing white space and newline */
380 for (cp = &input[strlen(input) - 2];
381 cp >= &input[0] && isspace((uchar_t)*cp);
382 cp--) {
383 continue;
384 /*LINTED [empty loop body]*/
386 *++cp = '\0';
387 if ((strlen(input) + 2) > MAXCOMPLEXLEN) {
388 fprintf(stderr, gettext("command is too long\n"));
389 goto readagain;
390 } else {
391 /* double null terminate string */
392 *(cp + 1) = '\0';
395 if (cp == &input[0])
396 goto readagain;
399 * Copy the command into "cmd".
401 cp = copynext(input, cmd, cmdsiz);
402 ap->cmd = cmd;
404 * If no argument, use curdir as the default.
406 if (*cp == '\0') {
407 (void) strncpy(name, curdir, namesiz);
408 name[namesiz - 1] = '\0';
409 /* double null terminate string */
410 if ((strlen(name) + 2) > namesiz) {
411 fprintf(stderr, gettext("name is too long, ignoring"));
412 memset(name, 0, namesiz);
413 } else {
414 name[strlen(name) + 1] = '\0';
416 return;
418 nextarg = cp;
420 * Find the next argument.
422 getnext:
423 cp = copynext(nextarg, rawname, sizeof (rawname));
424 if (*cp == '\0')
425 nextarg = NULL;
426 else
427 nextarg = cp;
429 * If it an absolute pathname, canonicalize it and return it.
431 if (rawname[0] == '/') {
432 canon(rawname, name, namesiz);
433 } else {
435 * For relative pathnames, prepend the current directory to
436 * it then canonicalize and return it.
438 (void) snprintf(output, sizeof (output), "%s/%s",
439 curdir, rawname);
440 canon(output, name, namesiz);
442 expandarg(name, ap);
444 * ap->head->fname guaranteed to be double null-terminated and
445 * no more than MAXCOMPLEXLEN characters long.
447 assert(namesiz >= (MAXCOMPLEXLEN));
448 (void) strcpy(name, ap->head->fname);
449 /* double null terminate string */
450 name[strlen(name) + 1] = '\0';
451 freename(ap->head->fname);
452 ap->head++;
453 #undef rawname
457 * Strip off the next token of the input.
459 static char *
460 copynext(input, output, outsize)
461 char *input, *output;
462 size_t outsize;
464 char *cp, *bp, *limit;
465 char quote;
467 dontexpand = 0;
468 /* skip to argument */
469 for (cp = input; *cp != '\0' && isspace((uchar_t)*cp); cp++) {
470 continue;
471 /*LINTED [empty loop body]*/
473 bp = output;
474 limit = output + outsize - 1; /* -1 for the trailing \0 */
475 while (!isspace((uchar_t)*cp) && *cp != '\0' && bp < limit) {
477 * Handle back slashes.
479 if (*cp == '\\') {
480 if (*++cp == '\0') {
481 (void) fprintf(stderr, gettext(
482 "command lines cannot be continued\n"));
483 continue;
485 *bp++ = *cp++;
486 continue;
489 * The usual unquoted case.
491 if (*cp != '\'' && *cp != '"') {
492 *bp++ = *cp++;
493 continue;
496 * Handle single and double quotes.
498 quote = *cp++;
499 dontexpand = 1;
500 while (*cp != quote && *cp != '\0' && bp < limit)
501 *bp++ = *cp++;
502 if (*cp++ == '\0') {
503 (void) fprintf(stderr,
504 gettext("missing %c\n"), (uchar_t)quote);
505 cp--;
506 continue;
509 *bp = '\0';
510 if ((strlen(output) + 2) > outsize) {
511 fprintf(stderr, gettext(
512 "name is too long, ignoring"));
513 memset(output, 0, outsize);
514 } else {
515 /* double null terminate string */
516 *(bp + 1) = '\0';
518 return (cp);
522 * Canonicalize file names to always start with ``./'' and
523 * remove any imbedded "." and ".." components.
525 * The pathname "canonname" is returned double null terminated.
527 void
528 canon(rawname, canonname, limit)
529 char *rawname, *canonname;
530 size_t limit;
532 char *cp, *np, *prefix;
533 uint_t len;
535 assert(limit > 3);
536 if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
537 prefix = "";
538 else if (rawname[0] == '/')
539 prefix = ".";
540 else
541 prefix = "./";
542 (void) snprintf(canonname, limit, "%s%s", prefix, rawname);
544 * Eliminate multiple and trailing '/'s
546 for (cp = np = canonname; *np != '\0'; cp++) {
547 *cp = *np++;
548 while (*cp == '/' && *np == '/')
549 np++;
551 *cp = '\0';
552 if ((strlen(canonname) + 2) > limit) {
553 fprintf(stderr,
554 gettext("canonical name is too long, ignoring name\n"));
555 memset(canonname, 0, limit);
556 } else {
557 /* double null terminate string */
558 *(cp + 1) = '\0';
561 if (*--cp == '/')
562 *cp = '\0';
564 * Eliminate extraneous "." and ".." from pathnames. Uses
565 * memmove(), as strcpy() might do the wrong thing for these
566 * small overlaps.
568 np = canonname;
569 while (*np != '\0') {
570 np++;
571 cp = np;
572 while (*np != '/' && *np != '\0')
573 np++;
574 if (np - cp == 1 && *cp == '.') {
575 cp--;
576 len = strlen(np);
577 (void) memmove(cp, np, len);
578 *(cp + len) = '\0';
579 /* double null terminate string */
580 *(cp + len + 1) = '\0';
581 np = cp;
583 if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
584 cp--;
585 /* find beginning of name */
586 while (cp > &canonname[1] && *--cp != '/') {
587 continue;
588 /*LINTED [empty loop body]*/
590 len = strlen(np);
591 (void) memmove(cp, np, len);
592 *(cp + len) = '\0';
593 /* double null terminate string */
594 *(cp + len + 1) = '\0';
595 np = cp;
601 * globals (file name generation)
603 * "*" in params matches r.e ".*"
604 * "?" in params matches r.e. "."
605 * "[...]" in params matches character class
606 * "[...a-z...]" in params matches a through z.
608 static void
609 expandarg(arg, ap)
610 char *arg;
611 struct arglist *ap;
613 static struct afile single;
614 int size;
616 ap->head = ap->last = NULL;
617 if (dontexpand)
618 size = 0;
619 else
620 size = expand(arg, 0, ap);
621 if (size == 0) {
622 struct entry *ep;
624 ep = lookupname(arg);
625 single.fnum = ep ? ep->e_ino : 0;
626 single.fname = savename(arg);
627 ap->head = &single;
628 ap->last = ap->head + 1;
629 return;
631 if ((ap->last - ap->head) > ULONG_MAX) {
632 (void) fprintf(stderr,
633 gettext("Argument expansion too large to sort\n"));
634 } else {
635 /* LINTED pointer arith just range-checked */
636 qsort((char *)ap->head, (size_t)(ap->last - ap->head),
637 sizeof (*ap->head),
638 (int (*)(const void *, const void *)) fcmp);
643 * Do an "ls" style listing of a directory
645 static void
646 printlist(name, ino, basename, marked_only)
647 char *name;
648 ino_t ino;
649 char *basename;
650 int marked_only;
652 struct afile *fp;
653 struct direct *dp;
654 static struct arglist alist = { 0, 0, 0, 0, "ls" };
655 struct afile single;
656 struct entry *np;
657 RST_DIR *dirp;
658 int list_entry;
660 if ((dirp = rst_opendir(name)) == NULL) {
661 single.fnum = ino;
662 if (strncmp(name, basename, strlen(basename)) == 0)
663 single.fname = savename(name + strlen(basename) + 1);
664 else
665 single.fname = savename(name);
666 alist.head = &single;
667 alist.last = alist.head + 1;
668 if (alist.base != NULL) {
669 free(alist.base);
670 alist.base = NULL;
672 } else {
673 alist.head = NULL;
674 (void) fprintf(stderr, "%s:\n", name);
675 while (dp = rst_readdir(dirp)) {
676 if (dp == NULL || dp->d_ino == 0) {
677 rst_closedir(dirp);
678 dirp = NULL;
679 break;
681 if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
682 continue;
683 if (vflag == 0 &&
684 (strcmp(dp->d_name, ".") == 0 ||
685 strcmp(dp->d_name, "..") == 0))
686 continue;
687 list_entry = 1;
688 if (marked_only) {
689 np = lookupino(dp->d_ino);
690 if ((np == NIL) || ((np->e_flags & NEW) == 0))
691 list_entry = 0;
693 if (list_entry) {
694 if (!mkentry(dp->d_name, dp->d_ino, &alist)) {
695 rst_closedir(dirp);
696 return;
701 if (alist.head != 0) {
702 if ((alist.last - alist.head) > ULONG_MAX) {
703 (void) fprintf(stderr,
704 gettext("Directory too large to sort\n"));
705 } else {
706 qsort((char *)alist.head,
707 /* LINTED range-checked */
708 (size_t)(alist.last - alist.head),
709 sizeof (*alist.head),
710 (int (*)(const void *, const void *)) fcmp);
712 formatf(&alist);
713 for (fp = alist.head; fp < alist.last; fp++)
714 freename(fp->fname);
715 alist.head = NULL;
717 * Don't free alist.base, as we'll probably be called
718 * again, and might as well re-use what we've got.
721 if (dirp != NULL) {
722 (void) fprintf(stderr, "\n");
723 rst_closedir(dirp);
728 * Print out a pretty listing of a directory
730 static void
731 formatf(ap)
732 struct arglist *ap;
734 struct afile *fp;
735 struct entry *np;
736 /* LINTED: result fits into an int */
737 int nentry = (int)(ap->last - ap->head);
738 int i, j;
739 uint_t len, w, width = 0, columns, lines;
740 char *cp;
741 FILE *output = stderr;
743 if (ap->head == ap->last)
744 return;
746 if (paginating) {
747 int fds[2];
749 if (pipe(fds) < 0) {
750 perror(gettext("could not create pipe"));
751 goto no_page;
754 switch (fork()) {
755 case -1:
756 perror(gettext("could not fork"));
757 goto no_page;
758 case 0:
760 * Make sure final output still ends up in
761 * the same place.
763 (void) dup2(fileno(stderr), fileno(stdout));
764 (void) close(fds[0]);
765 (void) dup2(fds[1], fileno(stdin));
766 execvp(pager_vector[0], pager_vector);
767 perror(gettext("execvp of pager failed"));
768 exit(1);
769 /*NOTREACHED*/
770 default:
771 (void) close(fds[1]);
772 output = fdopen(fds[0], "w");
773 if (output != NULL) {
774 break;
776 perror(gettext("could not open pipe to pager"));
777 output = stderr;
778 no_page:
779 (void) fprintf(stderr,
780 gettext("pagination disabled\n"));
781 paginating = 0;
785 for (fp = ap->head; fp < ap->last; fp++) {
786 fp->ftype = inodetype(fp->fnum);
787 np = lookupino(fp->fnum);
788 if (np != NIL)
789 fp->fflags = np->e_flags;
790 else
791 fp->fflags = 0;
792 len = strlen(fmtentry(fp));
793 if (len > width)
794 width = len;
796 width += 2;
797 columns = 80 / width;
798 if (columns == 0)
799 columns = 1;
800 lines = (nentry + columns - 1) / columns;
801 for (i = 0; i < lines && !ferror(output); i++) {
802 for (j = 0; j < columns && !ferror(output); j++) {
803 fp = ap->head + j * lines + i;
804 cp = fmtentry(fp);
805 (void) fprintf(output, "%s", cp);
806 if (fp + lines >= ap->last) {
807 (void) fprintf(output, "\n");
808 break;
810 w = strlen(cp);
811 while (w < width) {
812 w++;
813 if (fprintf(output, " ") < 0)
814 break;
819 if (paginating) {
820 (void) fclose(output);
821 (void) wait(NULL);
826 * Comparison routine for qsort.
828 static int
829 fcmp(f1, f2)
830 struct afile *f1, *f2;
833 return (strcoll(f1->fname, f2->fname));
837 * Format a directory entry.
839 static char *
840 fmtentry(fp)
841 struct afile *fp;
843 static char fmtres[MAXCOMPLEXLEN];
844 static int precision = 0;
845 ino_t i;
846 char *cp, *dp, *limit;
848 if (!vflag) {
849 /* MAXCOMPLEXLEN assumed to be >= 1 */
850 fmtres[0] = '\0';
851 } else {
852 if (precision == 0) {
853 for (i = maxino; i != 0; i /= 10)
854 precision++;
855 if (sizeof (fmtres) < (unsigned)(precision + 2)) {
856 (void) fprintf(stderr, gettext(
857 "\nInternal check failed, minimum width %d exceeds available size %d\n"),
858 (precision + 2), sizeof (fmtres));
859 done(1);
862 (void) snprintf(fmtres, sizeof (fmtres), "%*ld ",
863 precision, fp->fnum);
865 dp = &fmtres[strlen(fmtres)];
866 limit = fmtres + sizeof (fmtres) - 1;
867 if (dflag && BIT(fp->fnum, dumpmap) == 0)
868 *dp++ = '^';
869 else if ((fp->fflags & NEW) != 0)
870 *dp++ = '*';
871 else
872 *dp++ = ' ';
873 for (cp = fp->fname; *cp && dp < limit; cp++)
874 /* LINTED: precedence ok, can't fix system macro */
875 if (!vflag && (!ISPRINT(*cp, wp)))
876 *dp++ = '?';
877 else
878 *dp++ = *cp;
879 if (fp->ftype == NODE && dp < limit)
880 *dp++ = '/';
881 *dp++ = 0;
882 return (fmtres);
886 * respond to interrupts
888 /* ARGSUSED */
889 void
890 onintr(sig)
891 int sig;
893 char buf[300];
895 if (command == 'i' && reset_OK)
896 longjmp(reset, 1);
898 (void) snprintf(buf, sizeof (buf),
899 gettext("%s interrupted, continue"), progname);
900 if (reply(buf) == FAIL)
901 done(1);
904 * Set up pager_catenated and pager_vector.
906 void
907 #ifdef __STDC__
908 initpagercmd(void)
909 #else
910 initpagercmd()
911 #endif
913 char *cp;
915 cp = getenv("PAGER");
916 if (cp != NULL)
917 pager_catenated = strdup(cp);
918 if ((pager_catenated == NULL) || (*pager_catenated == '\0')) {
919 free(pager_catenated);
920 pager_catenated = strdup(DEF_PAGER);
922 if (pager_catenated == NULL) {
923 (void) fprintf(stderr, gettext("out of memory\n"));
924 done(1);
927 pager_vector = (char **)malloc(sizeof (char *));
928 if (pager_vector == NULL) {
929 (void) fprintf(stderr, gettext("out of memory\n"));
930 done(1);
933 pager_len = 1;
934 cp = pager_catenated;
935 (void) setpagerargs(&cp);
940 * Resets pager_catenated and pager_vector from user input.
942 void
943 #ifdef __STDC__
944 setpagercmd(void)
945 #else
946 setpagercmd()
947 #endif
949 uint_t catenate_length;
950 int index;
953 * We'll get called immediately after setting a pager, due to
954 * our interaction with getcmd()'s internal state. Don't do
955 * anything when that happens.
957 if (*input == '\0')
958 return;
960 if (pager_len > 0) {
961 for (index = 0; pager_vector[index] != NULL; index += 1)
962 free(pager_vector[index]);
963 free(pager_vector);
964 free(pager_catenated);
967 pager_vector = (char **)malloc(2 * sizeof (char *));
968 if (pager_vector == NULL) {
969 (void) fprintf(stderr, gettext("out of memory\n"));
970 done(1);
973 pager_len = 2;
974 pager_vector[0] = strdup(input);
975 if (pager_vector[0] == NULL) {
976 (void) fprintf(stderr, gettext("out of memory\n"));
977 done(1);
979 if (dflag)
980 (void) fprintf(stderr, gettext("got command `%s'\n"), input);
981 catenate_length = setpagerargs(&nextarg) + strlen(pager_vector[0]) + 1;
982 pager_catenated = (char *)malloc(catenate_length *
983 (size_t)sizeof (char));
984 if (pager_catenated == NULL) {
985 (void) fprintf(stderr, gettext("out of memory\n"));
986 done(1);
988 for (index = 0; pager_vector[index] != NULL; index += 1) {
989 if (index > 0)
990 (void) strcat(pager_catenated, " ");
991 (void) strcat(pager_catenated, pager_vector[index]);
997 * Extract arguments for the pager command from getcmd()'s input buffer.
999 static uint_t
1000 setpagerargs(source)
1001 char **source;
1003 char word[MAXCOMPLEXLEN];
1004 char *cp = *source;
1005 uint_t length = 0;
1007 while ((cp != NULL) && (*cp != '\0')) {
1008 cp = copynext(cp, word, sizeof (word));
1009 if (dflag)
1010 fprintf(stderr, gettext("got word `%s'\n"), word);
1011 pager_vector = reallocarray(pager_vector,
1012 pager_len + 1, sizeof (char *));
1013 if (pager_vector == (char **)NULL) {
1014 (void) fprintf(stderr, gettext("out of memory\n"));
1015 done(1);
1017 pager_vector[pager_len - 1] = strdup(word);
1018 if (pager_vector[pager_len - 1] == NULL) {
1019 (void) fprintf(stderr, gettext("out of memory\n"));
1020 done(1);
1022 length += strlen(word) + 1;
1023 pager_len += 1;
1025 pager_vector[pager_len - 1] = NULL;
1026 *source = cp;
1027 return (length);