2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
26 /* $Id: amidxtaped.c,v 1.25.2.3.4.1.2.11.2.2 2005/10/02 13:48:42 martinea Exp $
28 * This daemon extracts a dump image off a tape for amrecover and
29 * returns it over the network. It basically, reads a number of
30 * arguments from stdin (it is invoked via inet), one per line,
31 * preceeded by the number of them, and forms them into an argv
32 * structure, then execs amrestore
44 static char *pgm = "amidxtaped"; /* in case argv[0] is not set */
46 char *conf_logdir = NULL;
47 char *conf_logfile = NULL;
49 char *found_device = NULL;
51 static char *get_client_line P((void));
53 /* get a line from client - line terminated by \r\n */
57 static char *line = NULL;
63 if((part = agets(stdin)) == NULL) {
65 dbprintf(("%s: read error: %s\n",
66 debug_prefix_time(NULL), strerror(errno)));
68 dbprintf(("%s: EOF reached\n", debug_prefix_time(NULL)));
71 dbprintf(("%s: unprocessed input:\n", debug_prefix_time(NULL)));
72 dbprintf(("-----\n"));
73 dbprintf(("%s\n", line));
74 dbprintf(("-----\n"));
86 strappend(line, part);
92 if((len = strlen(line)) > 0 && line[len-1] == '\r') {
93 line[len-1] = '\0'; /* zap the '\r' */
97 * Hmmm. We got a "line" from agets(), which means it saw
98 * a '\n' (or EOF, etc), but there was not a '\r' before it.
99 * Put a '\n' back in the buffer and loop for more.
101 strappend(line, "\n");
103 dbprintf(("%s: > %s\n", debug_prefix_time(NULL), line));
108 char *searchlabel = NULL;
109 int nslots, backwards;
111 int scan_init(rc, ns, bk)
116 unlink(conf_logfile);
118 error("could not get changer info: %s", changer_resultstr);
127 int taperscan_slot(rc, slotstr, device)
133 char *datestamp = NULL, *label = NULL;
136 dbprintf(("%s: fatal slot %s: %s\n", debug_prefix_time(NULL),
137 slotstr, changer_resultstr));
141 dbprintf(("%s: slot %s: %s\n", debug_prefix_time(NULL),
142 slotstr, changer_resultstr));
146 if((errstr = tape_rdlabel(device, &datestamp, &label)) != NULL) {
147 dbprintf(("%s: slot %s: %s\n", debug_prefix_time(NULL),
150 /* got an amanda tape */
151 dbprintf(("%s: slot %s: date %-8s label %s",
152 debug_prefix_time(NULL), slotstr, datestamp, label));
153 if(strcmp(label, FAKE_LABEL) == 0 ||
154 strcmp(label, searchlabel) == 0) {
155 /* it's the one we are looking for, stop here */
156 found_device = newstralloc(found_device,device);
157 dbprintf((" (exact label match)\n"));
162 dbprintf((" (no match)\n"));
172 conf_logdir = getconf_str(CNF_LOGDIR);
173 if (*conf_logdir == '/') {
174 conf_logdir = stralloc(conf_logdir);
176 conf_logdir = stralloc2(config_dir, conf_logdir);
178 conf_logfile = vstralloc(conf_logdir, "/log", NULL);
179 if (access(conf_logfile, F_OK) == 0) {
180 error("%s exists: amdump or amflush is already running, or you must run amcleanup", conf_logfile);
182 log_add(L_INFO, "amidxtaped");
192 char **amrestore_args;
196 char *amrestore_path;
199 struct stat stat_tape;
200 char *tapename = NULL;
204 struct sockaddr_in addr;
209 char *re_label = NULL;
211 char *re_device = NULL;
212 char *re_host = NULL;
213 char *re_disk = NULL;
214 char *re_datestamp = NULL;
215 char *re_config = NULL;
221 * When called via inetd, it is not uncommon to forget to put the
222 * argv[0] value on the config line. On some systems (e.g. Solaris)
223 * this causes argv and/or argv[0] to be NULL, so we have to be
224 * careful getting our name.
226 if (argc >= 1 && argv != NULL && argv[0] != NULL) {
227 if((pgm = strrchr(argv[0], '/')) != NULL) {
238 /* we'd rather not run as root */
241 if(client_uid == (uid_t) -1) {
242 error("error [cannot find user %s in passwd file]\n", CLIENT_LOGIN);
245 initgroups(CLIENT_LOGIN, client_gid);
250 #endif /* FORCE_USERID */
253 /* close stderr first so that debug file becomes it - amrestore
254 chats to stderr, which we don't want going to client */
255 /* if no debug file, ship to bit bucket */
256 (void)close(STDERR_FILENO);
259 dbprintf(("%s: version %s\n", pgm, version()));
261 if(dbfd() != -1 && dbfd() != STDERR_FILENO)
263 if(dup2(dbfd(),STDERR_FILENO) != STDERR_FILENO)
265 perror("amidxtaped can't redirect stderr to the debug file");
266 dbprintf(("%s: can't redirect stderr to the debug file\n",
267 debug_prefix_time(NULL)));
272 if ((i = open("/dev/null", O_WRONLY)) == -1 ||
273 (i != STDERR_FILENO &&
274 (dup2(i, STDERR_FILENO) != STDERR_FILENO ||
276 perror("amidxtaped can't redirect stderr");
281 if (! (argc >= 1 && argv != NULL && argv[0] != NULL)) {
282 dbprintf(("%s: WARNING: argv[0] not defined: check inetd.conf\n",
283 debug_prefix_time(NULL)));
286 socklen = sizeof (addr);
287 if (getpeername(0, (struct sockaddr *)&addr, &socklen) == -1)
288 error("getpeername: %s", strerror(errno));
289 if (addr.sin_family != AF_INET || ntohs(addr.sin_port) == 20) {
290 error("connection rejected from %s family %d port %d",
291 inet_ntoa(addr.sin_addr), addr.sin_family, htons(addr.sin_port));
294 /* do the security thing */
296 buf = stralloc(get_client_line());
300 skip_whitespace(s, ch);
303 error("cannot parse SECURITY line");
306 skip_non_whitespace(s, ch);
308 if (strcmp(fp, "SECURITY") != 0)
310 error("cannot parse SECURITY line");
312 skip_whitespace(s, ch);
313 if (!security_ok(&addr, s-1, 0, &errstr)) {
314 error("security check failed: %s", errstr);
317 /* get the number of arguments */
321 buf = stralloc(get_client_line());
322 if(strncmp(buf, "LABEL=", 6) == 0) {
323 re_label = stralloc(buf+6);
325 else if(strncmp(buf, "FSF=", 4) == 0) {
326 int fsf = atoi(buf+4);
328 re_fsf = stralloc(buf+4);
331 else if(strncmp(buf, "HEADER", 6) == 0) {
334 else if(strncmp(buf, "DEVICE=", 7) == 0) {
335 re_device = stralloc(buf+7);
337 else if(strncmp(buf, "HOST=", 5) == 0) {
338 re_host = stralloc(buf+5);
340 else if(strncmp(buf, "DISK=", 5) == 0) {
341 re_disk = stralloc(buf+5);
343 else if(strncmp(buf, "DATESTAMP=", 10) == 0) {
344 re_datestamp = stralloc(buf+10);
346 else if(strncmp(buf, "END", 3) == 0) {
349 else if(strncmp(buf, "CONFIG=", 7) == 0) {
350 re_config = stralloc(buf+7);
352 else if(buf[0] != '\0' && buf[0] >= '0' && buf[0] <= '9') {
353 amrestore_nargs = atoi(buf);
358 } while (re_end == 0);
362 config_dir = vstralloc(CONFIG_DIR, "/", re_config, "/", NULL);
363 conffile = stralloc2(config_dir, CONFFILE_NAME);
364 if (read_conffile(conffile)) {
365 dbprintf(("%s: config '%s' not found\n",
366 debug_prefix_time(NULL), re_config));
377 if(re_device && re_config &&
378 strcmp(re_device, getconf_str(CNF_TAPEDEV)) == 0) {
379 get_lock = lock_logfile();
382 if(re_label && re_config &&
383 strcmp(re_device, getconf_str(CNF_AMRECOVER_CHANGER)) == 0) {
385 if(changer_init() == 0) {
386 dbprintf(("%s: No changer available\n",
387 debug_prefix_time(NULL)));
390 searchlabel = stralloc(re_label);
391 changer_find(scan_init, taperscan_slot, searchlabel);
393 dbprintf(("%s: Can't find label \"%s\"\n",
394 debug_prefix_time(NULL), searchlabel));
396 unlink(conf_logfile);
402 re_device=stralloc(found_device);
403 dbprintf(("%s: label \"%s\" found\n",
404 debug_prefix_time(NULL), searchlabel));
409 if(re_fsf && re_config && getconf_int(CNF_AMRECOVER_DO_FSF) == 0) {
412 if(re_label && re_config && getconf_int(CNF_AMRECOVER_CHECK_LABEL) == 0) {
416 dbprintf(("%s: amrestore_nargs=%d\n",
417 debug_prefix_time(NULL),
420 amrestore_args = (char **)alloc((amrestore_nargs+12)*sizeof(char *));
422 amrestore_args[i++] = "amrestore";
423 if(re_header || re_device || re_host || re_disk || re_datestamp ||
424 re_label || re_fsf) {
426 amrestore_args[i++] = "-p";
427 if(re_header) amrestore_args[i++] = "-h";
429 amrestore_args[i++] = "-l";
430 amrestore_args[i++] = re_label;
433 amrestore_args[i++] = "-f";
434 amrestore_args[i++] = re_fsf;
436 if(re_device) amrestore_args[i++] = re_device;
437 if(re_host) amrestore_args[i++] = re_host;
438 if(re_disk) amrestore_args[i++] = re_disk;
439 if(re_datestamp) amrestore_args[i++] = re_datestamp;
441 else { /* fe_amidxtaped_nargs */
442 while (i <= amrestore_nargs) {
443 amrestore_args[i++] = stralloc(get_client_line());
446 amrestore_args[i] = NULL;
448 amrestore_path = vstralloc(sbindir, "/", "amrestore", NULL);
450 /* so got all the arguments, now ready to execv */
451 dbprintf(("%s: Ready to execv amrestore with:\n", debug_prefix_time(NULL)));
452 dbprintf(("path = %s\n", amrestore_path));
453 for (i = 0; amrestore_args[i] != NULL; i++)
455 dbprintf(("argv[%d] = \"%s\"\n", i, amrestore_args[i]));
458 if ((pid = fork()) == 0)
461 (void)execv(amrestore_path, amrestore_args);
463 /* only get here if exec failed */
464 dbprintf(("%s: child could not exec %s: %s\n",
465 debug_prefix_time(NULL),
472 /* this is the parent */
475 dbprintf(("%s: error forking amrestore child: %s\n",
476 debug_prefix_time(NULL), strerror(errno)));
478 unlink(conf_logfile);
484 /* wait for the child to do the restore */
485 if (waitpid(pid, &status, 0) == -1)
487 dbprintf(("%s: error waiting for amrestore child: %s\n",
488 debug_prefix_time(NULL), strerror(errno)));
490 unlink(conf_logfile);
495 /* amrestore often sees the pipe reader (ie restore) quit in the middle
496 of the file because it has extracted all of the files needed. This
497 results in an exit status of 2. This unfortunately is the exit
498 status returned by many errors. Only when the exit status is 1 is it
499 guaranteed that an error existed. In all cases we should rewind the
500 tape if we can so that a retry starts from the correct place */
501 if (WIFEXITED(status) != 0)
504 dbprintf(("%s: amrestore terminated normally with status: %d\n",
505 debug_prefix_time(NULL), WEXITSTATUS(status)));
509 dbprintf(("%s: amrestore terminated abnormally.\n",
510 debug_prefix_time(NULL)));
515 tapename = re_device;
518 /* the first non-option argument is the tape device */
519 for (i = 1; i <= amrestore_nargs; i++)
520 if (amrestore_args[i][0] != '-')
522 if (i > amrestore_nargs) {
523 dbprintf(("%s: Couldn't find tape in arguments\n",
524 debug_prefix_time(NULL)));
526 unlink(conf_logfile);
532 tapename = stralloc(amrestore_args[i]);
534 if (tape_stat(tapename, &stat_tape) != 0) {
535 error("could not stat %s: %s", tapename, strerror(errno));
537 isafile = S_ISREG((stat_tape.st_mode));
541 dbprintf(("%s: rewinding tape ...\n", debug_prefix_time(NULL)));
542 errstr = tape_rewind(tapename);
544 if (errstr != NULL) {
545 dbprintf(("%s: %s\n", debug_prefix_time(NULL), errstr));
548 dbprintf(("%s: done\n", debug_prefix_time(NULL)));
553 unlink(conf_logfile);