PageRenderTime 127ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/tags/amanda252p1/client-src/sendbackup.c

#
C | 1241 lines | 975 code | 138 blank | 128 comment | 308 complexity | b402f9cd879b9757240c7d81fa4c9264 MD5 | raw file
  1. /*
  2. * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  3. * Copyright (c) 1991-1999 University of Maryland at College Park
  4. * All Rights Reserved.
  5. *
  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.
  15. *
  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.
  22. *
  23. * Authors: the Amanda Development Team. Its members are listed in a
  24. * file named AUTHORS, in the root directory of this distribution.
  25. */
  26. /*
  27. * $Id: sendbackup.c,v 1.88 2006/07/25 18:27:56 martinea Exp $
  28. *
  29. * common code for the sendbackup-* programs.
  30. */
  31. #include "amanda.h"
  32. #include "sendbackup.h"
  33. #include "clock.h"
  34. #include "pipespawn.h"
  35. #include "amfeatures.h"
  36. #include "amandad.h"
  37. #include "arglist.h"
  38. #include "getfsent.h"
  39. #include "version.h"
  40. #include "conffile.h"
  41. #define sendbackup_debug(i,x) do { \
  42. if ((i) <= debug_sendbackup) { \
  43. dbprintf(x); \
  44. } \
  45. } while (0)
  46. #define TIMEOUT 30
  47. pid_t comppid = (pid_t)-1;
  48. pid_t dumppid = (pid_t)-1;
  49. pid_t tarpid = (pid_t)-1;
  50. pid_t encpid = (pid_t)-1;
  51. pid_t indexpid = (pid_t)-1;
  52. char *errorstr = NULL;
  53. int datafd;
  54. int mesgfd;
  55. int indexfd;
  56. option_t *options;
  57. g_option_t *g_options = NULL;
  58. long dump_size = -1;
  59. backup_program_t *program = NULL;
  60. static am_feature_t *our_features = NULL;
  61. static char *our_feature_string = NULL;
  62. static char *amandad_auth = NULL;
  63. /* local functions */
  64. int main(int argc, char **argv);
  65. char *optionstr(option_t *options);
  66. char *childstr(pid_t pid);
  67. int check_status(pid_t pid, amwait_t w);
  68. pid_t pipefork(void (*func)(void), char *fname, int *stdinfd,
  69. int stdoutfd, int stderrfd);
  70. void parse_backup_messages(int mesgin);
  71. static void process_dumpline(char *str);
  72. static void save_fd(int *, int);
  73. void backup_api_info_tapeheader(int mesgfd, char *prog, option_t *options);
  74. double the_num(char *str, int pos);
  75. char *
  76. optionstr(
  77. option_t * options)
  78. {
  79. static char *optstr = NULL;
  80. char *compress_opt;
  81. char *encrypt_opt;
  82. char *decrypt_opt;
  83. char *record_opt = "";
  84. char *index_opt = "";
  85. char *auth_opt;
  86. char *exclude_file_opt;
  87. char *exclude_list_opt;
  88. char *exc = NULL;
  89. sle_t *excl;
  90. if(options->compress == COMP_BEST)
  91. compress_opt = stralloc("compress-best;");
  92. else if(options->compress == COMP_FAST)
  93. compress_opt = stralloc("compress-fast;");
  94. else if(options->compress == COMP_SERVER_BEST)
  95. compress_opt = stralloc("srvcomp-best;");
  96. else if(options->compress == COMP_SERVER_FAST)
  97. compress_opt = stralloc("srvcomp-fast;");
  98. else if(options->compress == COMP_SERVER_CUST)
  99. compress_opt = vstralloc("srvcomp-cust=", options->srvcompprog, ";", NULL);
  100. else if(options->compress == COMP_CUST)
  101. compress_opt = vstralloc("comp-cust=", options->clntcompprog, ";", NULL);
  102. else
  103. compress_opt = stralloc("");
  104. if(options->encrypt == ENCRYPT_CUST) {
  105. encrypt_opt = vstralloc("encrypt-cust=", options->clnt_encrypt, ";", NULL);
  106. if (options->clnt_decrypt_opt)
  107. decrypt_opt = vstralloc("client-decrypt-option=", options->clnt_decrypt_opt, ";", NULL);
  108. else
  109. decrypt_opt = stralloc("");
  110. }
  111. else if(options->encrypt == ENCRYPT_SERV_CUST) {
  112. encrypt_opt = vstralloc("encrypt-serv-cust=", options->srv_encrypt, ";", NULL);
  113. if(options->srv_decrypt_opt)
  114. decrypt_opt = vstralloc("server-decrypt-option=", options->srv_decrypt_opt, ";", NULL);
  115. else
  116. decrypt_opt = stralloc("");
  117. }
  118. else {
  119. encrypt_opt = stralloc("");
  120. decrypt_opt = stralloc("");
  121. }
  122. if(options->no_record) record_opt = "no-record;";
  123. if(options->auth) auth_opt = vstralloc("auth=", options->auth, ";", NULL);
  124. else auth_opt = stralloc("");
  125. if(options->createindex) index_opt = "index;";
  126. exclude_file_opt = stralloc("");
  127. if(options->exclude_file) {
  128. for(excl = options->exclude_file->first; excl != NULL; excl=excl->next){
  129. exc = newvstralloc(exc, "exclude-file=", excl->name, ";", NULL);
  130. strappend(exclude_file_opt, exc);
  131. }
  132. }
  133. exclude_list_opt = stralloc("");
  134. if(options->exclude_list) {
  135. for(excl = options->exclude_list->first; excl != NULL; excl=excl->next){
  136. exc = newvstralloc(exc, "exclude-list=", excl->name, ";", NULL);
  137. strappend(exclude_list_opt, exc);
  138. }
  139. }
  140. amfree(exc);
  141. optstr = newvstralloc(optstr,
  142. compress_opt,
  143. encrypt_opt,
  144. decrypt_opt,
  145. record_opt,
  146. index_opt,
  147. auth_opt,
  148. exclude_file_opt,
  149. exclude_list_opt,
  150. NULL);
  151. amfree(compress_opt);
  152. amfree(encrypt_opt);
  153. amfree(decrypt_opt);
  154. amfree(auth_opt);
  155. amfree(exclude_file_opt);
  156. amfree(exclude_list_opt);
  157. return optstr;
  158. }
  159. int
  160. main(
  161. int argc,
  162. char ** argv)
  163. {
  164. int interactive = 0;
  165. int level = 0;
  166. int mesgpipe[2];
  167. char *prog, *dumpdate, *stroptions;
  168. int program_is_backup_api;
  169. char *disk = NULL;
  170. char *qdisk = NULL;
  171. char *amdevice = NULL;
  172. char *qamdevice = NULL;
  173. char *line = NULL;
  174. char *err_extra = NULL;
  175. char *s;
  176. char *conffile;
  177. int i;
  178. int ch;
  179. unsigned long malloc_hist_1, malloc_size_1;
  180. unsigned long malloc_hist_2, malloc_size_2;
  181. FILE *toolin;
  182. int status;
  183. /* initialize */
  184. safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
  185. safe_cd();
  186. set_pname("sendbackup");
  187. /* Don't die when child closes pipe */
  188. signal(SIGPIPE, SIG_IGN);
  189. /* Don't die when interrupt received */
  190. signal(SIGINT, SIG_IGN);
  191. malloc_size_1 = malloc_inuse(&malloc_hist_1);
  192. if(argc > 1 && strcmp(argv[1],"-t") == 0) {
  193. interactive = 1;
  194. argc--;
  195. argv++;
  196. } else {
  197. interactive = 0;
  198. }
  199. erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
  200. dbopen(DBG_SUBDIR_CLIENT);
  201. startclock();
  202. dbprintf(("%s: version %s\n", get_pname(), version()));
  203. if(argc > 2 && strcmp(argv[1], "amandad") == 0) {
  204. amandad_auth = stralloc(argv[2]);
  205. }
  206. our_features = am_init_feature_set();
  207. our_feature_string = am_feature_to_string(our_features);
  208. conffile = vstralloc(CONFIG_DIR, "/", "amanda-client.conf", NULL);
  209. if (read_clientconf(conffile) > 0) {
  210. error("error reading conffile: %s", conffile);
  211. /*NOTREACHED*/
  212. }
  213. amfree(conffile);
  214. if(interactive) {
  215. /*
  216. * In interactive (debug) mode, the backup data is sent to
  217. * /dev/null and none of the network connections back to driver
  218. * programs on the tape host are set up. The index service is
  219. * run and goes to stdout.
  220. */
  221. fprintf(stderr, "%s: running in interactive test mode\n", get_pname());
  222. fflush(stderr);
  223. }
  224. prog = NULL;
  225. disk = NULL;
  226. qdisk = NULL;
  227. amdevice = NULL;
  228. dumpdate = NULL;
  229. stroptions = NULL;
  230. program_is_backup_api=0;
  231. for(; (line = agets(stdin)) != NULL; free(line)) {
  232. if (line[0] == '\0')
  233. continue;
  234. if(interactive) {
  235. fprintf(stderr, "%s> ", get_pname());
  236. fflush(stderr);
  237. }
  238. if(strncmp_const(line, "OPTIONS ") == 0) {
  239. g_options = parse_g_options(line+8, 1);
  240. if(!g_options->hostname) {
  241. g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
  242. gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
  243. g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
  244. }
  245. if (g_options->config) {
  246. conffile = vstralloc(CONFIG_DIR, "/", g_options->config, "/",
  247. "amanda-client.conf", NULL);
  248. if (read_clientconf(conffile) > 0) {
  249. error("error reading conffile: %s", conffile);
  250. /*NOTREACHED*/
  251. }
  252. amfree(conffile);
  253. dbrename(g_options->config, DBG_SUBDIR_CLIENT);
  254. }
  255. continue;
  256. }
  257. if (prog != NULL) {
  258. err_extra = "multiple requests";
  259. goto err;
  260. }
  261. dbprintf((" sendbackup req: <%s>\n", line));
  262. s = line;
  263. ch = *s++;
  264. skip_whitespace(s, ch); /* find the program name */
  265. if(ch == '\0') {
  266. err_extra = "no program name";
  267. goto err; /* no program name */
  268. }
  269. prog = s - 1;
  270. skip_non_whitespace(s, ch);
  271. s[-1] = '\0';
  272. if(strcmp(prog,"BACKUP")==0) {
  273. program_is_backup_api=1;
  274. skip_whitespace(s, ch); /* find dumper name */
  275. if (ch == '\0') {
  276. goto err; /* no program */
  277. }
  278. prog = s - 1;
  279. skip_non_whitespace(s, ch);
  280. s[-1] = '\0';
  281. }
  282. prog = stralloc(prog);
  283. skip_whitespace(s, ch); /* find the disk name */
  284. if(ch == '\0') {
  285. err_extra = "no disk name";
  286. goto err; /* no disk name */
  287. }
  288. amfree(disk);
  289. amfree(qdisk);
  290. qdisk = s - 1;
  291. ch = *qdisk;
  292. skip_quoted_string(s, ch);
  293. s[-1] = '\0';
  294. qdisk = stralloc(qdisk);
  295. disk = unquote_string(qdisk);
  296. skip_whitespace(s, ch); /* find the device or level */
  297. if (ch == '\0') {
  298. err_extra = "bad level";
  299. goto err;
  300. }
  301. if(!isdigit((int)s[-1])) {
  302. amfree(amdevice);
  303. amfree(qamdevice);
  304. qamdevice = s - 1;
  305. ch = *qamdevice;
  306. skip_quoted_string(s, ch);
  307. s[-1] = '\0';
  308. qamdevice = stralloc(qamdevice);
  309. amdevice = unquote_string(qamdevice);
  310. skip_whitespace(s, ch); /* find level number */
  311. }
  312. else {
  313. amdevice = stralloc(disk);
  314. qamdevice = stralloc(qdisk);
  315. }
  316. /* find the level number */
  317. if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
  318. err_extra = "bad level";
  319. goto err; /* bad level */
  320. }
  321. skip_integer(s, ch);
  322. skip_whitespace(s, ch); /* find the dump date */
  323. if(ch == '\0') {
  324. err_extra = "no dumpdate";
  325. goto err; /* no dumpdate */
  326. }
  327. amfree(dumpdate);
  328. dumpdate = s - 1;
  329. skip_non_whitespace(s, ch);
  330. s[-1] = '\0';
  331. dumpdate = stralloc(dumpdate);
  332. skip_whitespace(s, ch); /* find the options keyword */
  333. if(ch == '\0') {
  334. err_extra = "no options";
  335. goto err; /* no options */
  336. }
  337. if(strncmp_const_skip(s - 1, "OPTIONS ", s, ch) != 0) {
  338. err_extra = "no OPTIONS keyword";
  339. goto err; /* no options */
  340. }
  341. skip_whitespace(s, ch); /* find the options string */
  342. if(ch == '\0') {
  343. err_extra = "bad options string";
  344. goto err; /* no options */
  345. }
  346. amfree(stroptions);
  347. stroptions = stralloc(s - 1);
  348. }
  349. amfree(line);
  350. if (prog == NULL ||
  351. disk == NULL ||
  352. amdevice == NULL ||
  353. dumpdate == NULL ||
  354. stroptions == NULL) {
  355. err_extra = "no valid sendbackup request";
  356. goto err;
  357. }
  358. dbprintf((" parsed request as: program `%s'\n", prog));
  359. dbprintf((" disk `%s'\n", qdisk));
  360. dbprintf((" device `%s'\n", qamdevice));
  361. dbprintf((" level %d\n", level));
  362. dbprintf((" since %s\n", dumpdate));
  363. dbprintf((" options `%s'\n", stroptions));
  364. if(program_is_backup_api==1) {
  365. /* check that the backup_api exist */
  366. }
  367. else {
  368. for(i = 0; programs[i]; i++) {
  369. if (strcmp(programs[i]->name, prog) == 0) {
  370. break;
  371. }
  372. }
  373. if (programs[i] == NULL) {
  374. dbprintf(("ERROR [%s: unknown program %s]\n", get_pname(), prog));
  375. error("ERROR [%s: unknown program %s]", get_pname(), prog);
  376. /*NOTREACHED*/
  377. }
  378. program = programs[i];
  379. }
  380. options = parse_options(stroptions, disk, amdevice, g_options->features, 0);
  381. if(!interactive) {
  382. datafd = DATA_FD_OFFSET + 0;
  383. mesgfd = DATA_FD_OFFSET + 2;
  384. indexfd = DATA_FD_OFFSET + 4;
  385. }
  386. if (!options->createindex)
  387. indexfd = -1;
  388. if(options->auth && amandad_auth) {
  389. if(strcasecmp(options->auth, amandad_auth) != 0) {
  390. printf("ERROR [client configured for auth=%s while server requested '%s']\n",
  391. amandad_auth, options->auth);
  392. exit(-1);
  393. }
  394. }
  395. printf("CONNECT DATA %d MESG %d INDEX %d\n",
  396. DATA_FD_OFFSET, DATA_FD_OFFSET+1,
  397. indexfd == -1 ? -1 : DATA_FD_OFFSET+2);
  398. printf("OPTIONS ");
  399. if(am_has_feature(g_options->features, fe_rep_options_features)) {
  400. printf("features=%s;", our_feature_string);
  401. }
  402. if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
  403. printf("hostname=%s;", g_options->hostname);
  404. }
  405. if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) {
  406. printf("%s", optionstr(options));
  407. }
  408. printf("\n");
  409. fflush(stdout);
  410. if (freopen("/dev/null", "w", stdout) == NULL) {
  411. dbprintf(("%s: error redirecting stdout to /dev/null: %s\n",
  412. debug_prefix_time(NULL), strerror(errno)));
  413. exit(1);
  414. }
  415. if(interactive) {
  416. if((datafd = open("/dev/null", O_RDWR)) < 0) {
  417. s = strerror(errno);
  418. error("ERROR [%s: open of /dev/null for debug data stream: %s]\n",
  419. get_pname(), s);
  420. /*NOTREACHED*/
  421. }
  422. mesgfd = 2;
  423. indexfd = 1;
  424. }
  425. if(!interactive) {
  426. if(datafd == -1 || mesgfd == -1 || (options->createindex && indexfd == -1)) {
  427. dbclose();
  428. exit(1);
  429. }
  430. }
  431. if(program_is_backup_api==1) {
  432. pid_t backup_api_pid;
  433. int i, j;
  434. char *cmd=NULL;
  435. char *argvchild[20];
  436. char levelstr[20];
  437. int property_pipe[2];
  438. backup_support_option_t *bsu;
  439. if (pipe(property_pipe) < 0) {
  440. error("Can't create pipe: %s",strerror(errno));
  441. /*NOTREACHED*/
  442. }
  443. bsu = backup_support_option(prog, g_options, disk, amdevice);
  444. switch(backup_api_pid=fork()) {
  445. case 0:
  446. aclose(property_pipe[1]);
  447. if(dup2(property_pipe[0], 0) == -1) {
  448. error("Can't dup2: %s",strerror(errno));
  449. /*NOTREACHED*/
  450. }
  451. if(dup2(datafd, 1) == -1) {
  452. error("Can't dup2: %s",strerror(errno));
  453. /*NOTREACHED*/
  454. }
  455. if(dup2(mesgfd, 2) == -1) {
  456. error("Can't dup2: %s",strerror(errno));
  457. /*NOTREACHED*/
  458. }
  459. if(indexfd != 0) {
  460. if(dup2(indexfd, 3) == -1) {
  461. error("Can't dup2: %s",strerror(errno));
  462. /*NOTREACHED*/
  463. }
  464. fcntl(indexfd, F_SETFD, 0);
  465. fcntl(3, F_SETFD, 0);
  466. }
  467. cmd = vstralloc(DUMPER_DIR, "/", prog, NULL);
  468. i=0;
  469. argvchild[i++] = prog;
  470. argvchild[i++] = "backup";
  471. if (bsu->message_line == 1) {
  472. argvchild[i++] = "--message";
  473. argvchild[i++] = "line";
  474. }
  475. if (g_options->config && bsu->config == 1) {
  476. argvchild[i++] = "--config";
  477. argvchild[i++] = g_options->config;
  478. }
  479. if (g_options->hostname && bsu->host == 1) {
  480. argvchild[i++] = "--host";
  481. argvchild[i++] = g_options->hostname;
  482. }
  483. if (disk && bsu->disk == 1) {
  484. argvchild[i++] = "--disk";
  485. argvchild[i++] = disk;
  486. }
  487. argvchild[i++] = "--device";
  488. argvchild[i++] = amdevice;
  489. if (level <= bsu->max_level) {
  490. argvchild[i++] = "--level";
  491. snprintf(levelstr,19,"%d",level);
  492. argvchild[i++] = levelstr;
  493. }
  494. if (indexfd != 0 && bsu->index_line == 1) {
  495. argvchild[i++] = "--index";
  496. argvchild[i++] = "line";
  497. }
  498. if (!options->no_record && bsu->record == 1) {
  499. argvchild[i++] = "--record";
  500. }
  501. argvchild[i] = NULL;
  502. dbprintf(("%s: running \"%s", get_pname(), cmd));
  503. for(j=1;j<i;j++) dbprintf((" %s",argvchild[j]));
  504. dbprintf(("\"\n"));
  505. backup_api_info_tapeheader(mesgfd, prog, options);
  506. execve(cmd, argvchild, safe_env());
  507. exit(1);
  508. break;
  509. default:
  510. aclose(property_pipe[0]);
  511. toolin = fdopen(property_pipe[1],"w");
  512. if (!toolin) {
  513. error("Can't fdopen: %s", strerror(errno));
  514. /*NOTREACHED*/
  515. }
  516. output_tool_property(toolin, options);
  517. fflush(toolin);
  518. fclose(toolin);
  519. break;
  520. case -1:
  521. error("%s: fork returned: %s", get_pname(), strerror(errno));
  522. }
  523. amfree(bsu);
  524. if (waitpid(backup_api_pid, &status, 0) < 0) {
  525. if (!WIFEXITED(status)) {
  526. dbprintf(("Tool exited with signal %d", WTERMSIG(status)));
  527. } else if (WEXITSTATUS(status) != 0) {
  528. dbprintf(("Tool exited with status %d", WEXITSTATUS(status)));
  529. } else {
  530. dbprintf(("waitpid returned negative value"));
  531. }
  532. }
  533. }
  534. else {
  535. if(!interactive) {
  536. /* redirect stderr */
  537. if(dup2(mesgfd, 2) == -1) {
  538. dbprintf(("%s: error redirecting stderr to fd %d: %s\n",
  539. debug_prefix_time(NULL), mesgfd, strerror(errno)));
  540. dbclose();
  541. exit(1);
  542. }
  543. }
  544. if(pipe(mesgpipe) == -1) {
  545. s = strerror(errno);
  546. dbprintf(("error [opening mesg pipe: %s]\n", s));
  547. error("error [opening mesg pipe: %s]", s);
  548. }
  549. program->start_backup(g_options->hostname, disk, amdevice, level,
  550. dumpdate, datafd, mesgpipe[1], indexfd);
  551. dbprintf(("%s: started backup\n", debug_prefix_time(NULL)));
  552. parse_backup_messages(mesgpipe[0]);
  553. dbprintf(("%s: parsed backup messages\n", debug_prefix_time(NULL)));
  554. }
  555. amfree(prog);
  556. amfree(disk);
  557. amfree(qdisk);
  558. amfree(amdevice);
  559. amfree(qamdevice);
  560. amfree(dumpdate);
  561. amfree(stroptions);
  562. amfree(our_feature_string);
  563. am_release_feature_set(our_features);
  564. our_features = NULL;
  565. am_release_feature_set(g_options->features);
  566. g_options->features = NULL;
  567. amfree(g_options->hostname);
  568. amfree(g_options->str);
  569. amfree(g_options);
  570. dbclose();
  571. malloc_size_2 = malloc_inuse(&malloc_hist_2);
  572. if(malloc_size_1 != malloc_size_2) {
  573. malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
  574. }
  575. return 0;
  576. err:
  577. printf("FORMAT ERROR IN REQUEST PACKET\n");
  578. dbprintf(("%s: REQ packet is bogus%s%s\n",
  579. debug_prefix_time(NULL),
  580. err_extra ? ": " : "",
  581. err_extra ? err_extra : ""));
  582. dbclose();
  583. return 1;
  584. }
  585. /*
  586. * Returns a string for a child process. Checks the saved dump and
  587. * compress pids to see which it is.
  588. */
  589. char *
  590. childstr(
  591. pid_t pid)
  592. {
  593. if(pid == dumppid) return program->backup_name;
  594. if(pid == comppid) return "compress";
  595. if(pid == encpid) return "encrypt";
  596. if(pid == indexpid) return "index";
  597. return "unknown";
  598. }
  599. /*
  600. * Determine if the child return status really indicates an error.
  601. * If so, add the error message to the error string; more than one
  602. * child can have an error.
  603. */
  604. int
  605. check_status(
  606. pid_t pid,
  607. amwait_t w)
  608. {
  609. char *thiserr = NULL;
  610. char *str, *strX;
  611. int ret, sig, rc;
  612. char number[NUM_STR_SIZE];
  613. char numberpid[NUM_STR_SIZE];
  614. str = childstr(pid);
  615. if(WIFSIGNALED(w)) {
  616. ret = 0;
  617. rc = sig = WTERMSIG(w);
  618. } else {
  619. sig = 0;
  620. rc = ret = WEXITSTATUS(w);
  621. }
  622. if(pid == indexpid) {
  623. /*
  624. * Treat an index failure (other than signal) as a "STRANGE"
  625. * rather than an error so the dump goes ahead and gets processed
  626. * but the failure is noted.
  627. */
  628. if(ret != 0) {
  629. fprintf(stderr, "? index %s returned %d\n", str, ret);
  630. rc = 0;
  631. }
  632. indexpid = -1;
  633. strX = "index ";
  634. } else if(pid == comppid) {
  635. /*
  636. * compress returns 2 sometimes, but it is ok.
  637. */
  638. #ifndef HAVE_GZIP
  639. if(ret == 2) {
  640. rc = 0;
  641. }
  642. #endif
  643. comppid = -1;
  644. strX = "compress ";
  645. } else if(pid == dumppid && tarpid == -1) {
  646. /*
  647. * Ultrix dump returns 1 sometimes, but it is ok.
  648. */
  649. #ifdef DUMP_RETURNS_1
  650. if(ret == 1) {
  651. rc = 0;
  652. }
  653. #endif
  654. dumppid = -1;
  655. strX = "dump ";
  656. } else if(pid == tarpid) {
  657. if (ret == 1) {
  658. rc = 0;
  659. }
  660. /*
  661. * tar bitches about active filesystems, but we do not care.
  662. */
  663. #ifdef IGNORE_TAR_ERRORS
  664. if(ret == 2) {
  665. rc = 0;
  666. }
  667. #endif
  668. dumppid = tarpid = -1;
  669. strX = "dump ";
  670. } else {
  671. strX = "unknown ";
  672. }
  673. if(rc == 0) {
  674. return 0; /* normal exit */
  675. }
  676. snprintf(numberpid, SIZEOF(number), "%d", (int)pid);
  677. if(ret == 0) {
  678. snprintf(number, SIZEOF(number), "%d", sig);
  679. thiserr = vstralloc(strX, "(", numberpid, ") ", str, " got signal ", number, NULL);
  680. } else {
  681. snprintf(number, SIZEOF(number), "%d", ret);
  682. thiserr = vstralloc(strX, "(", numberpid, ") ", str, " returned ", number, NULL);
  683. }
  684. if(errorstr) {
  685. strappend(errorstr, ", ");
  686. strappend(errorstr, thiserr);
  687. amfree(thiserr);
  688. } else {
  689. errorstr = thiserr;
  690. thiserr = NULL;
  691. }
  692. return 1;
  693. }
  694. /*
  695. *Send header info to the message file.
  696. */
  697. void
  698. info_tapeheader(void)
  699. {
  700. fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
  701. fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
  702. if (options->compress == COMP_FAST || options->compress == COMP_BEST)
  703. fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
  704. #ifdef UNCOMPRESS_OPT
  705. UNCOMPRESS_OPT
  706. #else
  707. ""
  708. #endif
  709. );
  710. fprintf(stderr, "%s -xpGf - ...\n", program->restore_name);
  711. if (options->compress == COMP_FAST || options->compress == COMP_BEST)
  712. fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
  713. get_pname(), COMPRESS_SUFFIX);
  714. fprintf(stderr, "%s: info end\n", get_pname());
  715. }
  716. void
  717. backup_api_info_tapeheader(
  718. int mesgfd,
  719. char *prog,
  720. option_t *options)
  721. {
  722. char line[1024];
  723. snprintf(line, 1024, "%s: info BACKUP=DUMPER\n", get_pname());
  724. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  725. dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
  726. return;
  727. }
  728. snprintf(line, 1024, "%s: info DUMPER=%s\n", get_pname(), prog);
  729. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  730. dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
  731. return;
  732. }
  733. snprintf(line, 1024, "%s: info RECOVER_CMD=", get_pname());
  734. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  735. dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
  736. return;
  737. }
  738. if (options->compress) {
  739. snprintf(line, 1024, "%s %s |", UNCOMPRESS_PATH,
  740. #ifdef UNCOMPRESS_OPT
  741. UNCOMPRESS_OPT
  742. #else
  743. ""
  744. #endif
  745. );
  746. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  747. dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
  748. return;
  749. }
  750. }
  751. snprintf(line, 1024, "%s -f... -\n", prog);
  752. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  753. dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
  754. return;
  755. }
  756. if (options->compress) {
  757. snprintf(line, 1024, "%s: info COMPRESS_SUFFIX=%s\n",
  758. get_pname(), COMPRESS_SUFFIX);
  759. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  760. dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
  761. return;
  762. }
  763. }
  764. snprintf(line, 1024, "%s: info end\n", get_pname());
  765. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  766. dbprintf(("error writing to mesgfd socket: %s", strerror(errno)));
  767. return;
  768. }
  769. }
  770. pid_t
  771. pipefork(
  772. void (*func)(void),
  773. char * fname,
  774. int * stdinfd,
  775. int stdoutfd,
  776. int stderrfd)
  777. {
  778. int inpipe[2];
  779. pid_t pid;
  780. dbprintf(("%s: forking function %s in pipeline\n",
  781. debug_prefix_time(NULL), fname));
  782. if(pipe(inpipe) == -1) {
  783. error("error [open pipe to %s: %s]", fname, strerror(errno));
  784. /*NOTREACHED*/
  785. }
  786. switch(pid = fork()) {
  787. case -1:
  788. error("error [fork %s: %s]", fname, strerror(errno));
  789. /*NOTREACHED*/
  790. default: /* parent process */
  791. aclose(inpipe[0]); /* close input side of pipe */
  792. *stdinfd = inpipe[1];
  793. break;
  794. case 0: /* child process */
  795. aclose(inpipe[1]); /* close output side of pipe */
  796. if(dup2(inpipe[0], 0) == -1) {
  797. error("error [fork %s: dup2(%d, in): %s]",
  798. fname, inpipe[0], strerror(errno));
  799. /*NOTRACHED*/
  800. }
  801. if(dup2(stdoutfd, 1) == -1) {
  802. error("error [fork %s: dup2(%d, out): %s]",
  803. fname, stdoutfd, strerror(errno));
  804. /*NOTRACHED*/
  805. }
  806. if(dup2(stderrfd, 2) == -1) {
  807. error("error [fork %s: dup2(%d, err): %s]",
  808. fname, stderrfd, strerror(errno));
  809. /*NOTRACHED*/
  810. }
  811. func();
  812. exit(0);
  813. /*NOTREACHED*/
  814. }
  815. return pid;
  816. }
  817. void
  818. parse_backup_messages(
  819. int mesgin)
  820. {
  821. int goterror;
  822. pid_t wpid;
  823. amwait_t retstat;
  824. char *line;
  825. goterror = 0;
  826. amfree(errorstr);
  827. for(; (line = areads(mesgin)) != NULL; free(line)) {
  828. process_dumpline(line);
  829. }
  830. if(errno) {
  831. error("error [read mesg pipe: %s]", strerror(errno));
  832. /*NOTREACHED*/
  833. }
  834. while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
  835. if(check_status(wpid, retstat)) goterror = 1;
  836. }
  837. if (dumppid != -1) {
  838. sleep(5);
  839. while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
  840. if(check_status(wpid, retstat)) goterror = 1;
  841. }
  842. }
  843. if (dumppid != -1) {
  844. dbprintf(("%s: Sending SIGHUP to dump process %d\n",
  845. debug_prefix_time(NULL), (int)dumppid));
  846. if(dumppid != -1) {
  847. if(kill(dumppid, SIGHUP) == -1) {
  848. dbprintf(("%s: Can't send SIGHUP to %d: %s\n",
  849. debug_prefix_time(NULL), (int)dumppid,
  850. strerror(errno)));
  851. }
  852. }
  853. sleep(5);
  854. while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
  855. if(check_status(wpid, retstat)) goterror = 1;
  856. }
  857. }
  858. if (dumppid != -1) {
  859. dbprintf(("%s: Sending SIGKILL to dump process %d\n",
  860. debug_prefix_time(NULL), (int)dumppid));
  861. if(dumppid != -1) {
  862. if(kill(dumppid, SIGKILL) == -1) {
  863. dbprintf(("%s: Can't send SIGKILL to %d: %s\n",
  864. debug_prefix_time(NULL), (int)dumppid,
  865. strerror(errno)));
  866. }
  867. }
  868. sleep(5);
  869. while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
  870. if(check_status(wpid, retstat)) goterror = 1;
  871. }
  872. }
  873. if(errorstr) {
  874. error("error [%s]", errorstr);
  875. /*NOTREACHED*/
  876. } else if(dump_size == -1) {
  877. error("error [no backup size line]");
  878. /*NOTREACHED*/
  879. }
  880. program->end_backup(goterror);
  881. fprintf(stderr, "%s: size %ld\n", get_pname(), dump_size);
  882. fprintf(stderr, "%s: end\n", get_pname());
  883. }
  884. /*
  885. * Returns the value of the first integer in a string.
  886. */
  887. double
  888. the_num(
  889. char * str,
  890. int pos)
  891. {
  892. char *num;
  893. int ch;
  894. double d;
  895. do {
  896. ch = *str++;
  897. while(ch && !isdigit(ch)) ch = *str++;
  898. if (pos == 1) break;
  899. pos--;
  900. while(ch && (isdigit(ch) || ch == '.')) ch = *str++;
  901. } while (ch);
  902. num = str - 1;
  903. while(isdigit(ch) || ch == '.') ch = *str++;
  904. str[-1] = '\0';
  905. d = atof(num);
  906. str[-1] = (char)ch;
  907. return d;
  908. }
  909. static void
  910. process_dumpline(
  911. char * str)
  912. {
  913. amregex_t *rp;
  914. char *type;
  915. char startchr;
  916. for(rp = program->re_table; rp->regex != NULL; rp++) {
  917. if(match(rp->regex, str)) {
  918. break;
  919. }
  920. }
  921. if(rp->typ == DMP_SIZE) {
  922. dump_size = (long)((the_num(str, rp->field)* rp->scale+1023.0)/1024.0);
  923. }
  924. switch(rp->typ) {
  925. case DMP_NORMAL:
  926. type = "normal";
  927. startchr = '|';
  928. break;
  929. case DMP_STRANGE:
  930. type = "strange";
  931. startchr = '?';
  932. break;
  933. case DMP_SIZE:
  934. type = "size";
  935. startchr = '|';
  936. break;
  937. case DMP_ERROR:
  938. type = "error";
  939. startchr = '?';
  940. break;
  941. default:
  942. /*
  943. * Should never get here.
  944. */
  945. type = "unknown";
  946. startchr = '!';
  947. break;
  948. }
  949. dbprintf(("%s: %3d: %7s(%c): %s\n",
  950. debug_prefix_time(NULL),
  951. rp->srcline,
  952. type,
  953. startchr,
  954. str));
  955. fprintf(stderr, "%c %s\n", startchr, str);
  956. }
  957. /*
  958. * start_index. Creates an index file from the output of dump/tar.
  959. * It arranges that input is the fd to be written by the dump process.
  960. * If createindex is not enabled, it does nothing. If it is not, a
  961. * new process will be created that tees input both to a pipe whose
  962. * read fd is dup2'ed input and to a program that outputs an index
  963. * file to `index'.
  964. *
  965. * make sure that the chat from restore doesn't go to stderr cause
  966. * this goes back to amanda which doesn't expect to see it
  967. * (2>/dev/null should do it)
  968. *
  969. * Originally by Alan M. McIvor, 13 April 1996
  970. *
  971. * Adapted by Alexandre Oliva, 1 May 1997
  972. *
  973. * This program owes a lot to tee.c from GNU sh-utils and dumptee.c
  974. * from the DeeJay backup package.
  975. */
  976. static void
  977. save_fd(
  978. int * fd,
  979. int min)
  980. {
  981. int origfd = *fd;
  982. while (*fd >= 0 && *fd < min) {
  983. int newfd = dup(*fd);
  984. if (newfd == -1)
  985. dbprintf(("%s: unable to save file descriptor [%s]\n",
  986. debug_prefix_time(NULL), strerror(errno)));
  987. *fd = newfd;
  988. }
  989. if (origfd != *fd)
  990. dbprintf(("%s: dupped file descriptor %i to %i\n",
  991. debug_prefix_time(NULL), origfd, *fd));
  992. }
  993. void
  994. start_index(
  995. int createindex,
  996. int input,
  997. int mesg,
  998. int index,
  999. char * cmd)
  1000. {
  1001. int pipefd[2];
  1002. FILE *pipe_fp;
  1003. int exitcode;
  1004. if (!createindex)
  1005. return;
  1006. if (pipe(pipefd) != 0) {
  1007. error("creating index pipe: %s", strerror(errno));
  1008. /*NOTREACHED*/
  1009. }
  1010. switch(indexpid = fork()) {
  1011. case -1:
  1012. error("forking index tee process: %s", strerror(errno));
  1013. /*NOTREACHED*/
  1014. default:
  1015. aclose(pipefd[0]);
  1016. if (dup2(pipefd[1], input) == -1) {
  1017. error("dup'ping index tee output: %s", strerror(errno));
  1018. /*NOTREACHED*/
  1019. }
  1020. aclose(pipefd[1]);
  1021. return;
  1022. case 0:
  1023. break;
  1024. }
  1025. /* now in a child process */
  1026. save_fd(&pipefd[0], 4);
  1027. save_fd(&index, 4);
  1028. save_fd(&mesg, 4);
  1029. save_fd(&input, 4);
  1030. dup2(pipefd[0], 0);
  1031. dup2(index, 1);
  1032. dup2(mesg, 2);
  1033. dup2(input, 3);
  1034. for(index = 4; index < FD_SETSIZE; index++) {
  1035. if (index != dbfd()) {
  1036. close(index);
  1037. }
  1038. }
  1039. if ((pipe_fp = popen(cmd, "w")) == NULL) {
  1040. error("couldn't start index creator [%s]", strerror(errno));
  1041. /*NOTREACHED*/
  1042. }
  1043. dbprintf(("%s: started index creator: \"%s\"\n",
  1044. debug_prefix_time(NULL), cmd));
  1045. while(1) {
  1046. char buffer[BUFSIZ], *ptr;
  1047. ssize_t bytes_read;
  1048. size_t bytes_written;
  1049. ssize_t just_written;
  1050. do {
  1051. bytes_read = read(0, buffer, SIZEOF(buffer));
  1052. } while ((bytes_read < 0) && ((errno == EINTR) || (errno == EAGAIN)));
  1053. if (bytes_read < 0) {
  1054. error("index tee cannot read [%s]", strerror(errno));
  1055. /*NOTREACHED*/
  1056. }
  1057. if (bytes_read == 0)
  1058. break; /* finished */
  1059. /* write the stuff to the subprocess */
  1060. ptr = buffer;
  1061. bytes_written = 0;
  1062. just_written = fullwrite(fileno(pipe_fp), ptr, (size_t)bytes_read);
  1063. if (just_written < 0) {
  1064. /*
  1065. * just as we waited for write() to complete.
  1066. */
  1067. if (errno != EPIPE) {
  1068. dbprintf(("%s: index tee cannot write to index creator [%s]\n",
  1069. debug_prefix_time(NULL), strerror(errno)));
  1070. }
  1071. } else {
  1072. bytes_written += just_written;
  1073. ptr += just_written;
  1074. }
  1075. /* write the stuff to stdout, ensuring none lost when interrupt
  1076. occurs */
  1077. ptr = buffer;
  1078. bytes_written = 0;
  1079. just_written = fullwrite(3, ptr, (size_t)bytes_read);
  1080. if (just_written < 0) {
  1081. error("index tee cannot write [%s]", strerror(errno));
  1082. /*NOTREACHED*/
  1083. } else {
  1084. bytes_written += just_written;
  1085. ptr += just_written;
  1086. }
  1087. }
  1088. aclose(pipefd[1]);
  1089. /* finished */
  1090. /* check the exit code of the pipe and moan if not 0 */
  1091. if ((exitcode = pclose(pipe_fp)) != 0) {
  1092. dbprintf(("%s: index pipe returned %d\n",
  1093. debug_prefix_time(NULL), exitcode));
  1094. } else {
  1095. dbprintf(("%s: index created successfully\n", debug_prefix_time(NULL)));
  1096. }
  1097. pipe_fp = NULL;
  1098. exit(exitcode);
  1099. }
  1100. extern backup_program_t dump_program, gnutar_program;
  1101. backup_program_t *programs[] = {
  1102. &dump_program, &gnutar_program, NULL
  1103. };