+/*
+ * Copyright (c) 1998,1999,2000
+ * Traakan, Inc., Los Altos, CA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Project: NDMJOB
+ * Ident: $Id: $
+ *
+ * Description:
+ *
+ */
+
+
+#include "ndmjob.h"
+
+
+char *help_text[] = {
+ "ndmjob -v -- print version and configuration info",
+ "ndmjob OPTIONS ... FILES ...",
+ " FILES can be FILEPATH or NEWFILEPATH=OLDFILEPATH with",
+ " '=' quoted by backslash.",
+ "Modes (exactly one required)",
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ " -c -- create a backup",
+ " -t -- list contents on a backup",
+ " -x -- extract from a backup",
+ " -l -- list media labels",
+ " -q -- query agent(s)",
+ " -Z -- clean up zee mess (put robot right)",
+ " -o init-labels -- init media labels",
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+#ifndef NDMOS_EFFECT_NO_SERVER_AGENTS
+ " -o daemon -- launch session for incomming connections",
+ " -o test-daemon -- launch session for incomming connections, exit when stdin is closed",
+ " -o tape-size=SIZE -- specify the length, in bytes of the simulated tape",
+#endif /* !NDMOS_EFFECT_NO_SERVER_AGENTS */
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ " -o rewind -- rewind tape in drive, need -T and -f",
+ " -o eject -- eject tape in drive, need -T and -f",
+ " -o move -- cmd ROBOT to move tape, need -o from/to-addr",
+ " -o import=ELEMADDR -- cmd ROBOT to import tape from door to slot",
+ " -o export=ELEMADDR -- cmd ROBOT to export tape from slot to door",
+ " -o load=ELEMADDR -- cmd ROBOT to load tape from slot to drive",
+ " -o unload[=ELEMADDR]-- cmd ROBOT to unload tape, sometimes auto",
+ " -o init-elem-status -- cmd ROBOT to rescan tape slots",
+ " -o test-tape -- test TAPE agent NDMP_TAPE functions",
+ " -o test-mover -- test TAPE agent NDMP_MOVER functions",
+ " -o test-data -- test DATA agent NDMP_DATA functions",
+ " -o time-limit=N",
+ " -- check for reply within specified seconds (default 360)",
+ " -o swap-connect -- perform DATA LISTEN & MOVER CONNECT",
+#if 0
+ " -p -- pass DATA->DATA (ndmpcopy)",
+ " -P -- pass TAPE->TAPE",
+ " -o c-partial -- partial backup",
+ " -o c-full -- full backup",
+ " -o x-restore -- extract restoring",
+#endif
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+ "General and Logging parameters",
+ " --MACRO -- expand MACRO from ndmjob-args file",
+ " -d N -- set debug level to N (default 0, max 9)",
+ " -L FILE -- set log file (default stderr, includes debug)",
+ " -n -- no-op, just show how args were handled",
+ " -v -- verbose, same messages as -d1 to standard out",
+ " -S -- Perform DATA listen and MOVER CONNECT",
+ " -p PORT -- NDMP port to listen on (for -o daemon)",
+ " -o no-time-stamps -- log w/o time stamps, makes diff(1)s easier",
+ " -o config-file=PATH",
+ " -- set config file ($NDMJOB_CONFIG, /usr/local/etc/ndmjob.conf)",
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ "CONTROL of DATA agent parameters",
+ " -D AGENT -- data agent (see AGENT below)",
+ " -B TYPE -- set backup format (default tar)",
+ " -C DIR -- change directory on data agent before operation",
+ " -e PATN -- exclude files matching pattern",
+ " -E NAME=VAL -- add to data agent environment",
+ " -F FILE -- add FILE arg (used to not confuse arg processing)",
+ " -o load-files=PATHNAME",
+ " -- load FILES from the specified PATHANME",
+ " -o import=ELEMADDR -- cmd ROBOT to import tape from door to slot",
+
+ " -I FILE -- set output index file, enable FILEHIST (default to log)",
+ " -J FILE -- set input index file (default none)",
+ " -U USER -- user rights to use on data agent",
+ " -o rules=RULES -- apply RULES to job (see RULES below)",
+ "CONTROL of TAPE agent parameters",
+ " -T AGENT -- tape agent if different than -D (see AGENT below)",
+ " -b N -- block size in 512-byte records (default 20)",
+ " -f TAPE -- tape drive device name",
+ " -o tape-timeout=SECONDS",
+ " -- how long to retry opening drive (await tape)",
+ " -o use-eject=N",
+ " -- use eject when unloading tapes (default 0)",
+ " -o tape-tcp=hostname:port -- send the data directly to that tcp port.",
+ "CONTROL of ROBOT agent parameters",
+ " -R AGENT -- robot agent if different than -T (see AGENT below)",
+ " -m MEDIA -- add entry to media table (see below)",
+ " -o tape-addr=ELEMADDR",
+ " -- robot element address of drive (default first)",
+ " -o tape-scsi=SCSI",
+ " -- tape drive SCSI target (see below)",
+ " -o robot-timeout=SECONDS",
+ " -- how long to retry moving tapes (await robot)",
+ " -r SCSI -- tape robot target (see below)",
+ "",
+ "Definitions:",
+ " AGENT HOST[:PORT][/FLAGS][,USERNAME,PASSWORD]",
+ " FLAGS [234][ntm] 2->v2 3->v3 4->v4 n->AUTH_NONE t->TEXT m->MD5",
+ " AGENT . (resident)",
+ " SCSI DEVICE[,[CNUM,]SID[,LUN]]",
+ " MEDIA [TAPE-LABEL][+SKIP-FILEMARKS][@ELEMADDR][/WINDOW-SIZE]",
+ "",
+ "RULES:",
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+ 0
+};
+
+
+int
+process_args (int argc, char *argv[])
+{
+ int c;
+ char options[100];
+ char ** pp;
+ char * p;
+ char * op;
+ char * av[1000];
+ int ac = 0;
+
+ progname = argv[0];
+
+ if (argc == 2 && strcmp (argv[1], "-help") == 0) {
+ help();
+ exit(0);
+ }
+
+ if (argc == 2 && strcmp (argv[1], "-v") == 0) {
+ ndmjob_version_info ();
+ exit(0);
+ }
+
+ if (argc < 2)
+ usage();
+
+ o_config_file = g_strdup_printf("%s/ndmjob.conf", amdatadir);
+ if ((p = getenv ("NDMJOB_CONF")) != 0) {
+ o_config_file = p;
+ }
+
+ op = options;
+ for (pp = help_text; *pp; pp++) {
+ p = *pp;
+
+ if (strncmp (p, " -", 3) != 0)
+ continue;
+ if (p[3] == 'o')
+ continue; /* don't include o: repeatedly */
+ *op++ = p[3];
+ if (p[5] != ' ')
+ *op++ = ':';
+ }
+ *op++ = 'o'; /* include o: once */
+ *op++ = ':';
+ *op = 0;
+
+ ac = copy_args_expanding_macros (argc, argv,
+ av, sizeof(av)/sizeof(av[0]));
+
+ while ((c = getopt (ac, av, options)) != EOF) {
+ switch (c) {
+ case 'o':
+ handle_long_option (optarg);
+ break;
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ case 'c': /* -c -- create a backup */
+ set_job_mode (NDM_JOB_OP_BACKUP);
+ break;
+
+ case 't': /* -t -- list contents on a backup */
+ set_job_mode (NDM_JOB_OP_TOC);
+ break;
+
+ case 'x': /* -x -- extract from a backup */
+ set_job_mode (NDM_JOB_OP_EXTRACT);
+ break;
+
+ case 'l': /* -l -- list media labels */
+ set_job_mode (NDM_JOB_OP_LIST_LABELS);
+ break;
+
+ case 'q': /* -q -- query agent(s) */
+ set_job_mode (NDM_JOB_OP_QUERY_AGENTS);
+ break;
+
+ case 'Z': /* -Z -- clean up zee mess */
+ set_job_mode (NDM_JOB_OP_REMEDY_ROBOT);
+ break;
+
+ case 'B': /* -B TYPE -- set backup format (default tar) */
+ if (B_bu_type) {
+ error_byebye ("more than one of -B");
+ }
+ B_bu_type = optarg;
+ break;
+
+ case 'b': /* -b N -- block size in 512-byte records (20) */
+ {
+ long b = strtol(optarg, NULL, 10);
+ if (b < 1 || b > 200 || (!b && EINVAL == errno)) {
+ error_byebye ("bad -b option");
+ }
+ b_bsize = (int) b;
+ break;
+ }
+
+ case 'p': /* -p N -- port number for daemon mode (10000) */
+ {
+ long p = strtol(optarg, NULL, 10);
+ if (p < 1 || p > 65535 || (!p && EINVAL == errno)) {
+ error_byebye ("bad -p option");
+ }
+ p_ndmp_port = (int) p;
+ break;
+ }
+
+ case 'C': /* -C DIR -- change directory on data agent */
+#if 0
+ /* allow second to override first. make recover easier */
+ if (C_chdir) {
+ error_byebye ("more than one of -C");
+ }
+#endif
+ C_chdir = optarg;
+ break;
+
+ case 'D': /* -D AGENT -- data agent (see below) */
+ if (AGENT_GIVEN(D_data_agent)) {
+ error_byebye ("more than one of -D");
+ }
+ if (ndmagent_from_str (&D_data_agent, optarg)) {
+ error_byebye ("bad -D argument");
+ }
+ break;
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+
+ case 'd': /* -d N -- set debug level to N */
+ d_debug = atoi(optarg);
+ break;
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ case 'E': /* -E NAME=VAL -- add to data agent environment */
+ if (n_E_environment >= NDM_MAX_ENV) {
+ error_byebye ("too many of -E");
+ }
+ {
+ char * p;
+
+ p = optarg;
+ E_environment[n_E_environment].name = p;
+ while (*p && *p != '=') p++;
+ if (*p != '=') {
+ error_byebye ("missing value in -E");
+ }
+ *p++ = 0;
+ E_environment[n_E_environment].value = p;
+ n_E_environment++;
+ }
+ break;
+
+ case 'e': /* -e PATN -- exclude files matching pattern */
+ if (n_e_exclude_pattern >= MAX_EXCLUDE_PATTERN) {
+ error_byebye ("too many of -e");
+ }
+ e_exclude_pattern[n_e_exclude_pattern++] = optarg;
+ break;
+
+ case 'F': /* -F FILE -- add to list of files */
+ if (n_file_arg >= MAX_FILE_ARG) {
+ error_byebye ("too many FILE args");
+ }
+ if (strchr(optarg, '=')) {
+ char *p = strchr(optarg, '=');
+ *p++ = 0;
+ file_arg[n_file_arg] = p;
+ file_arg_new[n_file_arg] = optarg;
+ n_file_arg++;
+ } else {
+ file_arg[n_file_arg] = optarg;
+ file_arg_new[n_file_arg] = 0;
+ n_file_arg++;
+ }
+
+ break;
+
+ case 'f': /* -f TAPE -- tape drive device name */
+ if (f_tape_device) {
+ error_byebye ("more than one of -f");
+ }
+ f_tape_device = optarg;
+ break;
+
+ case 'I': /* -I FILE -- output index, enab FILEHIST */
+ if (I_index_file) {
+ error_byebye ("more than one of -I");
+ }
+ I_index_file = optarg;
+ break;
+
+ case 'J': /* -J FILE -- input index */
+ if (J_index_file) {
+ error_byebye ("more than one of -J");
+ }
+ J_index_file = optarg;
+ break;
+
+ case 'L': /* -L FILE -- set log file (def stderr, incl. dbg) */
+ if (L_log_file) {
+ error_byebye ("more than one of -L");
+ }
+ L_log_file = optarg;
+ if (d_debug < 2) d_debug = 2;
+ break;
+
+ case 'm': /* -m MEDIA -- add entry to media table (see below) */
+ if (n_m_media >= NDM_MAX_MEDIA) {
+ error_byebye ("too many of -m");
+ }
+ if (ndmmedia_from_str (&m_media[n_m_media], optarg)) {
+ error_byebye ("bad -m argument: %s", optarg);
+ }
+ n_m_media++;
+ break;
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+
+ case 'n': /* -n -- no-op, show how args were handled */
+ n_noop++;
+ break;
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ case 'R': /* -R AGENT -- robot agent if different than -T */
+ if (AGENT_GIVEN(R_robot_agent)) {
+ error_byebye ("more than one of -R");
+ }
+ if (ndmagent_from_str (&R_robot_agent, optarg)) {
+ error_byebye ("bad -R argument");
+ }
+ break;
+
+ case 'r': /* -r SCSI -- tape robot target (see below) */
+ if (ROBOT_GIVEN()) {
+ error_byebye ("more than one of -r");
+ }
+ if (ndmscsi_target_from_str (&r_robot_target, optarg)) {
+ error_byebye ("bad -r argument");
+ }
+ break;
+
+ case 'T': /* -T AGENT -- tape agent if different than -D */
+ if (AGENT_GIVEN(T_tape_agent)) {
+ error_byebye ("more than one of -T");
+ }
+ if (ndmagent_from_str (&T_tape_agent, optarg)) {
+ error_byebye ("bad -T argument");
+ }
+ break;
+
+ case 'U': /* -U USER -- user rights to use on data agent */
+ if (U_user) {
+ error_byebye ("more than one of -U");
+ }
+ U_user = optarg;
+ break;
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+
+ case 'v': /* -v -- verbose */
+ v_verbose++;
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (n_noop && d_debug > 1) {
+ int i;
+
+ for (i = 0; i < ac; i++) {
+ printf (" av[%d] = '%s'\n", i, av[i]);
+ }
+ }
+
+ if (!the_mode) {
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ printf ("must specify one of -[ctxlqZ] or other mode\n");
+#else /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+ printf ("must specify -o daemon\n");
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+ usage();
+ }
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ for (c = optind; c < ac; c++) {
+ if (n_file_arg >= MAX_FILE_ARG) {
+ error_byebye ("too many file args");
+ }
+ if (strchr(av[c], '=')) {
+ char *p = strchr(av[c], '=');
+ *p++ = 0;
+ file_arg[n_file_arg] = p;
+ file_arg_new[n_file_arg] = av[c];
+ } else {
+ file_arg[n_file_arg] = av[c];
+ file_arg_new[n_file_arg] = 0;
+ }
+ n_file_arg++;
+ }
+
+ if (o_load_files_file) {
+ char buf[2048];
+ FILE *fp;
+ static struct load_file_entry {
+ struct load_file_entry *next;
+ char name[1];
+ } *load_files_list = 0;
+
+ /* clean up old load_files_list */
+ while (load_files_list) {
+ struct load_file_entry *p;
+ p = load_files_list;
+ load_files_list = p->next;
+ p->next = 0;
+ free(p);
+ }
+
+ fp = fopen(o_load_files_file, "r");
+ if (!fp) {
+ perror (o_load_files_file);
+ error_byebye ("can't open load_files file %s",
+ o_load_files_file);
+ /* no return */
+ }
+ while (fgets (buf, sizeof buf, fp) != NULL) {
+ char *bp = buf, *p, *ep;
+ int len, slen;
+ struct load_file_entry *lfe;
+
+ bp = buf;
+ while (*bp && isspace(*bp))
+ bp++;
+ ep = bp;
+ while (*ep && (*ep != '\n') && (*ep != '\r'))
+ ep++;
+ *ep = 0;
+ if (bp >= ep)
+ continue;
+
+ if (n_file_arg >= MAX_FILE_ARG) {
+ error_byebye ("too many FILE args");
+ }
+
+ /* allocate memory */
+ slen = (ep-bp)+2;
+ len = sizeof(struct load_file_entry)+(ep-bp)+1;
+ lfe = malloc(len);
+ if (lfe == 0) {
+ error_byebye ("can't allocate entry for load_files file line %s",
+ bp);
+ /* no return */
+ }
+ lfe->next = 0;
+
+ /* see if we have destination */
+ if ((p = strchr(bp, '=')) != 0) {
+ int plen;
+ char ch = *p;
+ *p = 0;
+
+ /* double conversion -- assume the strings shrink */
+ plen = (p-bp);
+ ndmcstr_to_str(p, &lfe->name[plen+2], slen-plen-2);
+ ndmcstr_to_str(bp, lfe->name, plen+1);
+ file_arg[n_file_arg] = &lfe->name[plen+2];
+ file_arg_new[n_file_arg] = lfe->name;
+ *p = ch;
+ } else {
+ /* simple conversion copy */
+ ndmcstr_to_str(bp, lfe->name, slen-1);
+ file_arg[n_file_arg] = lfe->name;
+ file_arg_new[n_file_arg] = 0;
+ }
+ n_file_arg++;
+
+ /* link into list */
+ lfe->next = load_files_list;
+ load_files_list = lfe;
+ }
+
+ fclose (fp);
+ } /* end of load_files option */
+
+ if (!B_bu_type)
+ B_bu_type = "tar";
+
+ /*
+ * A quirk of the NDMP protocol is that the robot
+ * should be accessed over a different connection
+ * than the TAPE agent. (See the Workflow document).
+ */
+ if (ROBOT_GIVEN()) {
+ if (!AGENT_GIVEN(R_robot_agent)) {
+ if (AGENT_GIVEN(T_tape_agent))
+ R_robot_agent = T_tape_agent;
+ else
+ R_robot_agent = D_data_agent;
+
+ if (!AGENT_GIVEN(R_robot_agent)) {
+ error_byebye ("-r given, can't determine -R");
+ }
+ }
+ } else if (AGENT_GIVEN(R_robot_agent)) {
+ if (the_mode != NDM_JOB_OP_QUERY_AGENTS) {
+ error_byebye ("-R but no -r");
+ }
+ }
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+
+ return 0;
+}
+
+struct ndmp_enum_str_table mode_long_name_table[] = {
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ { "init-labels", NDM_JOB_OP_INIT_LABELS },
+ { "test-tape", NDM_JOB_OP_TEST_TAPE },
+ { "test-mover", NDM_JOB_OP_TEST_MOVER },
+ { "test-data", NDM_JOB_OP_TEST_DATA },
+ { "eject", NDM_JOB_OP_EJECT_TAPE },
+ { "rewind", NDM_JOB_OP_REWIND_TAPE },
+ { "move", NDM_JOB_OP_MOVE_TAPE },
+ { "import", NDM_JOB_OP_IMPORT_TAPE },
+ { "export", NDM_JOB_OP_EXPORT_TAPE },
+ { "load", NDM_JOB_OP_LOAD_TAPE },
+ { "unload", NDM_JOB_OP_UNLOAD_TAPE },
+ { "init-elem-status", NDM_JOB_OP_INIT_ELEM_STATUS },
+ { "-c", NDM_JOB_OP_BACKUP },
+ { "-t", NDM_JOB_OP_TOC },
+ { "-x", NDM_JOB_OP_EXTRACT },
+ { "-l", NDM_JOB_OP_LIST_LABELS },
+ { "-q", NDM_JOB_OP_QUERY_AGENTS },
+ { "-Z", NDM_JOB_OP_REMEDY_ROBOT },
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+#ifndef NDMOS_EFFECT_NO_SERVER_AGENTS
+ { "daemon", NDM_JOB_OP_DAEMON },
+ { "test-daemon", NDM_JOB_OP_TEST_DAEMON },
+#endif /* !NDMOS_EFFECT_NO_SERVER_AGENTS */
+ { 0 }
+};
+
+
+int
+handle_long_option (char *str)
+{
+ char * name;
+ char * value;
+ int mode;
+
+ name = str;
+ for (value = str; *value; value++)
+ if (*value == '=')
+ break;
+ if (*value)
+ *value++ = 0;
+ else
+ value = 0;
+
+ if (ndmp_enum_from_str (&mode, name, mode_long_name_table)) {
+ set_job_mode (mode);
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ if (value) {
+ switch (mode) {
+ default: /* value part ignored */
+ break;
+
+ case NDM_JOB_OP_LOAD_TAPE:
+ case NDM_JOB_OP_EXPORT_TAPE:
+ o_from_addr = atoi(value);
+ break;
+ case NDM_JOB_OP_UNLOAD_TAPE:
+ case NDM_JOB_OP_IMPORT_TAPE:
+ o_to_addr = atoi(value);
+ break;
+ }
+ }
+ } else if (strcmp (name, "swap-connect") == 0) {
+ /* value part ignored */
+ o_swap_connect++;
+ } else if (strcmp (name, "time-limit") == 0) {
+ if (!value) {
+ o_time_limit = 5*60;
+ } else {
+ o_time_limit = atoi(value);
+ }
+ } else if (strcmp (name, "use-eject") == 0) {
+ if (!value) {
+ o_use_eject = 1;
+ } else {
+ o_use_eject = atoi(value);
+ }
+ } else if (strcmp (name, "tape-addr") == 0 && value) {
+ o_tape_addr = atoi(value);
+ } else if (strcmp (name, "from-addr") == 0 && value) {
+ o_from_addr = atoi(value);
+ } else if (strcmp (name, "to-addr") == 0 && value) {
+ o_to_addr = atoi(value);
+ } else if (strcmp (name, "tape-timeout") == 0 && value) {
+ o_tape_timeout = atoi(value);
+ } else if (strcmp (name, "robot-timeout") == 0 && value) {
+ o_robot_timeout = atoi(value);
+ } else if (strcmp (name, "tape-scsi") == 0 && value) {
+ if (ndmscsi_target_from_str (&o_tape_scsi, value)) {
+ error_byebye ("bad -otape-scsi argument");
+ }
+ } else if (strcmp (name, "rules") == 0 && value) {
+ if (!value)
+ error_byebye ("missing RULES in -o rules");
+ o_rules = value;
+ } else if (strcmp (name, "load-files") == 0 && value) {
+ o_load_files_file = value;
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+ } else if (strcmp (name, "no-time-stamps") == 0) {
+ /* value part ignored */
+ o_no_time_stamps++;
+ } else if (strcmp (name, "config-file") == 0 && value) {
+ o_config_file = value;
+ } else if (strcmp (name, "tape-tcp") == 0 && value) {
+ o_tape_tcp = value;
+ } else if (strcmp (name, "tape-limit") == 0) {
+ if (!value) {
+ error_byebye ("tape-limit argument is required");
+ } else {
+ o_tape_limit = atoi(value);
+ }
+ } else {
+ if (value) value[-1] = '=';
+ error_byebye ("unknown/bad long option -o%s", str);
+ }
+
+ if (value) value[-1] = '=';
+ return 0;
+}
+
+void
+set_job_mode (int mode)
+{
+ if (the_mode) {
+ printf ("more than one -[ctxlqZ] or other mode");
+ usage();
+ }
+ the_mode = mode;
+}
+
+void
+usage (void)
+{
+ error_byebye ("bad usage, use -help");
+}
+
+void
+help (void)
+{
+ char * p;
+ char ** pp;
+
+ for (pp = help_text; *pp; pp++) {
+ p = *pp;
+ printf ("%s\n", p);
+ }
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ help_rules();
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+}
+
+void
+ndmjob_version_info (void)
+{
+ char vbuf[100];
+ char abuf[100];
+ char obuf[5];
+
+ *vbuf = 0;
+#ifndef NDMOS_OPTION_NO_NDMP2
+ strcat (vbuf, " NDMPv2");
+#endif /* !NDMOS_OPTION_NO_NDMP2 */
+#ifndef NDMOS_OPTION_NO_NDMP3
+ strcat (vbuf, " NDMPv3");
+#endif /* !NDMOS_OPTION_NO_NDMP3 */
+#ifndef NDMOS_OPTION_NO_NDMP4
+ strcat (vbuf, " NDMPv4");
+#endif /* !NDMOS_OPTION_NO_NDMP4 */
+
+ *abuf = 0;
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ strcat (abuf, " CONTROL");
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+#ifndef NDMOS_OPTION_NO_DATA_AGENT
+ strcat (abuf, " DATA");
+#endif /* !NDMOS_OPTION_NO_DATA_AGENT */
+#ifndef NDMOS_OPTION_NO_TAPE_AGENT
+ strcat (abuf, " TAPE");
+#endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
+#ifndef NDMOS_OPTION_NO_ROBOT_AGENT
+ strcat (abuf, " ROBOT");
+#endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
+
+ obuf[0] = (char)(NDMOS_ID >> 24);
+ obuf[1] = (char)(NDMOS_ID >> 16);
+ obuf[2] = (char)(NDMOS_ID >> 8);
+ obuf[3] = (char)(NDMOS_ID >> 0);
+ obuf[4] = 0;
+
+ printf ("%s (%s)\n",
+ NDMOS_CONST_PRODUCT_NAME,
+ NDMOS_CONST_VENDOR_NAME);
+
+ printf (" Rev %s LIB:%d.%d/%s OS:%s (%s)\n",
+ NDMOS_CONST_PRODUCT_REVISION,
+ NDMJOBLIB_VERSION, NDMJOBLIB_RELEASE,
+ NDMOS_CONST_NDMJOBLIB_REVISION,
+ NDMOS_CONST_NDMOS_REVISION,
+ obuf);
+
+ printf (" Agents: %s\n", abuf);
+ printf (" Protocols:%s\n", vbuf);
+}
+
+
+void
+dump_settings (void)
+{
+ int i;
+ char buf[100];
+
+ *buf = 0; /* shuts up -Wall */
+ i = 0; /* shuts up -Wall */
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ switch (the_mode) {
+ case 'x':
+ printf ("mode = x (extract)\n");
+ break;
+
+ case 'c':
+ printf ("mode = c (create)\n");
+ break;
+
+ case 't':
+ printf ("mode = t (table-of-contents)\n");
+ break;
+
+ case 'q':
+ printf ("mode = q (query-agents)\n");
+ break;
+
+ default:
+ printf ("mode = %c (unknown)\n", the_mode);
+ break;
+ }
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+
+ if (v_verbose)
+ printf ("verbose %d\n", v_verbose);
+ else
+ printf ("not verbose\n");
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ printf ("blocksize = %d (%dkb, %db)\n",
+ b_bsize, b_bsize/2, b_bsize*512);
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+
+ if (d_debug)
+ printf ("debug %d\n", d_debug);
+ else
+ printf ("no debug\n");
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ printf ("Data agent %s\n", D_data_agent.host);
+ if (AGENT_GIVEN(T_tape_agent))
+ printf ("Tape agent %s\n", T_tape_agent.host);
+ else
+ printf ("Tape agent same as data agent\n");
+
+ printf ("tape device %s\n", f_tape_device);
+
+ printf ("tape format %s\n", B_bu_type);
+
+ if (C_chdir)
+ printf ("Chdir %s\n", C_chdir);
+ else
+ printf ("Chdir / (default)\n");
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+
+ if (L_log_file)
+ printf ("Log to file %s\n", L_log_file);
+ else
+ printf ("Log to stderr (default)\n");
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+ if (I_index_file) {
+ if (strcmp (I_index_file, "-") == 0) {
+ printf ("Index to log, enable FILEHIST\n");
+ } else {
+ printf ("Index to file %s, enable FILEHIST\n",
+ I_index_file);
+ }
+ } else {
+ printf ("Index off (default), no FILEHIST\n");
+ }
+
+ printf ("%d media entries\n", n_m_media);
+ for (i = 0; i < n_m_media; i++) {
+ ndmmedia_to_str (&m_media[i], buf);
+ printf (" %2d: %s\n", i, buf);
+ }
+
+ printf ("%d excludes\n", n_e_exclude_pattern);
+ for (i = 0; i < n_e_exclude_pattern; i++) {
+ printf (" %2d: %s\n", i, e_exclude_pattern[i]);
+ }
+
+ printf ("%d environment values\n", n_E_environment);
+ for (i = 0; i < n_E_environment; i++) {
+ printf (" %2d: %s=%s\n", i,
+ E_environment[i].name, E_environment[i].value);
+ }
+
+ printf ("%d files\n", n_file_arg);
+ for (i = 0; i < n_file_arg; i++) {
+ printf (" %2d: @%-8lld %s\n", i,
+ nlist[i].fh_info.valid ? nlist[i].fh_info.value : NDMP9_INVALID_U_QUAD,
+ file_arg[i]);
+ }
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
+
+ return;
+}
+
+int
+copy_args_expanding_macros (int argc, char *argv[], char *av[], int max_ac)
+{
+ int i, ac = 0, rc;
+ char * arg;
+ char * p;
+ char env_name[50];
+
+ /* expand macros */
+ for (i = 0; i < argc; i++) {
+ arg = argv[i];
+
+ if (strncmp (arg, "--", 2) != 0 || arg[2] == 0) {
+ av[ac++] = arg;
+ continue;
+ }
+
+ sprintf (env_name, "NDMJOB_%s", arg+2);
+ if ((p = getenv (env_name)) != 0) {
+ ac += snarf_macro (&av[ac], p);
+ continue;
+ }
+
+ rc = lookup_and_snarf (&av[ac], arg+2);
+ if (rc < 0) {
+ error_byebye ("bad arg macro --%s", arg+2);
+ }
+ ac += rc;
+ }
+
+ av[ac] = 0;
+
+ return ac;
+}
+
+int
+lookup_and_snarf (char *av[], char *name)
+{
+ FILE * fp;
+ char buf[512];
+ char * argfile;
+ int ac = 0;
+ int found = 0;
+
+ argfile = o_config_file;
+ assert (argfile);
+
+ fp = fopen (argfile, "r");
+ if (!fp) {
+ perror (argfile);
+ error_byebye ("can't open config file %s", argfile);
+ }
+
+ while (ndmstz_getstanza (fp, buf, sizeof buf) >= 0) {
+ if (buf[0] == '-' && buf[1] == '-'
+ && strcmp (buf+2, name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ while (ndmstz_getline (fp, buf, sizeof buf) >= 0) {
+ if (*buf == 0)
+ continue;
+ ac += snarf_macro (&av[ac], buf);
+ }
+ }
+
+ fclose (fp);
+
+ if (!found)
+ return -1;
+
+ return ac;
+}
+
+int
+snarf_macro (char *av[], char *val)
+{
+ char * p;
+ int ac = 0;
+ char * tmp_av[100];
+ int tmp_ac = 0;
+
+ p = NDMOS_API_STRDUP (val);
+ if (!p) {
+ error_byebye ("bad strdup macro");
+ }
+ for (;;) {
+ while (isspace((int)*p)) p++;
+ if (*p == 0) break;
+ tmp_av[tmp_ac++] = p;
+ while (*p && !isspace((int)*p)) p++;
+ if (*p) *p++ = 0;
+ }
+
+ ac = copy_args_expanding_macros (tmp_ac, tmp_av, av, 100);
+
+ return ac;
+}