Bug Summary

File:src/sbin/restore/interactive.c
Warning:line 527, column 11
Although the value stored to 'dp' is used in the enclosing expression, the value is never actually read from 'dp'

Annotated Source Code

Press '?' to see keyboard shortcuts

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