PageRenderTime 58ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
C | 1229 lines | 957 code | 138 blank | 134 comment | 308 complexity | 71c8e3bb768b945cf47e468fd193745f 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, ...) do { \
  42. if ((i) <= debug_sendbackup) { \
  43. dbprintf(__VA_LIST__); \
  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. int i;
  177. int ch;
  178. FILE *toolin;
  179. int status;
  180. /* initialize */
  181. /*
  182. * Configure program for internationalization:
  183. * 1) Only set the message locale for now.
  184. * 2) Set textdomain for all amanda related programs to "amanda"
  185. * We don't want to be forced to support dozens of message catalogs.
  186. */
  187. setlocale(LC_MESSAGES, "C");
  188. textdomain("amanda");
  189. safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
  190. safe_cd();
  191. set_pname("sendbackup");
  192. /* Don't die when child closes pipe */
  193. signal(SIGPIPE, SIG_IGN);
  194. /* Don't die when interrupt received */
  195. signal(SIGINT, SIG_IGN);
  196. if(argc > 1 && strcmp(argv[1],"-t") == 0) {
  197. interactive = 1;
  198. argc--;
  199. argv++;
  200. } else {
  201. interactive = 0;
  202. }
  203. erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
  204. dbopen(DBG_SUBDIR_CLIENT);
  205. startclock();
  206. dbprintf(_("Version %s\n"), version());
  207. if(argc > 2 && strcmp(argv[1], "amandad") == 0) {
  208. amandad_auth = stralloc(argv[2]);
  209. }
  210. our_features = am_init_feature_set();
  211. our_feature_string = am_feature_to_string(our_features);
  212. config_init(CONFIG_INIT_CLIENT, NULL);
  213. check_running_as(RUNNING_AS_CLIENT_LOGIN);
  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. g_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. g_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. /* overlay this configuration on the existing (nameless) configuration */
  247. config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
  248. g_options->config);
  249. dbrename(config_name, DBG_SUBDIR_CLIENT);
  250. }
  251. continue;
  252. }
  253. if (prog != NULL) {
  254. err_extra = _("multiple requests");
  255. goto err;
  256. }
  257. dbprintf(_(" sendbackup req: <%s>\n"), line);
  258. s = line;
  259. ch = *s++;
  260. skip_whitespace(s, ch); /* find the program name */
  261. if(ch == '\0') {
  262. err_extra = _("no program name");
  263. goto err; /* no program name */
  264. }
  265. prog = s - 1;
  266. skip_non_whitespace(s, ch);
  267. s[-1] = '\0';
  268. if(strcmp(prog,"BACKUP")==0) {
  269. program_is_backup_api=1;
  270. skip_whitespace(s, ch); /* find dumper name */
  271. if (ch == '\0') {
  272. goto err; /* no program */
  273. }
  274. prog = s - 1;
  275. skip_non_whitespace(s, ch);
  276. s[-1] = '\0';
  277. }
  278. prog = stralloc(prog);
  279. skip_whitespace(s, ch); /* find the disk name */
  280. if(ch == '\0') {
  281. err_extra = _("no disk name");
  282. goto err; /* no disk name */
  283. }
  284. amfree(disk);
  285. amfree(qdisk);
  286. qdisk = s - 1;
  287. ch = *qdisk;
  288. skip_quoted_string(s, ch);
  289. s[-1] = '\0';
  290. qdisk = stralloc(qdisk);
  291. disk = unquote_string(qdisk);
  292. skip_whitespace(s, ch); /* find the device or level */
  293. if (ch == '\0') {
  294. err_extra = _("bad level");
  295. goto err;
  296. }
  297. if(!isdigit((int)s[-1])) {
  298. amfree(amdevice);
  299. amfree(qamdevice);
  300. qamdevice = s - 1;
  301. ch = *qamdevice;
  302. skip_quoted_string(s, ch);
  303. s[-1] = '\0';
  304. qamdevice = stralloc(qamdevice);
  305. amdevice = unquote_string(qamdevice);
  306. skip_whitespace(s, ch); /* find level number */
  307. }
  308. else {
  309. amdevice = stralloc(disk);
  310. qamdevice = stralloc(qdisk);
  311. }
  312. /* find the level number */
  313. if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
  314. err_extra = _("bad level");
  315. goto err; /* bad level */
  316. }
  317. skip_integer(s, ch);
  318. skip_whitespace(s, ch); /* find the dump date */
  319. if(ch == '\0') {
  320. err_extra = _("no dumpdate");
  321. goto err; /* no dumpdate */
  322. }
  323. amfree(dumpdate);
  324. dumpdate = s - 1;
  325. skip_non_whitespace(s, ch);
  326. s[-1] = '\0';
  327. dumpdate = stralloc(dumpdate);
  328. skip_whitespace(s, ch); /* find the options keyword */
  329. if(ch == '\0') {
  330. err_extra = _("no options");
  331. goto err; /* no options */
  332. }
  333. if(strncmp_const_skip(s - 1, "OPTIONS ", s, ch) != 0) {
  334. err_extra = _("no OPTIONS keyword");
  335. goto err; /* no options */
  336. }
  337. skip_whitespace(s, ch); /* find the options string */
  338. if(ch == '\0') {
  339. err_extra = _("bad options string");
  340. goto err; /* no options */
  341. }
  342. amfree(stroptions);
  343. stroptions = stralloc(s - 1);
  344. }
  345. amfree(line);
  346. if (g_options == NULL) {
  347. printf(_("ERROR [Missing OPTIONS line in sendbackup input]\n"));
  348. error(_("Missing OPTIONS line in sendbackup input\n"));
  349. /*NOTREACHED*/
  350. }
  351. if (prog == NULL ||
  352. disk == NULL ||
  353. amdevice == NULL ||
  354. dumpdate == NULL ||
  355. stroptions == NULL) {
  356. err_extra = _("no valid sendbackup request");
  357. goto err;
  358. }
  359. dbprintf(_(" Parsed request as: program `%s'\n"), prog);
  360. dbprintf(_(" disk `%s'\n"), qdisk);
  361. dbprintf(_(" device `%s'\n"), qamdevice);
  362. dbprintf(_(" level %d\n"), level);
  363. dbprintf(_(" since %s\n"), dumpdate);
  364. dbprintf(_(" options `%s'\n"), stroptions);
  365. if(program_is_backup_api==1) {
  366. /* check that the backup_api exist */
  367. }
  368. else {
  369. for(i = 0; programs[i]; i++) {
  370. if (strcmp(programs[i]->name, prog) == 0) {
  371. break;
  372. }
  373. }
  374. if (programs[i] == NULL) {
  375. dbprintf(_("ERROR [%s: unknown program %s]\n"), get_pname(), prog);
  376. error(_("ERROR [%s: unknown program %s]"), get_pname(), prog);
  377. /*NOTREACHED*/
  378. }
  379. program = programs[i];
  380. }
  381. options = parse_options(stroptions, disk, amdevice, g_options->features, 0);
  382. if(!interactive) {
  383. datafd = DATA_FD_OFFSET + 0;
  384. mesgfd = DATA_FD_OFFSET + 2;
  385. indexfd = DATA_FD_OFFSET + 4;
  386. }
  387. if (!options->createindex)
  388. indexfd = -1;
  389. if(options->auth && amandad_auth) {
  390. if(strcasecmp(options->auth, amandad_auth) != 0) {
  391. g_printf(_("ERROR [client configured for auth=%s while server requested '%s']\n"),
  392. amandad_auth, options->auth);
  393. exit(-1);
  394. }
  395. }
  396. if (options->kencrypt) {
  397. g_printf("KENCRYPT\n");
  398. }
  399. g_printf(_("CONNECT DATA %d MESG %d INDEX %d\n"),
  400. DATA_FD_OFFSET, DATA_FD_OFFSET+1,
  401. indexfd == -1 ? -1 : DATA_FD_OFFSET+2);
  402. g_printf(_("OPTIONS "));
  403. if(am_has_feature(g_options->features, fe_rep_options_features)) {
  404. g_printf("features=%s;", our_feature_string);
  405. }
  406. if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
  407. g_printf("hostname=%s;", g_options->hostname);
  408. }
  409. if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) {
  410. g_printf("%s", optionstr(options));
  411. }
  412. g_printf("\n");
  413. fflush(stdout);
  414. if (freopen("/dev/null", "w", stdout) == NULL) {
  415. dbprintf(_("Error redirecting stdout to /dev/null: %s\n"),
  416. strerror(errno));
  417. exit(1);
  418. }
  419. if(interactive) {
  420. if((datafd = open("/dev/null", O_RDWR)) < 0) {
  421. error(_("ERROR [open of /dev/null for debug data stream: %s]\n"),
  422. strerror(errno));
  423. /*NOTREACHED*/
  424. }
  425. mesgfd = 2;
  426. indexfd = 1;
  427. }
  428. if(!interactive) {
  429. if(datafd == -1 || mesgfd == -1 || (options->createindex && indexfd == -1)) {
  430. dbclose();
  431. exit(1);
  432. }
  433. }
  434. if(program_is_backup_api==1) {
  435. pid_t backup_api_pid;
  436. int i, j;
  437. char *cmd=NULL;
  438. char *argvchild[20];
  439. char levelstr[20];
  440. int property_pipe[2];
  441. backup_support_option_t *bsu;
  442. if (pipe(property_pipe) < 0) {
  443. error(_("Can't create pipe: %s"),strerror(errno));
  444. /*NOTREACHED*/
  445. }
  446. bsu = backup_support_option(prog, g_options, disk, amdevice);
  447. switch(backup_api_pid=fork()) {
  448. case 0:
  449. aclose(property_pipe[1]);
  450. if(dup2(property_pipe[0], 0) == -1) {
  451. error(_("Can't dup2: %s"),strerror(errno));
  452. /*NOTREACHED*/
  453. }
  454. if(dup2(datafd, 1) == -1) {
  455. error(_("Can't dup2: %s"),strerror(errno));
  456. /*NOTREACHED*/
  457. }
  458. if(dup2(mesgfd, 2) == -1) {
  459. error(_("Can't dup2: %s"),strerror(errno));
  460. /*NOTREACHED*/
  461. }
  462. if(indexfd != 0) {
  463. if(dup2(indexfd, 3) == -1) {
  464. error(_("Can't dup2: %s"),strerror(errno));
  465. /*NOTREACHED*/
  466. }
  467. fcntl(indexfd, F_SETFD, 0);
  468. fcntl(3, F_SETFD, 0);
  469. safe_fd(3, 1);
  470. } else {
  471. safe_fd(-1, 0);
  472. }
  473. cmd = vstralloc(DUMPER_DIR, "/", prog, NULL);
  474. i=0;
  475. argvchild[i++] = prog;
  476. argvchild[i++] = "backup";
  477. if (bsu->message_line == 1) {
  478. argvchild[i++] = "--message";
  479. argvchild[i++] = "line";
  480. }
  481. if (g_options->config && bsu->config == 1) {
  482. argvchild[i++] = "--config";
  483. argvchild[i++] = g_options->config;
  484. }
  485. if (g_options->hostname && bsu->host == 1) {
  486. argvchild[i++] = "--host";
  487. argvchild[i++] = g_options->hostname;
  488. }
  489. if (disk && bsu->disk == 1) {
  490. argvchild[i++] = "--disk";
  491. argvchild[i++] = disk;
  492. }
  493. argvchild[i++] = "--device";
  494. argvchild[i++] = amdevice;
  495. if (level <= bsu->max_level) {
  496. argvchild[i++] = "--level";
  497. g_snprintf(levelstr,19,"%d",level);
  498. argvchild[i++] = levelstr;
  499. }
  500. if (indexfd != 0 && bsu->index_line == 1) {
  501. argvchild[i++] = "--index";
  502. argvchild[i++] = "line";
  503. }
  504. if (!options->no_record && bsu->record == 1) {
  505. argvchild[i++] = "--record";
  506. }
  507. argvchild[i] = NULL;
  508. dbprintf(_("%s: running \"%s"), get_pname(), cmd);
  509. for(j=1;j<i;j++) dbprintf(" %s",argvchild[j]);
  510. dbprintf(_("\"\n"));
  511. backup_api_info_tapeheader(mesgfd, prog, options);
  512. execve(cmd, argvchild, safe_env());
  513. exit(1);
  514. break;
  515. default:
  516. aclose(property_pipe[0]);
  517. toolin = fdopen(property_pipe[1],"w");
  518. if (!toolin) {
  519. error(_("Can't fdopen: %s"), strerror(errno));
  520. /*NOTREACHED*/
  521. }
  522. output_tool_property(toolin, options);
  523. fflush(toolin);
  524. fclose(toolin);
  525. break;
  526. case -1:
  527. error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
  528. }
  529. amfree(bsu);
  530. if (waitpid(backup_api_pid, &status, 0) < 0) {
  531. if (!WIFEXITED(status)) {
  532. dbprintf(_("Tool exited with signal %d"), WTERMSIG(status));
  533. } else if (WEXITSTATUS(status) != 0) {
  534. dbprintf(_("Tool exited with status %d"), WEXITSTATUS(status));
  535. } else {
  536. dbprintf(_("waitpid returned negative value"));
  537. }
  538. }
  539. }
  540. else {
  541. if(!interactive) {
  542. /* redirect stderr */
  543. if(dup2(mesgfd, 2) == -1) {
  544. dbprintf(_("Error redirecting stderr to fd %d: %s\n"),
  545. mesgfd, strerror(errno));
  546. dbclose();
  547. exit(1);
  548. }
  549. }
  550. if(pipe(mesgpipe) == -1) {
  551. s = strerror(errno);
  552. dbprintf(_("error [opening mesg pipe: %s]\n"), s);
  553. error(_("error [opening mesg pipe: %s]"), s);
  554. }
  555. program->start_backup(g_options->hostname, disk, amdevice, level,
  556. dumpdate, datafd, mesgpipe[1], indexfd);
  557. dbprintf(_("Started backup\n"));
  558. parse_backup_messages(mesgpipe[0]);
  559. dbprintf(_("Parsed backup messages\n"));
  560. }
  561. amfree(prog);
  562. amfree(disk);
  563. amfree(qdisk);
  564. amfree(amdevice);
  565. amfree(qamdevice);
  566. amfree(dumpdate);
  567. amfree(stroptions);
  568. amfree(our_feature_string);
  569. am_release_feature_set(our_features);
  570. our_features = NULL;
  571. free_g_options(g_options);
  572. dbclose();
  573. return 0;
  574. err:
  575. g_printf(_("FORMAT ERROR IN REQUEST PACKET\n"));
  576. dbprintf(_("REQ packet is bogus%s%s\n"),
  577. err_extra ? ": " : "",
  578. err_extra ? err_extra : "");
  579. dbclose();
  580. return 1;
  581. }
  582. /*
  583. * Returns a string for a child process. Checks the saved dump and
  584. * compress pids to see which it is.
  585. */
  586. char *
  587. childstr(
  588. pid_t pid)
  589. {
  590. if(pid == dumppid) return program->backup_name;
  591. if(pid == comppid) return "compress";
  592. if(pid == encpid) return "encrypt";
  593. if(pid == indexpid) return "index";
  594. return "unknown";
  595. }
  596. /*
  597. * Determine if the child return status really indicates an error.
  598. * If so, add the error message to the error string; more than one
  599. * child can have an error.
  600. */
  601. int
  602. check_status(
  603. pid_t pid,
  604. amwait_t w)
  605. {
  606. char *thiserr = NULL;
  607. char *str, *strX;
  608. int ret, sig, rc;
  609. str = childstr(pid);
  610. if(WIFSIGNALED(w)) {
  611. ret = 0;
  612. rc = sig = WTERMSIG(w);
  613. } else {
  614. sig = 0;
  615. rc = ret = WEXITSTATUS(w);
  616. }
  617. if(pid == indexpid) {
  618. /*
  619. * Treat an index failure (other than signal) as a "STRANGE"
  620. * rather than an error so the dump goes ahead and gets processed
  621. * but the failure is noted.
  622. */
  623. if(ret != 0) {
  624. g_fprintf(stderr, _("? index %s returned %d\n"), str, ret);
  625. rc = 0;
  626. }
  627. indexpid = -1;
  628. strX = "index ";
  629. } else if(pid == comppid) {
  630. /*
  631. * compress returns 2 sometimes, but it is ok.
  632. */
  633. #ifndef HAVE_GZIP
  634. if(ret == 2) {
  635. rc = 0;
  636. }
  637. #endif
  638. comppid = -1;
  639. strX = "compress ";
  640. } else if(pid == dumppid && tarpid == -1) {
  641. /*
  642. * Ultrix dump returns 1 sometimes, but it is ok.
  643. */
  644. #ifdef DUMP_RETURNS_1
  645. if(ret == 1) {
  646. rc = 0;
  647. }
  648. #endif
  649. dumppid = -1;
  650. strX = "dump ";
  651. } else if(pid == tarpid) {
  652. if (ret == 1) {
  653. rc = 0;
  654. }
  655. /*
  656. * tar bitches about active filesystems, but we do not care.
  657. */
  658. #ifdef IGNORE_TAR_ERRORS
  659. if(ret == 2) {
  660. rc = 0;
  661. }
  662. #endif
  663. dumppid = tarpid = -1;
  664. strX = "dump ";
  665. } else {
  666. strX = "unknown ";
  667. }
  668. if(rc == 0) {
  669. return 0; /* normal exit */
  670. }
  671. if(ret == 0) {
  672. thiserr = vstrallocf(_("%s (%d) %s got signal %d"), strX, (int)pid, str,
  673. sig);
  674. } else {
  675. thiserr = vstrallocf(_("%s (%d) %s returned %d"), strX, (int)pid, str, ret);
  676. }
  677. if(errorstr) {
  678. errorstr = newvstrallocf(errorstr, "%s, %s", errorstr, thiserr);
  679. amfree(thiserr);
  680. } else {
  681. errorstr = thiserr;
  682. thiserr = NULL;
  683. }
  684. return 1;
  685. }
  686. /*
  687. *Send header info to the message file.
  688. */
  689. void
  690. info_tapeheader(void)
  691. {
  692. g_fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
  693. g_fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
  694. if (options->compress == COMP_FAST || options->compress == COMP_BEST)
  695. g_fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
  696. #ifdef UNCOMPRESS_OPT
  697. UNCOMPRESS_OPT
  698. #else
  699. ""
  700. #endif
  701. );
  702. g_fprintf(stderr, "%s -xpGf - ...\n", program->restore_name);
  703. if (options->compress == COMP_FAST || options->compress == COMP_BEST)
  704. g_fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
  705. get_pname(), COMPRESS_SUFFIX);
  706. g_fprintf(stderr, "%s: info end\n", get_pname());
  707. }
  708. void
  709. backup_api_info_tapeheader(
  710. int mesgfd,
  711. char *prog,
  712. option_t *options)
  713. {
  714. char line[1024];
  715. g_snprintf(line, 1024, "%s: info BACKUP=DUMPER\n", get_pname());
  716. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  717. dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
  718. return;
  719. }
  720. g_snprintf(line, 1024, "%s: info DUMPER=%s\n", get_pname(), prog);
  721. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  722. dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
  723. return;
  724. }
  725. g_snprintf(line, 1024, "%s: info RECOVER_CMD=", get_pname());
  726. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  727. dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
  728. return;
  729. }
  730. if (options->compress) {
  731. g_snprintf(line, 1024, "%s %s |", UNCOMPRESS_PATH,
  732. #ifdef UNCOMPRESS_OPT
  733. UNCOMPRESS_OPT
  734. #else
  735. ""
  736. #endif
  737. );
  738. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  739. dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
  740. return;
  741. }
  742. }
  743. g_snprintf(line, 1024, "%s -f... -\n", prog);
  744. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  745. dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
  746. return;
  747. }
  748. if (options->compress) {
  749. g_snprintf(line, 1024, "%s: info COMPRESS_SUFFIX=%s\n",
  750. get_pname(), COMPRESS_SUFFIX);
  751. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  752. dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
  753. return;
  754. }
  755. }
  756. g_snprintf(line, 1024, "%s: info end\n", get_pname());
  757. if (fullwrite(mesgfd, line, strlen(line)) != (ssize_t)strlen(line)) {
  758. dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
  759. return;
  760. }
  761. }
  762. pid_t
  763. pipefork(
  764. void (*func)(void),
  765. char * fname,
  766. int * stdinfd,
  767. int stdoutfd,
  768. int stderrfd)
  769. {
  770. int inpipe[2];
  771. pid_t pid;
  772. dbprintf(_("Forking function %s in pipeline\n"), fname);
  773. if(pipe(inpipe) == -1) {
  774. error(_("error [open pipe to %s: %s]"), fname, strerror(errno));
  775. /*NOTREACHED*/
  776. }
  777. switch(pid = fork()) {
  778. case -1:
  779. error(_("error [fork %s: %s]"), fname, strerror(errno));
  780. /*NOTREACHED*/
  781. default: /* parent process */
  782. aclose(inpipe[0]); /* close input side of pipe */
  783. *stdinfd = inpipe[1];
  784. break;
  785. case 0: /* child process */
  786. aclose(inpipe[1]); /* close output side of pipe */
  787. if(dup2(inpipe[0], 0) == -1) {
  788. error(_("error [fork %s: dup2(%d, in): %s]"),
  789. fname, inpipe[0], strerror(errno));
  790. /*NOTRACHED*/
  791. }
  792. if(dup2(stdoutfd, 1) == -1) {
  793. error(_("error [fork %s: dup2(%d, out): %s]"),
  794. fname, stdoutfd, strerror(errno));
  795. /*NOTRACHED*/
  796. }
  797. if(dup2(stderrfd, 2) == -1) {
  798. error(_("error [fork %s: dup2(%d, err): %s]"),
  799. fname, stderrfd, strerror(errno));
  800. /*NOTRACHED*/
  801. }
  802. func();
  803. exit(0);
  804. /*NOTREACHED*/
  805. }
  806. return pid;
  807. }
  808. void
  809. parse_backup_messages(
  810. int mesgin)
  811. {
  812. int goterror;
  813. pid_t wpid;
  814. amwait_t retstat;
  815. char *line;
  816. goterror = 0;
  817. amfree(errorstr);
  818. for(; (line = areads(mesgin)) != NULL; free(line)) {
  819. process_dumpline(line);
  820. }
  821. if(errno) {
  822. error(_("error [read mesg pipe: %s]"), strerror(errno));
  823. /*NOTREACHED*/
  824. }
  825. while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
  826. if(check_status(wpid, retstat)) goterror = 1;
  827. }
  828. if (dumppid != -1) {
  829. sleep(5);
  830. while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
  831. if(check_status(wpid, retstat)) goterror = 1;
  832. }
  833. }
  834. if (dumppid != -1) {
  835. dbprintf(_("Sending SIGHUP to dump process %d\n"),
  836. (int)dumppid);
  837. if(dumppid != -1) {
  838. if(kill(dumppid, SIGHUP) == -1) {
  839. dbprintf(_("Can't send SIGHUP to %d: %s\n"),
  840. (int)dumppid,
  841. strerror(errno));
  842. }
  843. }
  844. sleep(5);
  845. while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
  846. if(check_status(wpid, retstat)) goterror = 1;
  847. }
  848. }
  849. if (dumppid != -1) {
  850. dbprintf(_("Sending SIGKILL to dump process %d\n"),
  851. (int)dumppid);
  852. if(dumppid != -1) {
  853. if(kill(dumppid, SIGKILL) == -1) {
  854. dbprintf(_("Can't send SIGKILL to %d: %s\n"),
  855. (int)dumppid,
  856. strerror(errno));
  857. }
  858. }
  859. sleep(5);
  860. while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
  861. if(check_status(wpid, retstat)) goterror = 1;
  862. }
  863. }
  864. if(errorstr) {
  865. error(_("error [%s]"), errorstr);
  866. /*NOTREACHED*/
  867. } else if(dump_size == -1) {
  868. error(_("error [no backup size line]"));
  869. /*NOTREACHED*/
  870. }
  871. program->end_backup(goterror);
  872. g_fprintf(stderr, _("%s: size %ld\n"), get_pname(), dump_size);
  873. g_fprintf(stderr, _("%s: end\n"), get_pname());
  874. }
  875. /*
  876. * Returns the value of the first integer in a string.
  877. */
  878. double
  879. the_num(
  880. char * str,
  881. int pos)
  882. {
  883. char *num;
  884. int ch;
  885. double d;
  886. do {
  887. ch = *str++;
  888. while(ch && !isdigit(ch)) ch = *str++;
  889. if (pos == 1) break;
  890. pos--;
  891. while(ch && (isdigit(ch) || ch == '.')) ch = *str++;
  892. } while (ch);
  893. num = str - 1;
  894. while(isdigit(ch) || ch == '.') ch = *str++;
  895. str[-1] = '\0';
  896. d = atof(num);
  897. str[-1] = (char)ch;
  898. return d;
  899. }
  900. static void
  901. process_dumpline(
  902. char * str)
  903. {
  904. amregex_t *rp;
  905. char *type;
  906. char startchr;
  907. for(rp = program->re_table; rp->regex != NULL; rp++) {
  908. if(match(rp->regex, str)) {
  909. break;
  910. }
  911. }
  912. if(rp->typ == DMP_SIZE) {
  913. dump_size = (long)((the_num(str, rp->field)* rp->scale+1023.0)/1024.0);
  914. }
  915. switch(rp->typ) {
  916. case DMP_NORMAL:
  917. type = "normal";
  918. startchr = '|';
  919. break;
  920. case DMP_STRANGE:
  921. type = "strange";
  922. startchr = '?';
  923. break;
  924. case DMP_SIZE:
  925. type = "size";
  926. startchr = '|';
  927. break;
  928. case DMP_ERROR:
  929. type = "error";
  930. startchr = '?';
  931. break;
  932. default:
  933. /*
  934. * Should never get here.
  935. */
  936. type = "unknown";
  937. startchr = '!';
  938. break;
  939. }
  940. dbprintf("%3d: %7s(%c): %s\n",
  941. rp->srcline,
  942. type,
  943. startchr,
  944. str);
  945. g_fprintf(stderr, "%c %s\n", startchr, str);
  946. }
  947. /*
  948. * start_index. Creates an index file from the output of dump/tar.
  949. * It arranges that input is the fd to be written by the dump process.
  950. * If createindex is not enabled, it does nothing. If it is not, a
  951. * new process will be created that tees input both to a pipe whose
  952. * read fd is dup2'ed input and to a program that outputs an index
  953. * file to `index'.
  954. *
  955. * make sure that the chat from restore doesn't go to stderr cause
  956. * this goes back to amanda which doesn't expect to see it
  957. * (2>/dev/null should do it)
  958. *
  959. * Originally by Alan M. McIvor, 13 April 1996
  960. *
  961. * Adapted by Alexandre Oliva, 1 May 1997
  962. *
  963. * This program owes a lot to tee.c from GNU sh-utils and dumptee.c
  964. * from the DeeJay backup package.
  965. */
  966. static void
  967. save_fd(
  968. int * fd,
  969. int min)
  970. {
  971. int origfd = *fd;
  972. while (*fd >= 0 && *fd < min) {
  973. int newfd = dup(*fd);
  974. if (newfd == -1)
  975. dbprintf(_("Unable to save file descriptor [%s]\n"), strerror(errno));
  976. *fd = newfd;
  977. }
  978. if (origfd != *fd)
  979. dbprintf(_("Dupped file descriptor %i to %i\n"), origfd, *fd);
  980. }
  981. void
  982. start_index(
  983. int createindex,
  984. int input,
  985. int mesg,
  986. int index,
  987. char * cmd)
  988. {
  989. int pipefd[2];
  990. FILE *pipe_fp;
  991. int exitcode;
  992. if (!createindex)
  993. return;
  994. if (pipe(pipefd) != 0) {
  995. error(_("creating index pipe: %s"), strerror(errno));
  996. /*NOTREACHED*/
  997. }
  998. switch(indexpid = fork()) {
  999. case -1:
  1000. error(_("forking index tee process: %s"), strerror(errno));
  1001. /*NOTREACHED*/
  1002. default:
  1003. aclose(pipefd[0]);
  1004. if (dup2(pipefd[1], input) == -1) {
  1005. error(_("dup'ping index tee output: %s"), strerror(errno));
  1006. /*NOTREACHED*/
  1007. }
  1008. aclose(pipefd[1]);
  1009. return;
  1010. case 0:
  1011. break;
  1012. }
  1013. /* now in a child process */
  1014. save_fd(&pipefd[0], 4);
  1015. save_fd(&index, 4);
  1016. save_fd(&mesg, 4);
  1017. save_fd(&input, 4);
  1018. dup2(pipefd[0], 0);
  1019. dup2(index, 1);
  1020. dup2(mesg, 2);
  1021. dup2(input, 3);
  1022. for(index = 4; index < (int)FD_SETSIZE; index++) {
  1023. if (index != dbfd()) {
  1024. close(index);
  1025. }
  1026. }
  1027. if ((pipe_fp = popen(cmd, "w")) == NULL) {
  1028. error(_("couldn't start index creator [%s]"), strerror(errno));
  1029. /*NOTREACHED*/
  1030. }
  1031. dbprintf(_("Started index creator: \"%s\"\n"), cmd);
  1032. while(1) {
  1033. char buffer[BUFSIZ], *ptr;
  1034. ssize_t bytes_read;
  1035. size_t bytes_written;
  1036. ssize_t just_written;
  1037. do {
  1038. bytes_read = read(0, buffer, SIZEOF(buffer));
  1039. } while ((bytes_read < 0) && ((errno == EINTR) || (errno == EAGAIN)));
  1040. if (bytes_read < 0) {
  1041. error(_("index tee cannot read [%s]"), strerror(errno));
  1042. /*NOTREACHED*/
  1043. }
  1044. if (bytes_read == 0)
  1045. break; /* finished */
  1046. /* write the stuff to the subprocess */
  1047. ptr = buffer;
  1048. bytes_written = 0;
  1049. just_written = fullwrite(fileno(pipe_fp), ptr, (size_t)bytes_read);
  1050. if (just_written < 0) {
  1051. /*
  1052. * just as we waited for write() to complete.
  1053. */
  1054. if (errno != EPIPE) {
  1055. dbprintf(_("Index tee cannot write to index creator [%s]\n"),
  1056. strerror(errno));
  1057. }
  1058. } else {
  1059. bytes_written += just_written;
  1060. ptr += just_written;
  1061. }
  1062. /* write the stuff to stdout, ensuring none lost when interrupt
  1063. occurs */
  1064. ptr = buffer;
  1065. bytes_written = 0;
  1066. just_written = fullwrite(3, ptr, (size_t)bytes_read);
  1067. if (just_written < 0) {
  1068. error(_("index tee cannot write [%s]"), strerror(errno));
  1069. /*NOTREACHED*/
  1070. } else {
  1071. bytes_written += just_written;
  1072. ptr += just_written;
  1073. }
  1074. }
  1075. aclose(pipefd[1]);
  1076. /* finished */
  1077. /* check the exit code of the pipe and moan if not 0 */
  1078. if ((exitcode = pclose(pipe_fp)) != 0) {
  1079. char *exitstr = str_exit_status("Index pipe", exitcode);
  1080. dbprintf("%s\n", exitstr);
  1081. amfree(exitstr);
  1082. } else {
  1083. dbprintf(_("Index created successfully\n"));
  1084. }
  1085. pipe_fp = NULL;
  1086. exit(exitcode);
  1087. }
  1088. extern backup_program_t dump_program, gnutar_program;
  1089. backup_program_t *programs[] = {
  1090. &dump_program, &gnutar_program, NULL
  1091. };