]> git.wh0rd.org - dump.git/blame - restore/interactive.c
Version 0.4b5.
[dump.git] / restore / interactive.c
CommitLineData
1227625a
SP
1/*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
b45f51d6
SP
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <pop@cybercable.fr>, 1999
1227625a
SP
6 *
7 */
8
9/*
10 * Copyright (c) 1985, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41
42#ifndef lint
b45f51d6 43#if 0
1227625a 44static char sccsid[] = "@(#)interactive.c 8.5 (Berkeley) 5/1/95";
b45f51d6
SP
45#endif
46static const char rcsid[] =
47 "$Id: interactive.c,v 1.2 1999/10/11 12:53:23 stelian Exp $";
1227625a
SP
48#endif /* not lint */
49
50#include <sys/param.h>
1227625a
SP
51#include <sys/stat.h>
52
53#ifdef __linux__
54#include <linux/ext2_fs.h>
55#include <bsdcompat.h>
56#else /* __linux__ */
57#include <ufs/ufs/dinode.h>
58#include <ufs/ufs/dir.h>
1227625a
SP
59#endif /* __linux__ */
60#include <protocols/dumprestore.h>
61
62#include <setjmp.h>
63#include <glob.h>
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67
68#ifdef __linux__
69#include <ext2fs/ext2fs.h>
70#endif
71
72#include "restore.h"
73#include "extern.h"
74
75#define round(a, b) (((a) + (b) - 1) / (b) * (b))
76
77/*
78 * Things to handle interruptions.
79 */
80static int runshell;
81static jmp_buf reset;
82static char *nextarg = NULL;
83
84/*
85 * Structure and routines associated with listing directories.
86 */
87struct afile {
88 ino_t fnum; /* inode number of file */
89 char *fname; /* file name */
90 short len; /* name length */
91 char prefix; /* prefix character */
92 char postfix; /* postfix character */
93};
94struct arglist {
95 int freeglob; /* glob structure needs to be freed */
96 int argcnt; /* next globbed argument to return */
97 glob_t glob; /* globbing information */
98 char *cmd; /* the current command */
99};
100
101static char *copynext __P((char *, char *));
102static int fcmp __P((const void *, const void *));
103static void formatf __P((struct afile *, int));
b45f51d6 104static void getcmd __P((char *, char *, char *, int, struct arglist *));
1227625a
SP
105struct dirent *glob_readdir __P((RST_DIR *dirp));
106static int glob_stat __P((const char *, struct stat *));
107static void mkentry __P((char *, struct direct *, struct afile *));
108static void printlist __P((char *, char *));
109
110/*
111 * Read and execute commands from the terminal.
112 */
113void
114runcmdshell()
115{
116 register struct entry *np;
117 ino_t ino;
118 struct arglist arglist;
119 char curdir[MAXPATHLEN];
120 char name[MAXPATHLEN];
121 char cmd[BUFSIZ];
122
123 arglist.freeglob = 0;
124 arglist.argcnt = 0;
125 arglist.glob.gl_flags = GLOB_ALTDIRFUNC;
126 arglist.glob.gl_opendir = (void *)rst_opendir;
127 arglist.glob.gl_readdir = (void *)glob_readdir;
128 arglist.glob.gl_closedir = (void *)rst_closedir;
129 arglist.glob.gl_lstat = glob_stat;
130 arglist.glob.gl_stat = glob_stat;
b45f51d6 131 canon("/", curdir, sizeof(curdir));
1227625a
SP
132loop:
133 if (setjmp(reset) != 0) {
134 if (arglist.freeglob != 0) {
135 arglist.freeglob = 0;
136 arglist.argcnt = 0;
137 globfree(&arglist.glob);
138 }
139 nextarg = NULL;
140 volno = 0;
141 }
142 runshell = 1;
b45f51d6 143 getcmd(curdir, cmd, name, sizeof(name), &arglist);
1227625a
SP
144 switch (cmd[0]) {
145 /*
146 * Add elements to the extraction list.
147 */
148 case 'a':
149 if (strncmp(cmd, "add", strlen(cmd)) != 0)
150 goto bad;
151 ino = dirlookup(name);
152 if (ino == 0)
153 break;
154 if (mflag)
155 pathcheck(name);
156 treescan(name, ino, addfile);
157 break;
158 /*
159 * Change working directory.
160 */
161 case 'c':
162 if (strncmp(cmd, "cd", strlen(cmd)) != 0)
163 goto bad;
164 ino = dirlookup(name);
165 if (ino == 0)
166 break;
167 if (inodetype(ino) == LEAF) {
168 fprintf(stderr, "%s: not a directory\n", name);
169 break;
170 }
171 (void) strcpy(curdir, name);
172 break;
173 /*
174 * Delete elements from the extraction list.
175 */
176 case 'd':
177 if (strncmp(cmd, "delete", strlen(cmd)) != 0)
178 goto bad;
179 np = lookupname(name);
180 if (np == NULL || (np->e_flags & NEW) == 0) {
181 fprintf(stderr, "%s: not on extraction list\n", name);
182 break;
183 }
184 treescan(name, np->e_ino, deletefile);
185 break;
186 /*
187 * Extract the requested list.
188 */
189 case 'e':
190 if (strncmp(cmd, "extract", strlen(cmd)) != 0)
191 goto bad;
192 createfiles();
193 createlinks();
194 setdirmodes(0);
195 if (dflag)
196 checkrestore();
197 volno = 0;
198 break;
199 /*
200 * List available commands.
201 */
202 case 'h':
203 if (strncmp(cmd, "help", strlen(cmd)) != 0)
204 goto bad;
205 case '?':
206 fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
207 "Available commands are:\n",
208 "\tls [arg] - list directory\n",
209 "\tcd arg - change directory\n",
210 "\tpwd - print current directory\n",
211 "\tadd [arg] - add `arg' to list of",
212 " files to be extracted\n",
213 "\tdelete [arg] - delete `arg' from",
214 " list of files to be extracted\n",
215 "\textract - extract requested files\n",
216 "\tsetmodes - set modes of requested directories\n",
217 "\tquit - immediately exit program\n",
218 "\twhat - list dump header information\n",
219 "\tverbose - toggle verbose flag",
220 " (useful with ``ls'')\n",
221 "\thelp or `?' - print this list\n",
222 "If no `arg' is supplied, the current",
223 " directory is used\n");
224 break;
225 /*
226 * List a directory.
227 */
228 case 'l':
229 if (strncmp(cmd, "ls", strlen(cmd)) != 0)
230 goto bad;
231 printlist(name, curdir);
232 break;
233 /*
234 * Print current directory.
235 */
236 case 'p':
237 if (strncmp(cmd, "pwd", strlen(cmd)) != 0)
238 goto bad;
239 if (curdir[1] == '\0')
240 fprintf(stderr, "/\n");
241 else
242 fprintf(stderr, "%s\n", &curdir[1]);
243 break;
244 /*
245 * Quit.
246 */
247 case 'q':
248 if (strncmp(cmd, "quit", strlen(cmd)) != 0)
249 goto bad;
250 return;
251 case 'x':
252 if (strncmp(cmd, "xit", strlen(cmd)) != 0)
253 goto bad;
254 return;
255 /*
256 * Toggle verbose mode.
257 */
258 case 'v':
259 if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
260 goto bad;
261 if (vflag) {
262 fprintf(stderr, "verbose mode off\n");
263 vflag = 0;
264 break;
265 }
266 fprintf(stderr, "verbose mode on\n");
267 vflag++;
268 break;
269 /*
270 * Just restore requested directory modes.
271 */
272 case 's':
273 if (strncmp(cmd, "setmodes", strlen(cmd)) != 0)
274 goto bad;
275 setdirmodes(FORCE);
276 break;
277 /*
278 * Print out dump header information.
279 */
280 case 'w':
281 if (strncmp(cmd, "what", strlen(cmd)) != 0)
282 goto bad;
283 printdumpinfo();
284 break;
285 /*
286 * Turn on debugging.
287 */
288 case 'D':
289 if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
290 goto bad;
291 if (dflag) {
292 fprintf(stderr, "debugging mode off\n");
293 dflag = 0;
294 break;
295 }
296 fprintf(stderr, "debugging mode on\n");
297 dflag++;
298 break;
299 /*
300 * Unknown command.
301 */
302 default:
303 bad:
304 fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
305 break;
306 }
307 goto loop;
308}
309
310/*
311 * Read and parse an interactive command.
312 * The first word on the line is assigned to "cmd". If
313 * there are no arguments on the command line, then "curdir"
314 * is returned as the argument. If there are arguments
315 * on the line they are returned one at a time on each
316 * successive call to getcmd. Each argument is first assigned
317 * to "name". If it does not start with "/" the pathname in
318 * "curdir" is prepended to it. Finally "canon" is called to
319 * eliminate any embedded ".." components.
320 */
321static void
b45f51d6 322getcmd(curdir, cmd, name, size, ap)
1227625a
SP
323 char *curdir, *cmd, *name;
324 struct arglist *ap;
b45f51d6 325 int size;
1227625a
SP
326{
327 register char *cp;
328 static char input[BUFSIZ];
329 char output[BUFSIZ];
330# define rawname input /* save space by reusing input buffer */
331
332 /*
333 * Check to see if still processing arguments.
334 */
335 if (ap->argcnt > 0)
336 goto retnext;
337 if (nextarg != NULL)
338 goto getnext;
339 /*
340 * Read a command line and trim off trailing white space.
341 */
342 do {
343 fprintf(stderr, "restore > ");
344 (void) fflush(stderr);
345 (void) fgets(input, BUFSIZ, terminal);
346 } while (!feof(terminal) && input[0] == '\n');
347 if (feof(terminal)) {
348 (void) strcpy(cmd, "quit");
349 return;
350 }
351 for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
352 /* trim off trailing white space and newline */;
353 *++cp = '\0';
354 /*
355 * Copy the command into "cmd".
356 */
357 cp = copynext(input, cmd);
358 ap->cmd = cmd;
359 /*
360 * If no argument, use curdir as the default.
361 */
362 if (*cp == '\0') {
b45f51d6
SP
363 (void) strncpy(name, curdir, size);
364 name[size - 1] = '\0';
1227625a
SP
365 return;
366 }
367 nextarg = cp;
368 /*
369 * Find the next argument.
370 */
371getnext:
372 cp = copynext(nextarg, rawname);
373 if (*cp == '\0')
374 nextarg = NULL;
375 else
376 nextarg = cp;
377 /*
378 * If it is an absolute pathname, canonicalize it and return it.
379 */
380 if (rawname[0] == '/') {
b45f51d6 381 canon(rawname, name, size);
1227625a
SP
382 } else {
383 /*
384 * For relative pathnames, prepend the current directory to
385 * it then canonicalize and return it.
386 */
b45f51d6
SP
387 snprintf(output, sizeof(output), "%s/%s", curdir, rawname);
388 canon(output, name, size);
1227625a
SP
389 }
390 if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0)
391 fprintf(stderr, "%s: out of memory\n", ap->cmd);
392 if (ap->glob.gl_pathc == 0)
393 return;
394 ap->freeglob = 1;
395 ap->argcnt = ap->glob.gl_pathc;
396
397retnext:
b45f51d6
SP
398 strncpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt], size);
399 name[size - 1] = '\0';
1227625a
SP
400 if (--ap->argcnt == 0) {
401 ap->freeglob = 0;
402 globfree(&ap->glob);
403 }
404# undef rawname
405}
406
407/*
408 * Strip off the next token of the input.
409 */
410static char *
411copynext(input, output)
412 char *input, *output;
413{
414 register char *cp, *bp;
415 char quote;
416
417 for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
418 /* skip to argument */;
419 bp = output;
420 while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
421 /*
422 * Handle back slashes.
423 */
424 if (*cp == '\\') {
425 if (*++cp == '\0') {
426 fprintf(stderr,
427 "command lines cannot be continued\n");
428 continue;
429 }
430 *bp++ = *cp++;
431 continue;
432 }
433 /*
434 * The usual unquoted case.
435 */
436 if (*cp != '\'' && *cp != '"') {
437 *bp++ = *cp++;
438 continue;
439 }
440 /*
441 * Handle single and double quotes.
442 */
443 quote = *cp++;
444 while (*cp != quote && *cp != '\0')
b45f51d6 445 *bp++ = *cp++ | 0200;
1227625a
SP
446 if (*cp++ == '\0') {
447 fprintf(stderr, "missing %c\n", quote);
448 cp--;
449 continue;
450 }
451 }
452 *bp = '\0';
453 return (cp);
454}
455
456/*
457 * Canonicalize file names to always start with ``./'' and
b45f51d6 458 * remove any embedded "." and ".." components.
1227625a
SP
459 */
460void
b45f51d6 461canon(rawname, canonname, len)
1227625a 462 char *rawname, *canonname;
b45f51d6 463 int len;
1227625a
SP
464{
465 register char *cp, *np;
466
467 if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
468 (void) strcpy(canonname, "");
469 else if (rawname[0] == '/')
470 (void) strcpy(canonname, ".");
471 else
472 (void) strcpy(canonname, "./");
b45f51d6
SP
473 if (strlen(canonname) + strlen(rawname) >= len) {
474 fprintf(stderr, "canonname: not enough buffer space\n");
475 done(1);
476 }
477
1227625a
SP
478 (void) strcat(canonname, rawname);
479 /*
480 * Eliminate multiple and trailing '/'s
481 */
482 for (cp = np = canonname; *np != '\0'; cp++) {
483 *cp = *np++;
484 while (*cp == '/' && *np == '/')
485 np++;
486 }
487 *cp = '\0';
488 if (*--cp == '/')
489 *cp = '\0';
490 /*
491 * Eliminate extraneous "." and ".." from pathnames.
492 */
493 for (np = canonname; *np != '\0'; ) {
494 np++;
495 cp = np;
496 while (*np != '/' && *np != '\0')
497 np++;
498 if (np - cp == 1 && *cp == '.') {
499 cp--;
500 (void) strcpy(cp, np);
501 np = cp;
502 }
503 if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
504 cp--;
505 while (cp > &canonname[1] && *--cp != '/')
506 /* find beginning of name */;
507 (void) strcpy(cp, np);
508 np = cp;
509 }
510 }
511}
512
513/*
514 * Do an "ls" style listing of a directory
515 */
516static void
517printlist(name, basename)
518 char *name;
519 char *basename;
520{
b45f51d6 521 register struct afile *fp, *list, *listp=NULL;
1227625a
SP
522 register struct direct *dp;
523 struct afile single;
524 RST_DIR *dirp;
525 int entries, len, namelen;
526 char locname[MAXPATHLEN + 1];
527
528 dp = pathsearch(name);
529 if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
530 (!vflag && dp->d_ino == WINO))
531 return;
532 if ((dirp = rst_opendir(name)) == NULL) {
533 entries = 1;
534 list = &single;
535 mkentry(name, dp, list);
536 len = strlen(basename) + 1;
537 if (strlen(name) - len > single.len) {
538 freename(single.fname);
539 single.fname = savename(&name[len]);
540 single.len = strlen(single.fname);
541 }
542 } else {
543 entries = 0;
b45f51d6 544 while ((dp = rst_readdir(dirp)))
1227625a
SP
545 entries++;
546 rst_closedir(dirp);
547 list = (struct afile *)malloc(entries * sizeof(struct afile));
548 if (list == NULL) {
549 fprintf(stderr, "ls: out of memory\n");
550 return;
551 }
552 if ((dirp = rst_opendir(name)) == NULL)
553 panic("directory reopen failed\n");
554 fprintf(stderr, "%s:\n", name);
555 entries = 0;
556 listp = list;
557 (void) strncpy(locname, name, MAXPATHLEN);
558 (void) strncat(locname, "/", MAXPATHLEN);
559 namelen = strlen(locname);
b45f51d6 560 while ((dp = rst_readdir(dirp))) {
1227625a
SP
561 if (dp == NULL)
562 break;
563 if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
564 continue;
565 if (!vflag && (dp->d_ino == WINO ||
566 strcmp(dp->d_name, ".") == 0 ||
567 strcmp(dp->d_name, "..") == 0))
568 continue;
569 locname[namelen] = '\0';
570 if (namelen + dp->d_namlen >= MAXPATHLEN) {
571 fprintf(stderr, "%s%s: name exceeds %d char\n",
572 locname, dp->d_name, MAXPATHLEN);
573 } else {
574 (void) strncat(locname, dp->d_name,
575 (int)dp->d_namlen);
576 mkentry(locname, dp, listp++);
577 entries++;
578 }
579 }
580 rst_closedir(dirp);
581 if (entries == 0) {
582 fprintf(stderr, "\n");
583 free(list);
584 return;
585 }
586 qsort((char *)list, entries, sizeof(struct afile), fcmp);
587 }
588 formatf(list, entries);
589 if (dirp != NULL) {
590 for (fp = listp - 1; fp >= list; fp--)
591 freename(fp->fname);
592 fprintf(stderr, "\n");
593 free(list);
594 }
595}
596
597/*
598 * Read the contents of a directory.
599 */
600static void
601mkentry(name, dp, fp)
602 char *name;
603 struct direct *dp;
604 register struct afile *fp;
605{
606 char *cp;
607 struct entry *np;
608
609 fp->fnum = dp->d_ino;
610 fp->fname = savename(dp->d_name);
611 for (cp = fp->fname; *cp; cp++)
612 if (!vflag && (*cp < ' ' || *cp >= 0177))
613 *cp = '?';
614 fp->len = cp - fp->fname;
615 if (dflag && TSTINO(fp->fnum, dumpmap) == 0)
616 fp->prefix = '^';
617 else if ((np = lookupname(name)) != NULL && (np->e_flags & NEW))
618 fp->prefix = '*';
619 else
620 fp->prefix = ' ';
1227625a
SP
621 switch(dp->d_type) {
622
623 default:
624 fprintf(stderr, "Warning: undefined file type %d\n",
625 dp->d_type);
626 /* fall through */
627 case DT_REG:
628 fp->postfix = ' ';
629 break;
630
631 case DT_LNK:
632 fp->postfix = '@';
633 break;
634
635 case DT_FIFO:
636 case DT_SOCK:
637 fp->postfix = '=';
638 break;
639
640 case DT_CHR:
641 case DT_BLK:
642 fp->postfix = '#';
643 break;
644
645 case DT_WHT:
646 fp->postfix = '%';
647 break;
648
649 case DT_UNKNOWN:
650 case DT_DIR:
651 if (inodetype(dp->d_ino) == NODE)
652 fp->postfix = '/';
653 else
654 fp->postfix = ' ';
655 break;
656 }
1227625a
SP
657 return;
658}
659
660/*
661 * Print out a pretty listing of a directory
662 */
663static void
664formatf(list, nentry)
665 register struct afile *list;
666 int nentry;
667{
668 register struct afile *fp, *endlist;
669 int width, bigino, haveprefix, havepostfix;
b45f51d6 670 int i, j, w, precision=0, columns, lines;
1227625a
SP
671
672 width = 0;
673 haveprefix = 0;
674 havepostfix = 0;
675 bigino = ROOTINO;
676 endlist = &list[nentry];
677 for (fp = &list[0]; fp < endlist; fp++) {
678 if (bigino < fp->fnum)
679 bigino = fp->fnum;
680 if (width < fp->len)
681 width = fp->len;
682 if (fp->prefix != ' ')
683 haveprefix = 1;
684 if (fp->postfix != ' ')
685 havepostfix = 1;
686 }
687 if (haveprefix)
688 width++;
689 if (havepostfix)
690 width++;
691 if (vflag) {
692 for (precision = 0, i = bigino; i > 0; i /= 10)
693 precision++;
694 width += precision + 1;
695 }
696 width++;
697 columns = 81 / width;
698 if (columns == 0)
699 columns = 1;
700 lines = (nentry + columns - 1) / columns;
701 for (i = 0; i < lines; i++) {
702 for (j = 0; j < columns; j++) {
703 fp = &list[j * lines + i];
704 if (vflag) {
b45f51d6 705 fprintf(stderr, "%*ld ", precision, fp->fnum);
1227625a
SP
706 fp->len += precision + 1;
707 }
708 if (haveprefix) {
709 putc(fp->prefix, stderr);
710 fp->len++;
711 }
712 fprintf(stderr, "%s", fp->fname);
713 if (havepostfix) {
714 putc(fp->postfix, stderr);
715 fp->len++;
716 }
717 if (fp + lines >= endlist) {
718 fprintf(stderr, "\n");
719 break;
720 }
721 for (w = fp->len; w < width; w++)
722 putc(' ', stderr);
723 }
724 }
725}
726
727/*
728 * Skip over directory entries that are not on the tape
729 *
730 * First have to get definition of a dirent.
731 */
732#ifdef __linux__
733struct dirent {
734 off_t d_off; /* offset of next disk dir entry */
735 unsigned long d_fileno; /* file number of entry */
736 unsigned short d_reclen; /* length of this record */
737 unsigned short d_namlen; /* length of string in d_name */
738 char d_name[255+1]; /* name (up to MAXNAMLEN + 1) */
739};
740#else /* __linux__ */
741#undef DIRBLKSIZ
742#include <dirent.h>
743#undef d_ino
744#endif /* __linux__ */
745
746struct dirent *
747glob_readdir(dirp)
748 RST_DIR *dirp;
749{
750 struct direct *dp;
751 static struct dirent adirent;
752
753 while ((dp = rst_readdir(dirp)) != NULL) {
754 if (!vflag && dp->d_ino == WINO)
755 continue;
756 if (dflag || TSTINO(dp->d_ino, dumpmap))
757 break;
758 }
759 if (dp == NULL)
760 return (NULL);
761 adirent.d_fileno = dp->d_ino;
1227625a 762 adirent.d_namlen = dp->d_namlen;
1227625a
SP
763 memmove(adirent.d_name, dp->d_name, dp->d_namlen + 1);
764 return (&adirent);
765}
766
767/*
768 * Return st_mode information in response to stat or lstat calls
769 */
770static int
771glob_stat(name, stp)
772 const char *name;
773 struct stat *stp;
774{
775 register struct direct *dp;
776
777 dp = pathsearch(name);
778 if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
779 (!vflag && dp->d_ino == WINO))
780 return (-1);
781 if (inodetype(dp->d_ino) == NODE)
782 stp->st_mode = IFDIR;
783 else
784 stp->st_mode = IFREG;
785 return (0);
786}
787
788/*
789 * Comparison routine for qsort.
790 */
791static int
792fcmp(f1, f2)
793 register const void *f1, *f2;
794{
795 return (strcmp(((struct afile *)f1)->fname,
796 ((struct afile *)f2)->fname));
797}
798
799/*
800 * respond to interrupts
801 */
802void
803onintr(signo)
804 int signo;
805{
806 if (command == 'i' && runshell)
807 longjmp(reset, 1);
808 if (reply("restore interrupted, continue") == FAIL)
809 done(1);
810}