2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
10 * Copyright (c) 1983 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
18 * Modified to recursively extract all files within a subtree
19 * (supressed by the h option) and recreate the heirarchical
20 * structure of that subtree and move extracted files to their
21 * proper homes (supressed by the m option).
22 * Includes the s (skip files) option for use with multiple
23 * dumps on a single tape.
24 * 8/29/80 by Mike Litzkow
26 * Modified to work on the new file system and to recover from
28 * 1/19/82 by Kirk McKusick
30 * Full incremental restore running entirely in user code and
31 * interactive tape browser.
32 * 1/19/83 by Kirk McKusick
37 #include <byteorder.h>
38 #include <priv_utils.h>
45 int bflag
= 0, dflag
= 0, vflag
= 0, yflag
= 0;
46 int hflag
= 1, mflag
= 1, paginating
= 0, offline
= 0, autoload
= 0;
49 int cvtflag
= 0; /* Converting from old dump format */
53 uint_t ntrec
; /* blocking factor, in KB */
54 uint_t saved_ntrec
; /* saved blocking factor, in KB */
55 ssize_t tape_rec_size
= 0; /* tape record size (ntrec * tp_bsize) */
56 size_t newtapebuf_size
= 0; /* save size of last call to newtapebuf */
60 char *c_label
; /* if non-NULL, we must see this tape label */
66 char *pager_catenated
;
71 int32_t tp_bsize
= TP_BSIZE_MIN
;
72 struct byteorder_ctx
*byteorder
;
74 static void set_tmpdir(void);
77 main(int argc
, char *argv
[])
79 static struct arglist alist
= { 0, 0, 0, 0, 0 };
85 char *archivefile
= 0;
86 char *symtbl
= RESTORESYMTABLE
;
87 char name
[MAXPATHLEN
];
89 struct sigaction sa
, osa
;
93 if ((progname
= strrchr(argv
[0], '/')) != NULL
)
98 if (strcmp("hsmrestore", progname
) == 0) {
99 (void) fprintf(stderr
,
100 gettext("hsmrestore emulation is no longer supported.\n"));
105 * Convert the effective uid of 0 to the single privilege
106 * we really want. When running with all privileges, this
107 * is a no-op. When the set-uid bit is stripped restore
108 * still works for local tapes. Fail when trying to access
109 * a remote tape in that case and not immediately.
111 (void) __init_suid_priv(0, PRIV_NET_PRIVADDR
, NULL
);
116 * This doesn't work because ufsrestore is statically linked:
117 * (void) setlocale(LC_ALL, "");
118 * The problem seems to be with LC_COLLATE, so set all the
119 * others explicitly. Bug 1157128 was created against the I18N
120 * library. When that bug is fixed this should go back to the way
122 * XXX 1157128 was closed as a dup of 1099747. That bug was fixed by
123 * disallowing setlocale() to anything other than "C". "" is
124 * allowed, but only if none of the envars LC_ALL, LC_COLLATE, or LANG
125 * select anything other than "C".
127 (void) setlocale(LC_CTYPE
, "");
128 (void) setlocale(LC_NUMERIC
, "");
129 (void) setlocale(LC_TIME
, "");
130 (void) setlocale(LC_MONETARY
, "");
131 (void) setlocale(LC_MESSAGES
, "");
132 #if !defined(TEXT_DOMAIN)
133 #define TEXT_DOMAIN "SYS_TEST"
135 (void) textdomain(TEXT_DOMAIN
);
137 if ((byteorder
= byteorder_create()) == NULL
) {
138 (void) fprintf(stderr
,
139 gettext("Cannot create byteorder context\n"));
143 if ((savepwd
= open(".", O_RDONLY
)) < 0) {
144 (void) fprintf(stderr
,
145 gettext("Cannot save current directory context\n"));
151 autoload_period
= 12;
152 autoload_tries
= 12; /* traditional default of ~2.5 minutes */
154 sa
.sa_handler
= onintr
;
155 sa
.sa_flags
= SA_RESTART
;
156 (void) sigemptyset(&sa
.sa_mask
);
158 (void) sigaction(SIGINT
, &sa
, &osa
);
159 if (osa
.sa_handler
== SIG_IGN
)
160 (void) sigaction(SIGINT
, &osa
, NULL
);
162 (void) sigaction(SIGTERM
, &sa
, &osa
);
163 if (osa
.sa_handler
== SIG_IGN
)
164 (void) sigaction(SIGTERM
, &osa
, NULL
);
167 (void) fprintf(stderr
, gettext("Usage:\n\
168 \t%s tabcdfhsvyLloT [file file ...]\n\
169 \t%s xabcdfhmsvyLloT [file file ...]\n\
170 \t%s iabcdfhmsvyLloT\n\
171 \t%s rabcdfsvyLloT\n\
172 \t%s RabcdfsvyLloT\n\n\
173 a requires an archive file name\n\
174 b requires a blocking factor\n\
175 f requires a dump file\n\
176 s requires a file number\n\
177 L requires a tape label\n\
178 If set, the envar TMPDIR selects where temporary files are kept\n"),
179 progname
, progname
, progname
, progname
, progname
);
183 argv
++; /* the bag-of-options */
184 argc
-= 2; /* count of parameters to the options */
186 c_label
= NULL
; /* any tape's acceptable */
187 for (cp
= *argv
++; *cp
; cp
++) {
188 switch (*cp
) { /* BE CAUTIOUS OF FALLTHROUGHS */
191 (void) fprintf(stderr
, gettext(
192 "Missing autoload timeout period\n"));
198 (void) fprintf(stderr
, gettext(
199 "Unreasonable autoload timeout period `%s'\n"),
203 units
= *(*argv
+ strlen(*argv
) - 1);
211 case '0': case '1': case '2': case '3': case '4':
212 case '5': case '6': case '7': case '8': case '9':
217 (void) fprintf(stderr
, gettext(
218 "Unknown timeout units indicator `%c'\n"),
223 ((count
* multiplier
) / autoload_period
);
237 (void) fprintf(stderr
,
238 gettext("missing archive file name\n"));
241 archivefile
= *argv
++;
242 if (*archivefile
== '\0') {
243 (void) fprintf(stderr
,
244 gettext("empty archive file name\n"));
257 * This used to be the Dflag, but it doesn't
258 * hurt to always check, so was removed. This
259 * case is here for backward compatability.
276 (void) fprintf(stderr
,
277 gettext("missing device specifier\n"));
281 if (*inputdev
== '\0') {
282 (void) fprintf(stderr
,
283 gettext("empty device specifier\n"));
291 * change default tape blocksize
295 (void) fprintf(stderr
,
296 gettext("missing block size\n"));
299 saved_ntrec
= ntrec
= atoi(*argv
++);
300 if (ntrec
== 0 || (ntrec
&1)) {
301 (void) fprintf(stderr
, gettext(
302 "Block size must be a positive, even integer\n"));
305 ntrec
/= (tp_bsize
/DEV_BSIZE
);
310 * dumpnum (skip to) for multifile dump tapes
313 (void) fprintf(stderr
,
314 gettext("missing dump number\n"));
317 dumpnum
= atoi(*argv
++);
319 (void) fprintf(stderr
, gettext(
320 "Dump number must be a positive integer\n"));
330 if (command
!= '\0') {
331 (void) fprintf(stderr
, gettext(
332 "%c and %c are mutually exclusive\n"),
333 (uchar_t
)*cp
, (uchar_t
)command
);
339 if (argc
< 1 || **argv
== '\0') {
340 (void) fprintf(stderr
,
341 gettext("Missing tape label name\n"));
344 c_label
= *argv
++; /* must get tape with this label */
345 if (strlen(c_label
) > (sizeof (spcl
.c_label
) - 1)) {
346 c_label
[sizeof (spcl
.c_label
) - 1] = '\0';
347 (void) fprintf(stderr
, gettext(
348 "Truncating label to maximum supported length: `%s'\n"),
355 (void) fprintf(stderr
,
356 gettext("Bad key character %c\n"), (uchar_t
)*cp
);
360 if (command
== '\0') {
361 (void) fprintf(stderr
,
362 gettext("must specify i, t, r, R, or x\n"));
365 setinput(inputdev
, archivefile
);
366 if (argc
== 0) { /* re-use last argv slot for default */
368 *--argv
= mflag
? "." : "2";
378 initsymtable((char *)0);
384 * Incremental restoration of a file system.
390 * This is an incremental dump tape.
392 vprintf(stdout
, gettext("Begin incremental restore\n"));
393 initsymtable(symtbl
);
396 vprintf(stdout
, gettext("Calculate node updates.\n"));
399 treescan(name
, ROOTINO
, nodeupdates
);
400 attrscan(1, nodeupdates
);
405 * This is a level zero dump tape.
407 vprintf(stdout
, gettext("Begin level 0 restore\n"));
408 initsymtable((char *)0);
411 gettext("Calculate extraction list.\n"));
414 treescan(name
, ROOTINO
, nodeupdates
);
415 attrscan(1, nodeupdates
);
417 createleaves(symtbl
);
423 gettext("Verify the directory structure\n"));
426 treescan(name
, ROOTINO
, verifyfile
);
428 dumpsymtable(symtbl
, (long)1);
432 * Resume an incremental file system restoration.
436 initsymtable(symtbl
);
439 createleaves(symtbl
);
443 dumpsymtable(symtbl
, (long)1);
447 * List contents of tape.
452 initsymtable((char *)0);
456 canon(*argv
++, name
, sizeof (name
));
457 name
[strlen(name
)+1] = '\0';
458 ino
= dirlookup(name
);
461 treescan(name
, ino
, listfile
);
466 * Batch extraction of tape contents.
471 initsymtable((char *)0);
474 canon(*argv
++, name
, sizeof (name
));
475 if (expand(name
, 0, &alist
) == 0) {
476 /* no meta-characters to expand */
477 ino
= dirlookup(name
);
482 /* add each of the expansions */
483 while ((alist
.last
- alist
.head
) > 0) {
484 fname
= alist
.head
->fname
;
485 ino
= dirlookup(fname
);
495 continue; /* argc loop */
498 ino
= (ino_t
)atol(*argv
);
499 if ((*(*argv
++) == '-') || ino
< ROOTINO
) {
500 (void) fprintf(stderr
, gettext(
501 "bad inode number: %ld\n"),
507 treescan(name
, ino
, addfile
);
508 attrscan(0, addfile
);
522 * Determine where the user wants us to put our temporary files,
523 * and make sure we can actually do so. Bail out if there's a problem.
529 char name
[MAXPATHLEN
];
531 tmpdir
= getenv("TMPDIR");
532 if ((tmpdir
== NULL
) || (*tmpdir
== '\0'))
535 if (*tmpdir
!= '/') {
536 (void) fprintf(stderr
,
537 gettext("TMPDIR is not an absolute path (`%s').\n"),
543 * The actual use of tmpdir is in dirs.c, and is of the form
544 * tmpdir + "/rst" + type (three characters) + "%ld.XXXXXX" +
545 * a trailing NUL, where %ld is an arbitrary time_t.
547 * Thus, the magic 31 is strlen(itoa(MAX_TIME_T)) + "/rst" +
548 * ".XXXXXX" + '\0'. A time_t is 64 bits, so MAX_TIME_T is
549 * LONG_MAX - nineteen digits. In theory, so many things in
550 * ufsrestore will break once time_t's value goes beyond 32
551 * bits that it's not worth worrying about this particular
552 * instance at this time, but we've got to start somewhere.
554 * Note that the use of a pid below is just for testing the
555 * validity of the named directory.
557 if (strlen(tmpdir
) > (MAXPATHLEN
- 31)) {
558 (void) fprintf(stderr
, gettext("TMPDIR too long\n"));
562 /* Guaranteed to fit by above test (sizeof(time_t) >= sizeof(pid_t)) */
563 (void) snprintf(name
, sizeof (name
), "%s/rstdir.%ld", tmpdir
, getpid());
566 * This is effectively a stripped-down version of safe_open(),
567 * because if the file exists, we want to fail.
569 fd
= open(name
, O_CREAT
|O_EXCL
|O_RDWR
, 0600);
571 perror(gettext("Can not create temporary file"));
576 if (unlink(name
) < 0) {
577 perror(gettext("Can not delete temporary file"));