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' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | */ |
58 | static int runshell; |
59 | static jmp_buf reset; |
60 | static char *nextarg = NULL((void *)0); |
61 | |
62 | /* |
63 | * Structure and routines associated with listing directories. |
64 | */ |
65 | struct 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 | }; |
72 | struct 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 | |
79 | static char *copynext(char *, char *); |
80 | static int fcmp(const void *, const void *); |
81 | static void formatf(struct afile *, int); |
82 | static void getcmd(char *, char *, size_t, char *, size_t, struct arglist *); |
83 | struct dirent *glob_readdir(RST_DIR *dirp); |
84 | static int glob_stat(const char *, struct stat *); |
85 | static void mkentry(char *, struct direct *, struct afile *); |
86 | static void printlist(char *, char *); |
87 | |
88 | /* |
89 | * Read and execute commands from the terminal. |
90 | */ |
91 | void |
92 | runcmdshell(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); |
110 | loop: |
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 | */ |
299 | static void |
300 | getcmd(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 | */ |
347 | getnext: |
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 | |
390 | retnext: |
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 | */ |
403 | static char * |
404 | copynext(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 | */ |
452 | void |
453 | canon(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 | */ |
501 | static void |
502 | printlist(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 | */ |
584 | static void |
585 | mkentry(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 | */ |
640 | static void |
641 | formatf(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 | |
712 | struct dirent * |
713 | glob_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 | */ |
733 | static int |
734 | glob_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 | */ |
751 | static int |
752 | fcmp(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 | */ |
761 | void |
762 | onintr(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 | } |