/*  swlist.c -- The swbis catalog listing utility.  */
/*
   Copyright (C) 2006 Jim Lowe
   All Rights Reserved.
  
   COPYING TERMS AND CONDITIONS:
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#define FILENEEDDEBUG 1
#undef FILENEEDDEBUG
#include "swuser_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "vplob.h"
#include "swlib.h"
#include "usgetopt.h"
#include "ugetopt_help.h"
#include "swlist.h"
#include "swparse.h"
#include "swfork.h"
#include "swgp.h"
#include "swssh.h"
#include "swlist.h"
#include "progressmeter.h"
#include "swevents.h"
#include "swicol.h"
#include "swutillib.h"
#include "swmain.h"  /* this file should be included by the main program file */
#include "globalblob.h"

#define SWLIST_UPVERBOSE	4
#define PROGNAME                "swlist"
#define SW_UTILNAME             PROGNAME
#define SWPROG_VERSION          SWINSTALL_VERSION

#define WOPT_LAST                               200

#define DEFAULT_PUMP_DELAY      10111000        /* 1/100th sec */
#define DEFAULT_BURST_ADJUST    72000           /* similar to OpenSSH rcvd adjust ??? */

static char progName[] = PROGNAME;
static char * CHARTRUE = "True";
static char * CHARFALSE = (char*)NULL;

static GB g_blob;
static GB * G;

static
void 
version_string(FILE * fp)
{
        fprintf(fp,   
"%s (swbis) version " SWLIST_VERSION "\n",
                progName);
}

static
void 
version_info(FILE * fp)
{
	version_string(fp);
	fprintf(fp,  "%s",
"Copyright (C) 2006 Jim Lowe\n"
"Portions are copyright 1985-2000 Free Software Foundation, Inc.\n"
"This software is distributed under the terms of the GNU General Public License\n"
"and comes with NO WARRANTY to the extent permitted by law.\n"
"See the file named COPYING for details.\n");

}

static
int 
usage(FILE * fp, 
		char * pgm, 
		struct option  lop[], 
		struct ugetopt_option_desc helpdesc[])
{
	
fprintf(fp, "%s",
"swlist lists information in the software catalog\n"
);
	
	fprintf(fp, "%s",
"\n"
"Usage: swlist [-d|-r] [-v] [-a attribute] [-c catalog] [-f file] [-l level]\\\n"
"[-t targetfile] [-x option=value] [-X options_file] [-W option[=value]]\\\n"
"      [software_selections][@target]\n"
);

fprintf(fp, "%s",
"\n"
"Options:\n"
);
	ugetopt_print_help(fp, pgm, lop, helpdesc);

fprintf(fp , "%s",
"\n"
"Implementation Extension Options:\n"
"       Syntax : -W option[=option_argument] [-W ...]\n"
"           or   -W option[=option_argument],option...\n"
"           or   --option[=option_argument]\n"
"   noop       Legal option with no effect\n"
"   show-options  Show the extended options and exit\n"
"   show-options-files   Show the options files that will be parsed.\n"
"   pax-command={tar|pax|star|gtar}\n"
"   pax-read-command={tar|pax|star|gtar}\n"
"   local-pax-read-command={tar|pax|star|gtar}\n"
"   remote-pax-read-command={tar|pax|star|gtar}\n"
"              pax  = \"pax -r\"\n"
"              star = \"star xpUf -\"\n"
"              tar  = \"tar xpf -\"\n"
"              gtar = \"tar xpf - --overwrite\"\n"
"   pax-write-command={tar|pax|star|gtar}\n"
"   local-pax-write-command={tar|pax|star|swbistar}\n"
"   remote-pax-write-command={tar|pax|star|swbistar}\n"
"              pax  = \"pax -w\"\n"
"              star = \"star cf - -H ustar\"\n"
"              tar  = \"tar cf -\"\n"
"              gtar = \"gtar cf -\"\n"
"              swbistar = \"" SWBISLIBEXECDIR "/swbis/swbistar\"\n"
" 	The default is \"tar\"\n"
"   remote-shell=NAME  NAME is the client \"rsh\" or \"ssh\"(default).\n"
"   no-defaults  Do not read any defaults files.\n"
"   no-remote-kill  Do not execute a kill command. Normally a kill command\n"
"               is issued when signals TERM, PIPE, and INT are received for\n"
"               targets where nhops > 1.\n"
"   no-getconf  Don't use the getconf utility to set the PATH variable on the\n"
"               target host. This sets the remote command to be '/bin/sh -s'\n"
"               instead of the default \"PATH=`getconf PATH` sh -s\"\n"
"   use-getconf  This causes getconf to be used.  Opposite to --no-getconf.\n"
"   shell-command={posix|sh|bash|ksh}  posix is the default\n"
"   allow-rpm   Allow installation of RPM format packages.\n"
"   ssh-options=options  Single letter ssh options. e.g. --ssh-options=1\n"
"   debug-events  Show the internal events listing to stderr\n"
"   source-script-name=NAME  write the internal stdin script to NAME.\n"
"   target-script-name=NAME  write the internal stdin script to NAME.\n"
"   any-format        lists any format package, including RPM format\n"
"\n"
);

    swc_helptext_target_syntax(fp);

fprintf(fp, "%s",
"\n"
"Posix Extended Options:\n"
"        File : <libdir>/swbis/swdefaults\n"
"               ~/.swdefaults\n"
"        Override values in defaults file.\n"
"        Command Line Syntax : -x option=option_argument [-x ...]\n"
"            or : -x \"option=option_argument  ...\"\n"
"   distribution_target_directory   = -	     # Stdin\n"
"   installed_software_catalog  = var/lib/swbis/catalog\n"
"   one_liner                   = true\n"
"   select_local		= false      # Not Implemented\n"
"   verbose			= 1\n"
"\n"
"Swbis Extended Options:\n"
"        File : <libdir>/swbis/swbisdefaults\n"
"               ~/.swbis/swbisdefaults\n"
"        Command Line Syntax : -x option=option_argument\n"
"  swlist.swbis_no_getconf		 = false # getconf is used\n"
"  swlist.swbis_shell_command	 = posix\n"
"  swlist.swbis_no_remote_kill	 = false\n"
"  swlist.swbis_local_pax_write_command  = pax\n"
"  swlist.swbis_remote_pax_write_command = pax\n"
"  swlist.swbis_local_pax_read_command   = pax\n"
"  swlist.swbis_remote_pax_read_command  = pax\n"
"  swlist.swbis_remote_shell_client      = ssh\n"
"  swlist.swbis_any_format               = false\n"
"\n"
);

	fprintf(fp , "%s", "\n");
	version_string(fp);
	fprintf(fp , "\n%s", 
        "Report bugs to " REPORT_BUGS "\n");
	return 0;
}

static
void
tty_raw_ctl(int c)
{
	static int g = 0;
	if (c == 0) {
		g = 0;
	} else if (c == 1) {
		g = 1;
	} else {
		if (g) {
		g = 0;
		if (swlib_tty_raw(STDIN_FILENO) < 0)
			swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
				&G->g_logspec, swc_get_stderr_fd(G), "tty_raw error");
		}
	}
}

static
void
safe_sig_handler(int signum)
{
	switch(signum) {
		case SIGTERM:
			if (G->g_do_progressmeter) alarm(0);
			swlib_doif_writef(G->g_verboseG,
					SWC_VERBOSE_IDB, &G->g_logspec, swc_get_stderr_fd(G), 
							"Caught SIGTERM\n");
			G->g_signal_flag = signum;
			break;
		case SIGINT:
			if (G->g_do_progressmeter) alarm(0);
			swlib_doif_writef(G->g_verboseG,
				SWC_VERBOSE_IDB, &G->g_logspec, swc_get_stderr_fd(G), 
						"Caught SIGINT\n");
			G->g_signal_flag = signum;
			break;
		case SIGPIPE:
			if (G->g_do_progressmeter) alarm(0);
			swlib_doif_writef(G->g_verboseG,
				SWC_VERBOSE_IDB, &G->g_logspec, swc_get_stderr_fd(G), 
						"Caught SIGPIPE\n");
			G->g_signal_flag = signum;
			break;
	}
}

static
void
main_sig_handler(int signum)
{
	int fd;
	int loggersig = SIGABRT;
	switch(signum) {
		case SIGTERM:
		case SIGINT:
		case SIGPIPE:
			swlib_doif_writef(G->g_verboseG,
				SWC_VERBOSE_IDB, &G->g_logspec, swc_get_stderr_fd(G),
					"Executing handler for signal %d.\n",
					 signum);
			G->g_signal_flag = 0;
			if (G->g_do_progressmeter) alarm(0);
			swgp_signal_block(SIGTERM, (sigset_t *)NULL);
			swgp_signal_block(SIGINT, (sigset_t *)NULL);
			/* swgp_signal_block(SIGPIPE, (sigset_t *)NULL); */
			swlib_tty_atexit();
			fd = G->g_target_fdar[0]; if (fd >= 0) close(fd);
			fd = G->g_target_fdar[1]; if (fd >= 0) close(fd);
			swc_gf_xformat_close(G, G->g_xformat);
			swlib_kill_all_pids(G->g_pid_array + SWC_PID_ARRAY_LEN, 
						G->g_pid_array_len, 
						SIGTERM, 
						G->g_verboseG);
			swlib_wait_on_all_pids(G->g_pid_array, 
						G->g_pid_array_len, 
						G->g_status_array, 
						0, 
						G->g_verboseG);
			swc_shutdown_logger(G, loggersig);
			switch(signum) {
				case SIGTERM:
				case SIGINT:
					/* FIXME per spec */
					LCEXIT(SW_FAILED_ALL_TARGETS); 
					break;
			}
			break;
	}
}

/* Main Program */

int
main(int argc, char **argv)
{
	int c;
	int ret;
	int optret = 0;
	int target_fdar[3];
	int source_fdar[3];
	int target_stdio_fdar[3];
	int source_stdio_fdar[3];
	int save_stdio_fdar[3];
	int targetlist_fd = -1;
	int target_nhops;
	int main_optind = 0;
	int num_remains;
	int e_argc = 1;
	int w_argc = 1;
	int swi_event_fd = -1;
	char * tmp_s;
	pid_t ss_pid = 0;
	pid_t source_write_pid = 0;
	pid_t target_pump_pid = 0;
	int swutil_x_mode = 1;
	char * sh_dash_s;
	int is_target_local_regular_file = 0;
	char * optionname;

	int opt_do_distribution = 0;    /* -d option */
	int opt_list_level = 1;         /* -l option */ /* FIXME  what does 1 mean ? */
	int opt_alt_catalog_root = 0;   /* -r option */
	int opt_index_file_format = 0;  /* -v option */
	char * opt_catalog = (char *)NULL;   /* -c option */
	char * opt_attribute = (char*)NULL;   /* -a option */
	char * opt_option_files = (char*)NULL;

	char * wopt_shell_command = (char*)(NULL);
	char * wopt_any_format = (char*)(NULL);
	int    wopt_no_defaults = 0;
	int    wopt_kill_hop_threshhold = 2;  /* 2 */
	char * wopt_enforce_sig = (char*)NULL;
	char * wopt_no_getconf = (char*)NULL;
	char * wopt_no_remote_kill = (char*)NULL;
	char * wopt_local_pax_write_command = (char*)NULL;
	char * wopt_remote_pax_write_command = (char*)NULL;
	char * wopt_local_pax_read_command = (char*)NULL;
	char * wopt_remote_pax_read_command = (char*)NULL;
	char * wopt_ssh_options = (char*)NULL;
	int    wopt_with_hop_pids = 1;  /* internal test control */
	char * wopt_show_options = NULL;
	char * wopt_show_options_files = NULL;
	char * wopt_blocksize = "5120";

	char * eopt_distribution_target_directory;
	char * eopt_installed_software_catalog;
	char * eopt_one_liner;
	char * eopt_select_local;
	char * eopt_verbose;

	int is_seekable = 0;
	int optionEnum;
	int devel_no_fork_optimization = 1;
	int local_stdin = 0;
	int do_extension_options_via_goto = 0;
	int tmp_status;
	int fverfd;
	int target_loop_count = 0;
	int target_success_count = 0;
	int * p_do_progressmeter;
	int make_master_raw = 1;
	int is_local_stdin_seekable = 0;
	int nullfd;
	int testnum = 0;
	int retval = 0;
	int target_file_size;
	unsigned long int statbytes;
	int target_array_index = 0;
	int select_array_index = 0;
	int stdin_in_use = 0;
	int use_no_getconf;
	int swevent_fd = STDOUT_FILENO;
	struct extendedOptions * opta = optionsArray;
	struct termios	*login_orig_termiosP = NULL;
	struct winsize	*login_sizeP = NULL;
	
	char * xcmd;
	char * tty_opt = NULL;
	char * target_fork_type;
	char * target_script_pid = (char*)NULL;
	char * tmpcharp = (char*)NULL;
	/* char * selections_filename = (char*)NULL; */
	char * exoption_arg;
	char * exoption_value;
	char * soc_spec_target = (char*)NULL;
	char * soc_spec_source = (char*)NULL;
	char * cl_target_target = (char*)NULL;
	char * xcl_target_target = (char*)NULL;
	char * cl_target_selections = (char*)NULL;
	char * target_path = (char*)NULL;

	char * pax_read_command_key = (char*)NULL;
	char * pax_read_command = (char*)NULL;
	char * pax_write_command_key = (char*)NULL;
	char * working_arg = (char*)NULL;
	char * current_arg = (char*)NULL;
	char * system_defaults_files = (char*)NULL;
	char * source_path = (char*)NULL;
	char * target_terminal_host = (char*)NULL;
	char cwd[1024];
	char * remote_shell_command = REMOTE_SSH_BIN;
	char * remote_shell_path;

	SWI_DISTDATA  * distdataO;
	STRAR * target_cmdlist;
	STRAR * target_tramp_list;
	VPLOB * swspecs;
	STROB * tmp;
	STROB * target_control_message;
	STROB * target_start_message;
	STROB * target_catalog_message;
	STROB * target_access_message;
	STROB * source_line_buf;
	STROB * target_line_buf;
	STROB * tmpcommand;
	CPLOB * w_arglist;
	CPLOB * e_arglist;
	SWI * swi = (SWI*)NULL;
	SHCMD * target_sshcmd[2];
	SHCMD * source_sshcmd[2];
	SHCMD * kill_sshcmd[2];
	SHCMD * target_kill_sshcmd[2];
	FILE * fver;
	sigset_t * fork_blockmask;
	sigset_t * fork_defaultmask;
	sigset_t * currentmask;
	SWUTIL * swutil;

	struct option main_long_options[] =
             {
		{"attribute", 1, 0, 'a'},
		{"catalog", 1, 0, 'c'},
		{"distribution", 0, 0, 'd'},
		{"selections-file", 1, 0, 'f'},
		{"level", 1, 0, 'l'},
		{"alternate-catalog-root", 0, 0, 'r'},
		{"target-file", 1, 0, 't'},
		{"source", 1, 0, 's'},
		{"defaults-file", 1, 0, 'X'},
		{"index-format", 0, 0, 'v'},
		{"extension-option", 1, 0, 'W'},
		{"extended-option", 1, 0, 'x'},
		{"version", 0, 0, 'V'},
		{"help", 0, 0, '\012'},
		{"noop", 0, 0, 154},
		{"show-options", 0, 0, 158},
		{"show-options-files", 0, 0, 159},
		{"testnum", 1, 0, 164},
		{"remote-shell", 1, 0, 172},
		{"local-pax-write-command", 1, 0, 175},
		{"remote-pax-write-command", 1, 0, 176},
		{"pax-write-command", 1, 0, 177},
		{"remote-pax-read-command", 1, 0, 178},
		{"local-pax-read-command", 1, 0, 179},
		{"pax-read-command", 1, 0, 180},
		{"no-defaults", 0, 0, 181},
		{"pax-command", 1, 0, 182},
		{"no-remote-kill", 0, 0, 184},
		{"no-getconf", 0, 0, 185},
		{"use-getconf", 0, 0, 186},
		{"shell-command", 1, 0, 188},
		{"ssh-options", 1, 0, 195},
		{"debug-events", 0, 0, 196},
		{"source-script-name", 1, 0, 198},
		{"target-script-name", 1, 0, 199},
		{"any-format", 0, 0, 200},
		{0, 0, 0, 0}
             };

	struct option posix_extended_long_options[] =
             {
		{"distribution_target_directory", 1, 0, 232},
		{"verbose", 			1, 0, 206},
		{"installed_software_catalog",	1, 0, 217},
		{"swbis_no_getconf", 		1, 0, 218},
		{"swbis_shell_command", 	1, 0, 219},
		{"swbis_no_remote_kill", 	1, 0, 220},
		{"swbis_local_pax_write_command", 1, 0, 222},
		{"swbis_remote_pax_write_command", 1, 0, 223},
		{"swbis_local_pax_read_command", 1, 0, 224},
		{"swbis_remote_pax_read_command", 1, 0, 225},
               {0, 0, 0, 0}
             };

	struct option impl_extensions_long_options[] =
             {
		{"noop", 0, 0, 154},
		{"show-options", 0, 0, 158},
		{"show-options-files", 0, 0, 159},
		{"testnum", 1, 0, 164},
		{"remote-shell", 1, 0, 172},
		{"local-pax-write-command", 1, 0, 175},
		{"remote-pax-write-command", 1, 0, 176},
		{"pax-write-command", 1, 0, 177},
		{"remote-pax-read-command", 1, 0, 178},
		{"local-pax-read-command", 1, 0, 179},
		{"pax-read-command", 1, 0, 180},
		{"no-defaults", 0, 0, 181},
		{"pax-command", 1, 0, 182},
		{"no-remote-kill", 0, 0, 184},
		{"no-getconf", 0, 0, 185},
		{"use-getconf", 0, 0, 186},
		{"shell-command", 1, 0, 188},
		{"ssh-options", 1, 0, 195},
		{"debug-events", 0, 0, 196},
		{"source-script-name", 1, 0, 198},
		{"target-script-name", 1, 0, 199},
		{"any-format", 0, 0, 200},
		{0, 0, 0, 0}
             };
	
	struct option std_long_options[] =
             {
		{"attribute", 1, 0, 'a'},
		{"catalog", 1, 0, 'c'},
		{"distribution", 0, 0, 'd'},
		{"selections-file", 1, 0, 'f'},
		{"level", 1, 0, 'l'},
		{"installed-software", 0, 0, 'r'},
		{"target-file", 1, 0, 't'},
		{"extended-option", 1, 0, 'x'},
		{"defaults-file", 1, 0, 'X'},
		{"extension-option", 1, 0, 'W'},
		{"index-format", 0, 0, 'v'},
		{"help", 0, 0, '\012'},
               {0, 0, 0, 0}
             };
       
	struct ugetopt_option_desc main_help_desc[] =
             {
	{"", "", "specifies which attributes to list"},
	{"", "", "specify a catalog directory for write into"},
	{"", "", "causes swlist to operate on a distribution"},
	{"", "FILE","Take software selections from FILE."},
	{"", "", "specify the software level to list\n"},
	{"", "", "causes swlist to operate on installed software\n"
	"          located at an alternate root."},
	{"", "FILE", "Specify a FILE containing a list of targets." },
	{"", "option=value", "Specify posix extended option."},
	{"", "FILE[ FILE2 ...]", "Specify files that override \n"
	"        system option defaults. Specify empty string to disable \n"
	"        option file reading."
	},
	{"", "option[=value]", "Specify implementation extension option."},
	{"", "", "List in INDEX file format"},
	{"help", "", "Show this help to stdout (impl. extension)."},
	{0, 0, 0}
	};

	/*  End of Decalarations.  */
	
	G = &g_blob;
	gb_init(G);
	G->g_target_fdar = target_fdar;
	G->g_source_fdar = source_fdar;
	G->g_verbose_threshold = SWC_VERBOSE_1;

	target_fdar[0] = -1;
	target_fdar[1] = -1;
	target_fdar[2] = -1;

	source_fdar[0] = -1;
	source_fdar[1] = -1;
	source_fdar[2] = -1;

	source_stdio_fdar[0] = (STDIN_FILENO);
	source_stdio_fdar[1] = (STDOUT_FILENO);
	source_stdio_fdar[2] = (STDERR_FILENO);

	target_stdio_fdar[0] = (STDIN_FILENO);
	target_stdio_fdar[1] = (STDOUT_FILENO);
	target_stdio_fdar[2] = (STDERR_FILENO);

	save_stdio_fdar[0] = dup(STDIN_FILENO);
	save_stdio_fdar[1] = dup(STDOUT_FILENO);
	save_stdio_fdar[2] = dup(STDERR_FILENO);
	
	G->g_vstderr = stderr;

	G->g_main_sig_handler = main_sig_handler;
	G->g_safe_sig_handler = safe_sig_handler;

	target_fork_type = G->g_fork_pty_none;	


	swutil = swutil_open();
	G->g_swutil = swutil;

	G->g_logspec.logfdM = -1;
	G->g_logspec.loglevelM = 0;
	G->g_logspec.fail_loudlyM = -1;
	swc_set_stderr_fd(G, STDERR_FILENO);
	swlib_utilname_set(progName);
	swgp_check_fds();
	p_do_progressmeter = &G->g_do_progressmeter;

	G->g_targetfd_array[0] = -1;
	statbytes = 0;
	fork_defaultmask = &G->g_fork_defaultmask;
	fork_blockmask = &G->g_fork_blockmask;
	currentmask = &G->g_currentmask;
	sigemptyset(currentmask);
	sigemptyset(fork_blockmask);
	sigaddset(fork_blockmask, SIGALRM);
	sigemptyset(fork_defaultmask);
	sigaddset(fork_defaultmask, SIGINT);
	sigaddset(fork_defaultmask, SIGPIPE);
	
	source_line_buf = strob_open(10);
	target_line_buf = strob_open(10);

	nullfd = G->g_nullfd;

	swc0_create_parser_buffer();
	
	target_sshcmd[1] = (SHCMD*)NULL;
	source_sshcmd[1] = (SHCMD*)NULL;
	kill_sshcmd[1] = (SHCMD*)NULL;
	target_kill_sshcmd[1] = (SHCMD*)NULL;
	
	kill_sshcmd[0] = (SHCMD*)NULL;
	source_sshcmd[0] = shcmd_open();
	target_sshcmd[0] = (SHCMD*)NULL;
	target_kill_sshcmd[0] = shcmd_open();

	tmp = strob_open(10);		/* General use String object. */
	tmpcommand = strob_open(10);
	w_arglist = cplob_open(1);	/* Pointer list object. */
	e_arglist = cplob_open(1);	/* Pointer list object. */

	initExtendedOption();

	if (getcwd(cwd, sizeof(cwd) - 1) == NULL) {
		swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, &G->g_logspec, swc_get_stderr_fd(G), 
			"%s\n", strerror(errno));
		LCEXIT(1);
	}
	cwd[sizeof(cwd) - 1] = '\0';

	/* Set the compiled-in defaults for the extended options.  */

	eopt_distribution_target_directory = "-";
	eopt_installed_software_catalog = "var/lib/swbis/catalog/";
	eopt_one_liner			= "true";
	eopt_select_local		= "false";
	eopt_verbose			= "1";

	wopt_no_getconf			= "false";
	wopt_no_remote_kill		= "false";
	wopt_shell_command		= "posix";
	wopt_local_pax_write_command 	= "pax"; 
	wopt_remote_pax_write_command 	= "pax";
	wopt_local_pax_read_command 	= "pax";
	wopt_remote_pax_read_command 	= "pax";

	wopt_show_options = NULL;
	wopt_show_options_files = NULL;

	set_opta_initial(opta, SW_E_distribution_target_directory, eopt_distribution_target_directory);
	set_opta_initial(opta, SW_E_installed_software_catalog, eopt_installed_software_catalog);
	set_opta_initial(opta, SW_E_one_liner, eopt_one_liner);
	set_opta_initial(opta, SW_E_select_local, eopt_select_local);
	set_opta_initial(opta, SW_E_verbose, eopt_verbose);

	set_opta_initial(opta, SW_E_swbis_no_getconf, wopt_no_getconf);
	set_opta_initial(opta, SW_E_swbis_remote_shell_client, remote_shell_command);
	set_opta_initial(opta, SW_E_swbis_shell_command, wopt_shell_command);
	set_opta_initial(opta, SW_E_swbis_no_remote_kill, wopt_no_remote_kill);
	set_opta_initial(opta, SW_E_swbis_local_pax_write_command,
					wopt_local_pax_write_command);
	set_opta_initial(opta, SW_E_swbis_remote_pax_write_command,
					wopt_remote_pax_write_command);
	set_opta_initial(opta, SW_E_swbis_local_pax_read_command,
					wopt_local_pax_read_command);
	set_opta_initial(opta, SW_E_swbis_remote_pax_read_command,
					wopt_remote_pax_read_command);
	set_opta_initial(opta, SW_E_swbis_any_format, wopt_any_format);

	cplob_add_nta(w_arglist, strdup(argv[0]));
	cplob_add_nta(e_arglist, strdup(argv[0]));

	while (1) {
		int option_index = 0;

		c = ugetopt_long(argc, argv, "a:c:df:t:rl:Vvs:X:x:W:", 
					main_long_options, &option_index);
		if (c == -1) break;

		switch (c) {
		case 'a':
			opt_attribute = strdup(optarg);
			break;
		case 'c':
			opt_catalog = strdup(optarg);
			break;
		case 'd':
			opt_do_distribution = 1;
			break;
		case 'l':
			opt_list_level = swlib_atoi(optarg, NULL);
			break;
		case 'r':
			opt_alt_catalog_root = 1;
			break;
		case 'v':
			G->g_verboseG++;
			eopt_verbose = (char*)malloc(12);
			snprintf(eopt_verbose, 11, "%d", G->g_verboseG);
			eopt_verbose[11] = '\0';
			set_opta(opta, SW_E_verbose, eopt_verbose);
			opt_index_file_format = 1;
			break;
		case 'f':
			/* Process the selection file */
			if (swc_process_swoperand_file(swutil,
				"selections", optarg, &stdin_in_use,
				&select_array_index, G->g_selectfd_array))
			{
				LCEXIT(1);
			}
			break;
		case 't':
			/* Process the target file */
			if (swc_process_swoperand_file(swutil,
				"target", optarg, &stdin_in_use,
				&target_array_index, G->g_targetfd_array))
			{
				LCEXIT(1);
			}
			break;
		case 'W':
			swc0_process_w_option(tmp, w_arglist, optarg, &w_argc);
			break;
		case 'x':
			exoption_arg = strdup(optarg);
			SWLIB_ALLOC_ASSERT(exoption_arg != NULL);
			/*  Parse the extended option and add to pointer list
			    for later processing.  */
			{
				char * np;
				char * t;
				STROB * etmp = strob_open(10);
				
				t = strob_strtok(etmp, exoption_arg, " ");
				while (t) {
					exoption_value = strchr(t,'=');
					if (!exoption_value) {
						swlib_doif_writef(G->g_verboseG, 
							G->g_fail_loudly, 
							&G->g_logspec, swc_get_stderr_fd(G),
						"invalid extended arg : %s\n", 
							optarg);
						_exit(1);
					}
					np = exoption_value;
					*exoption_value = '\0';
					exoption_value++;
					/*
					 * 
					 *  Now add the option and value to 
					 *  the arg list.
					 * 
					 */
					strob_strcpy(tmp, "--");
					strob_strcat(tmp, t);
					strob_strcat(tmp, "=");
					strob_strcat(tmp, exoption_value);
					cplob_add_nta(e_arglist, 
						strdup(strob_str(tmp)));
					e_argc++;

					*np = '=';
					t = strob_strtok(etmp, NULL, " ");
				}
				strob_close(etmp);
			}
			break;
		case 'X':
			if (opt_option_files) {
				opt_option_files = (char*)realloc(
						(void*)opt_option_files,
						strlen(opt_option_files) \
						+ strlen(optarg) + 2);
				strcat(opt_option_files, " ");
				strcat(opt_option_files, optarg);
			} else {
				opt_option_files = strdup(optarg);
			}
			break;
               case 'V':
			version_info(stdout);
			LCEXIT(0);
		 	break;
               case '\012':
			usage(stdout, 
				argv[0], 
				std_long_options, 
				main_help_desc);
			LCEXIT(0);
		 	break;
               case '?':
			swlib_doif_writef(G->g_verboseG,
				G->g_fail_loudly, &G->g_logspec, swc_get_stderr_fd(G),
				"Try `swinstall --help' for more information.\n");
			LCEXIT(1);
		 	break;
               default:
			if (c >= 154 && c <= WOPT_LAST) { 
				/*  This provides the ablility to specify 
				    extension options by using the 
				    --long-option syntax (i.e. without using 
				    the -Woption syntax)  */
				do_extension_options_via_goto = 1;
				goto gotoExtensionOptions;
gotoStandardOptions:
				;
			} else {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
					&G->g_logspec, swc_get_stderr_fd(G),
					"invalid args.\n");
		 		LCEXIT(1);
			}
			break;
               }
	}

	main_optind = optind;

	optind = 1;
	optarg =  NULL;
		
	while (1) {
		int e_option_index = 0;
		c = ugetopt_long (e_argc, 
				cplob_get_list(e_arglist), 
				"", 
				posix_extended_long_options, 
				&e_option_index);
		if (c == -1) break;
		
		switch (c) {
		
		case 232:
			eopt_distribution_target_directory = strdup(optarg);
			set_opta(opta, 
				SW_E_distribution_target_directory, 
				eopt_distribution_target_directory);
			SWLIB_ALLOC_ASSERT
				(eopt_distribution_target_directory != NULL);
			break;
		case 206:
			eopt_verbose = strdup(optarg);
			G->g_verboseG = swlib_atoi(eopt_verbose, NULL);
			set_opta(opta, SW_E_verbose, eopt_verbose);
			break;
		case 217:
			eopt_installed_software_catalog = strdup(optarg);
			set_opta(opta, SW_E_installed_software_catalog, eopt_installed_software_catalog);
			break;
		case 218:
		case 219:
		case 220:
		case 222:
		case 223:
		case 224:
		case 225:
			optionname = getLongOptionNameFromValue(posix_extended_long_options , c);
			SWLIB_ASSERT(optionname != NULL);
			optionEnum = getEnumFromName(optionname, opta);
			SWLIB_ASSERT(optionEnum > 0);
			set_opta(opta, optionEnum, optarg);
			break;
		default:
			swlib_doif_writef(G->g_verboseG,
				G->g_fail_loudly, &G->g_logspec, swc_get_stderr_fd(G),
				"error processing extended option\n");
			swlib_doif_writef(G->g_verboseG,
				G->g_fail_loudly, &G->g_logspec, swc_get_stderr_fd(G),
				"Try `swlist --help' for more information.\n");
		 	LCEXIT(1);
               break;
               }
	}
	optind = 1;
	optarg =  NULL;

	/*  Now run the Implementation extension options (-W) through getopt.  */
	while (1) {
		int w_option_index = 0;
		c = ugetopt_long(w_argc, 
				cplob_get_list(w_arglist), 
				"", 
				impl_extensions_long_options, 
				&w_option_index);
		if (c == -1) break;
	
gotoExtensionOptions:    /* Goto, Uhhg... */
		switch (c) {
		case 154: /* noop */
			break;
		case 158:
			wopt_show_options = CHARTRUE;
			break;
		case 159:
			wopt_show_options_files = CHARTRUE;
			break;
		case 164:
			/* Development testing controls.  */
			testnum = swlib_atoi(optarg, NULL);
			if (testnum == 10) {
				devel_no_fork_optimization = 1;
			} else if (testnum == 11) {
				wopt_with_hop_pids = 1;
			}
			break;
		case 172:
			remote_shell_command = strdup(optarg);
			set_opta(opta, SW_E_swbis_remote_shell_client, remote_shell_command);
			break;
		case 175:
			wopt_local_pax_write_command = strdup(optarg);
			xcmd = swc_get_pax_write_command(
					G->g_pax_write_commands, wopt_local_pax_write_command,
							 G->g_verboseG, (char*)NULL);
			if (xcmd == NULL) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
					&G->g_logspec, swc_get_stderr_fd(G),
					"illegal pax write command: %s \n",
						wopt_local_pax_write_command);
				LCEXIT(1);
			}
			set_opta(opta, SW_E_swbis_local_pax_write_command,
					wopt_local_pax_write_command);
			break;
		case 176:
			wopt_remote_pax_write_command = strdup(optarg);
			xcmd = swc_get_pax_write_command(
				G->g_pax_write_commands, wopt_remote_pax_write_command, G->g_verboseG, (char*)NULL);
			if (xcmd == NULL) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
					&G->g_logspec, swc_get_stderr_fd(G),
					"illegal pax write command: %s \n", 
					wopt_remote_pax_write_command);
				LCEXIT(1);
			}
			set_opta(opta, SW_E_swbis_remote_pax_write_command,
						wopt_remote_pax_write_command);
			break;
		case 177:
			wopt_local_pax_write_command = strdup(optarg);
			wopt_remote_pax_write_command = strdup(optarg);
			xcmd = swc_get_pax_write_command(
					G->g_pax_write_commands, wopt_local_pax_write_command,
							G->g_verboseG, (char*)NULL);
			if (xcmd == NULL) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly,
					&G->g_logspec, swc_get_stderr_fd(G),
					"illegal pax write command: %s \n",
						wopt_local_pax_write_command);
				LCEXIT(1);
			}
			set_opta(opta, SW_E_swbis_local_pax_write_command,  
						wopt_local_pax_write_command);
			set_opta(opta, SW_E_swbis_remote_pax_write_command,  
						wopt_local_pax_write_command);
			break;
		case 178:
			wopt_remote_pax_read_command = strdup(optarg);
			xcmd = swc_get_pax_read_command(G->g_pax_read_commands,
					wopt_remote_pax_read_command,
						 0, 0, (char*)NULL);
			if (xcmd == NULL) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly,
					&G->g_logspec, swc_get_stderr_fd(G),
					"illegal pax read command: %s \n",
						wopt_remote_pax_read_command);
				LCEXIT(1);
			}
			set_opta(opta, SW_E_swbis_remote_pax_read_command,
						wopt_remote_pax_read_command);
			break;
		case 179:
			wopt_local_pax_read_command = strdup(optarg);
			xcmd = swc_get_pax_read_command(G->g_pax_read_commands,
						wopt_local_pax_read_command, 
							0, 0, (char*)NULL);
			if (xcmd == NULL) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
						&G->g_logspec, swc_get_stderr_fd(G),
					"illegal pax read command: %s \n", 
						wopt_local_pax_read_command);
				LCEXIT(1);
			}
			set_opta(opta, SW_E_swbis_local_pax_read_command,  
						wopt_local_pax_read_command);
			break;
		case 180:
			wopt_local_pax_read_command = strdup(optarg);
			wopt_remote_pax_read_command = strdup(optarg);
			xcmd = swc_get_pax_read_command(G->g_pax_read_commands,
						wopt_local_pax_read_command,
							0, 0, (char*)NULL);
			if (xcmd == NULL) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
					&G->g_logspec, swc_get_stderr_fd(G),
					"illegal pax read command: %s \n",
					wopt_local_pax_read_command);
				LCEXIT(1);
			}
			set_opta(opta, SW_E_swbis_local_pax_read_command,
						wopt_local_pax_read_command);
			set_opta(opta, SW_E_swbis_remote_pax_read_command,
						wopt_local_pax_read_command);
			break;
		case 181:
			wopt_no_defaults = 1;
			break;
		case 182:
			wopt_local_pax_read_command = strdup(optarg);
			wopt_remote_pax_read_command = strdup(optarg);
			wopt_local_pax_write_command = strdup(optarg);
			wopt_remote_pax_write_command = strdup(optarg);
			xcmd = swc_get_pax_read_command(G->g_pax_read_commands,
						wopt_local_pax_read_command,
							0, 0, (char*)NULL);
			if (xcmd == NULL) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly,
					&G->g_logspec, swc_get_stderr_fd(G),
					"illegal pax read command: %s \n",
					wopt_local_pax_read_command);
				LCEXIT(1);
			}
			set_opta(opta, SW_E_swbis_local_pax_read_command,
						wopt_local_pax_read_command);
			set_opta(opta, SW_E_swbis_remote_pax_read_command,
						wopt_local_pax_read_command);
			set_opta(opta, SW_E_swbis_local_pax_write_command,
						wopt_local_pax_write_command);
			set_opta(opta, SW_E_swbis_remote_pax_write_command,
						wopt_local_pax_write_command);
			break;
		case 184:
			wopt_no_remote_kill = CHARTRUE;
			set_opta(opta, SW_E_swbis_no_remote_kill, "true");
			break;
		case 185:
			wopt_no_getconf = CHARTRUE;
			set_opta(opta, SW_E_swbis_no_getconf, "true");
			break;
		case 186:
			wopt_no_getconf = CHARFALSE;
			set_opta(opta, SW_E_swbis_no_getconf, "false");
			break;
		case 188:
			wopt_shell_command = strdup(optarg);
			if (
				strcmp(wopt_shell_command, "bash") &&
				strcmp(wopt_shell_command, "sh") &&
				strcmp(wopt_shell_command, "ksh") &&
				strcmp(wopt_shell_command, "ash") &&
				strcmp(wopt_shell_command, "posix")
			) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly,
					&G->g_logspec, swc_get_stderr_fd(G),
					"illegal shell command: %s \n",
					wopt_shell_command);
				exit(1);
			}
			set_opta(opta, SW_E_swbis_shell_command, wopt_shell_command);
			break;
		case 195:
			wopt_ssh_options = strdup(optarg);
			break;
		case 196:
			G->g_do_debug_events = 1;
			break;
		case 198:
			G->g_source_script_name = strdup(optarg);
			break;
		case 199:
			G->g_target_script_name = strdup(optarg);
			break;
		case 200:
			wopt_any_format = CHARTRUE;
			set_opta(opta, SW_E_swbis_any_format, "true");
			break;
		default:
			swlib_doif_writef(G->g_verboseG, G->g_fail_loudly,
					&G->g_logspec, swc_get_stderr_fd(G),
		"error processing implementation extension option : %s\n",
				cplob_get_list(w_arglist)[w_option_index]);
		 	exit(1);
		break;
		}
		if (do_extension_options_via_goto == 1) {
			do_extension_options_via_goto = 0;
			goto gotoStandardOptions;
		}
	}

	optind = main_optind;

	system_defaults_files = initialize_options_files_list(NULL);

	/* Show the options to stdout.  */

	if (wopt_show_options_files) { 
		parse_options_files(opta, 
			system_defaults_files, 
			progName, 1 /* not req'd */,  1 /* show_only */);
		parse_options_files(opta, 
			opt_option_files, 
			progName,
		 	1 /* not req'd */,  1 /* show_only */);
		LCEXIT(0);
	}

	/*  Read the system defaults files and home directory copies
	    if HOME is set.  */

	if (wopt_no_defaults == 0) {
		optret += parse_options_files(opta, 
			system_defaults_files, 
			progName, 
			0 /* not req'd */,  0 /* not show_only */);
		if (optret) {
			swlib_doif_writef(G->g_verboseG, G->g_fail_loudly,
						&G->g_logspec, swc_get_stderr_fd(G),
						"defaults file error\n");
			LCEXIT(1);
		}
	}
	
	/*  Read the defaults files given with the -X option.  */

	optret += parse_options_files(opta, 
		opt_option_files, 
		progName, 	
		1 /* req'd */, 0 /* not show_only */);
	if (optret) {
		swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
				&G->g_logspec, swc_get_stderr_fd(G),
				"defaults file error\n");
		LCEXIT(1);
	}

	/*  Reset the option values to pick up the values from 
	    the defaults file(s). */

	eopt_installed_software_catalog = get_opta(opta, SW_E_installed_software_catalog);
	eopt_select_local		= get_opta(opta, SW_E_select_local);
	eopt_one_liner			= get_opta(opta, SW_E_one_liner);
	eopt_verbose			= get_opta(opta, SW_E_verbose);
		G->g_verboseG = swlib_atoi(eopt_verbose, NULL);
	
	wopt_no_remote_kill		= swbisoption_get_opta(opta, 
							SW_E_swbis_no_remote_kill);
	wopt_no_getconf			= swbisoption_get_opta(opta, 
							SW_E_swbis_no_getconf);
	wopt_shell_command		= swbisoption_get_opta(opta, 
							SW_E_swbis_shell_command);
	remote_shell_command		= swbisoption_get_opta(opta, 
							SW_E_swbis_remote_shell_client);
	wopt_local_pax_write_command	= swbisoption_get_opta(opta, 	
					SW_E_swbis_local_pax_write_command);
	wopt_remote_pax_write_command	= swbisoption_get_opta(opta, 
					SW_E_swbis_remote_pax_write_command);
	wopt_local_pax_read_command	= swbisoption_get_opta(opta, 
						SW_E_swbis_local_pax_read_command);
	wopt_remote_pax_read_command	= swbisoption_get_opta(opta, 
						SW_E_swbis_remote_pax_read_command);

	if (wopt_show_options) { 
		swextopt_writeExtendedOptions(STDOUT_FILENO, opta, SWC_U_L);
		if (G->g_verboseG > 4) {
			debug_writeBooleanExtendedOptions(STDOUT_FILENO, opta);
		}
		LCEXIT(0);
	}

	if (strcasecmp(wopt_shell_command, "posix") == 0) {
		sh_dash_s = "sh -s";
	} else if (strcasecmp(wopt_shell_command, "bash") == 0) {
		sh_dash_s = "bash -s";
	} else if (strcasecmp(wopt_shell_command, "sh") == 0) {
		sh_dash_s = "sh -s";
	} else if (strcasecmp(wopt_shell_command, "ash") == 0) {
		sh_dash_s = "ash -s";
	} else if (strcasecmp(wopt_shell_command, "ksh") == 0) {
		sh_dash_s = "ksh -s";
	} else {
		sh_dash_s = "sh -s";
	}
	
	remote_shell_path = shcmd_find_in_path(getenv("PATH"), 
						remote_shell_command);

	use_no_getconf = swc_is_option_true(wopt_no_getconf);	


	/* Configure the standard I/O usages.  */

	fver = G->g_vstderr;
	fverfd = STDERR_FILENO;
	
	if (G->g_verboseG == 0 /* && opt_preview == 0 */) {
		fver = fopen("/dev/null", "r+");
		if (!fver) LCEXIT(1);
		G->g_vstderr = fver;
		fverfd = nullfd;
		dup2(nullfd, STDOUT_FILENO);
		dup2(nullfd, STDERR_FILENO);
	}

	if (G->g_verboseG >= SWC_VERBOSE_7) {
		swlib_set_verbose_level(G->g_verboseG);
	}
	
	/* Set the terminal setting and ssh tty option.  */
	
	tty_opt = "-T";
	login_orig_termiosP = NULL;
	login_sizeP = NULL;
	
	/* Set the signal handlers.  */

	swgp_signal(SIGINT, safe_sig_handler);
	swgp_signal(SIGPIPE, safe_sig_handler);
	swgp_signal(SIGTERM, safe_sig_handler);

	/*  Set the Serial archive write command.  */

	/* Process the Software Selections */

	swspecs = vplob_open(); /* List object containing list of SWVERID objects */
	ret = 0;
	if (argv[optind]) {
		if (*(argv[optind]) != '@') {
			/* Must be a software selection.  */
			ret = swc_process_selection_args(swspecs, argv, argc, &optind);
		}
	}

	if (ret) {
		/* Software selection error */
		swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
			&G->g_logspec, swc_get_stderr_fd(G),
				"error processing selections\n");
		LCEXIT(sw_exitval(G, target_loop_count, target_success_count));
	}

	if (vplob_get_nstore(swspecs) > 0)
	{
		/*
		 * Software selections not supported yet.
		 */
		swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
			&G->g_logspec, swc_get_stderr_fd(G),
		"software selections not implemented: %s\n", swverid_print((SWVERID*)(vplob_val(swspecs, 0)), tmp));
		/*
			LCEXIT(sw_exitval(G, target_loop_count, target_success_count));
		*/
	}

	/* Loop over the targets.  */

   	current_arg = swc_get_next_target(argv, argc, &optind, 
						G->g_targetfd_array, 
					eopt_distribution_target_directory,
						&num_remains);
	while (current_arg) {
		distdataO = swi_distdata_create();
		swgp_signal(SIGINT, safe_sig_handler);
		swgp_signal(SIGPIPE, safe_sig_handler);
		swgp_signal(SIGTERM, safe_sig_handler);
		statbytes = 0;
		retval = 0;
		target_tramp_list = strar_open();
		target_sshcmd[0] = shcmd_open();
		target_cmdlist = strar_open();
		target_control_message = strob_open(10);
		target_start_message = strob_open(10);
		target_catalog_message = strob_open(10);
		target_access_message = strob_open(10);
		cl_target_target = NULL;
		cl_target_selections = NULL;
		working_arg = strdup(current_arg);

		/* Parse the target sofware_selections and targets.  */
		soc_spec_target = strdup(working_arg);
		if (target_loop_count == 0) {

			/* This branch really only checks for an invalid
			   syntax:   sw<utility> [args]  selection@target   */

			swc_parse_soc_spec(
				soc_spec_target, 
				&cl_target_selections, 
				&xcl_target_target
				);
			if (xcl_target_target == NULL) {
				cl_target_target = strdup(eopt_distribution_target_directory);
			} else {
				cl_target_target = strdup(xcl_target_target);
			}

			if (cl_target_selections) {

				/* Selections are not supported here.  They are applied
				   globally and processed before entering the target processing
				   loop. */

				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
				&G->g_logspec, swc_get_stderr_fd(G),
				"software selection not valid when specified with a specific target.\n");
				LCEXIT(sw_exitval(G, target_loop_count, 
						target_success_count));
			}
		} else {
			/* subsequext args are targets, the same software
                           selection applies.  */

			cl_target_target = strdup(soc_spec_target);
		}

		target_nhops = swssh_parse_target(target_sshcmd[0],
				target_kill_sshcmd[0],
				cl_target_target,
				remote_shell_path,
				remote_shell_command,
				&tmpcharp,
				&target_terminal_host,
				tty_opt, wopt_with_hop_pids,
				wopt_ssh_options);
		SWLIB_ASSERT(target_nhops >= 0);

		if (pax_write_command_key == (char*)NULL) {
			if (target_nhops < 1) {
				/* Local host */
				pax_write_command_key = wopt_local_pax_write_command;
			} else {
				/* Remote host */
				pax_write_command_key = wopt_remote_pax_write_command;
			}		
		}

		if (xcl_target_target == NULL && target_nhops >= 1 && 
					strcmp(cl_target_target, "-") == 0) {
			/* reading from stdin on a remote host is not supported.
			   Reset the the default target */

			/* FIXME?? silently change the target to something that makes
			   sense */
			cl_target_target = strdup(".");
		}

		target_path = swc_validate_targetpath(
					target_nhops, 
					tmpcharp, 
					eopt_distribution_target_directory, cwd);

		SWLIB_ASSERT(target_path != NULL);

		if (strcmp(target_path, "-") == 0 && target_nhops >= 1) {
			/* error
			   cannot write to stdout except on localhost */

			swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
						&G->g_logspec, swc_get_stderr_fd(G),
						"invalid target spec\n");
			LCEXIT(sw_exitval(G, target_loop_count, 
						target_success_count));
		}

		if (strcmp(target_path, "-") == 0) { 
			if (stdin_in_use) {

				/* error */
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
					&G->g_logspec, swc_get_stderr_fd(G),
					"invalid usage of stdin\n");
				LCEXIT(1);
			}
			local_stdin = 1; 
		}

		G->g_swevent_fd = swevent_fd;

		/*
		 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
		 *   Establish the logger process and stderr redirection.
		 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
		 */
		if (target_loop_count == 0) {
			G->g_logger_pid = swc_fork_logger(G, source_line_buf,
					target_line_buf, swc_get_stderr_fd(G),
					swevent_fd, &G->g_logspec, &G->g_s_efd, &G->g_t_efd,
					G->g_verboseG,  &swi_event_fd);
		}

		G->g_swi_event_fd = swi_event_fd;
		target_stdio_fdar[2] = G->g_t_efd;
		source_stdio_fdar[2] = G->g_s_efd;
		swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB,
				&G->g_logspec, swc_get_stderr_fd(G), 
				"logger_pid is %d\n", G->g_logger_pid);

		swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_3 + SWLIST_UPVERBOSE, 
			&G->g_logspec, swevent_fd,
			"SWBIS_TARGET_BEGINS for %s\n", current_arg);

		swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);

		pax_read_command_key = wopt_local_pax_read_command;
		pax_write_command_key = wopt_local_pax_write_command;

		swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB2, &G->g_logspec,
				swc_get_stderr_fd(G), 
				"target_fork_type : %s\n",
					target_fork_type);

		swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);

		/* Make the target piping (which is really the source to read) */
		if (local_stdin == 0) {
			/* Remote target */
			E_DEBUG("");

			if (swlib_is_sh_tainted_string(target_path)) {
				SWLIB_FATAL("tainted path");
			}
			ss_pid = swc_run_ssh_command(
				target_sshcmd,
				target_cmdlist,
				target_path,
				0 /*opt_preview */,
				target_nhops,
				target_fdar,
				target_stdio_fdar,
				login_orig_termiosP,
				login_sizeP, 
				&target_pump_pid, 
				target_fork_type, 
				make_master_raw, 
				(sigset_t*)fork_blockmask, 
				devel_no_fork_optimization,
				G->g_verboseG,
				&target_file_size,
				use_no_getconf,
				&is_target_local_regular_file,
				wopt_shell_command,
				swc_get_stderr_fd(G),
				&G->g_logspec);
			swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);

			if (is_target_local_regular_file) {
				if (lseek(target_fdar[0],
						(off_t)0, SEEK_SET) != 0) {
					/* sanity check */
					swlib_doif_writef(G->g_verboseG, G->g_fail_loudly, 
						&G->g_logspec, swc_get_stderr_fd(G),
					"lseek internal error on stdio_fdar[0]\n");
					retval = 1;
					goto TARGET1;
				}
			} 

			if (ss_pid < 0) {
				/* Fatal */		
				LCEXIT(sw_exitval(G,
					target_loop_count, 
					target_success_count));
			}

			if (ss_pid > 0) { 
				/* Normal */
				swc_record_pid(ss_pid, 
					G->g_pid_array, 
					&G->g_pid_array_len, 
					G->g_verboseG);
			}

			if (target_pump_pid > 0) {
				/* This is the child of slave 
				   pty process, zero if there 
				   isn't one.  */
				swc_record_pid(target_pump_pid, 
					G->g_pid_array, 
					&G->g_pid_array_len, 
					G->g_verboseG);
			}
			
			if (isatty(target_fdar[0])) {
				if (swlib_tty_raw(target_fdar[0]) < 0) {
					swlib_doif_writef(G->g_verboseG, 
						G->g_fail_loudly, 
						&G->g_logspec, swc_get_stderr_fd(G),
					"tty_raw error : target_fdar[0]\n");
					LCEXIT(
					sw_exitval(G, target_loop_count, 
						target_success_count));
				}
			}

		} else {

			/* here is the target piping for local stdin
			  If the '-d' is not specified then exit with error */

			E_DEBUG("");
			if (!opt_do_distribution) {
				swlib_doif_writef(G->g_verboseG, G->g_fail_loudly,
					&G->g_logspec, swc_get_stderr_fd(G),
				"invalid target spec\n");
				LCEXIT(1);
			}
			ss_pid = 0;
			target_fdar[0] = target_stdio_fdar[0];
			target_fdar[1] = target_stdio_fdar[1];
			target_fdar[2] = target_stdio_fdar[2];
		}

		E_DEBUG("");
		if (is_local_stdin_seekable  || is_target_local_regular_file) {
			E_DEBUG("");
			G->g_is_seekable = 1;
		} else {
			E_DEBUG("");
			G->g_is_seekable = 0;
		}

		/* Write the target script (to read the source). */

		source_write_pid = swc_run_source_script(G,
					swutil_x_mode, 
				local_stdin || is_target_local_regular_file,
					target_fdar[1],
					target_path,
					target_nhops, 
					pax_write_command_key,
					fork_blockmask,
					fork_defaultmask,
					target_terminal_host,
					wopt_blocksize, SWC_VERBOSE_4);
		swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);
		swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB, 
			&G->g_logspec, swc_get_stderr_fd(G), 
				"source write pid: %d\n", source_write_pid);

		if (source_write_pid > 0) {
			E_DEBUG("");
			swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB, 
				&G->g_logspec, swc_get_stderr_fd(G), 
				"waiting on source script pid\n");

			/* Wait on the target script  */

			if ((ret=swc_wait_on_script(G, source_write_pid, 
						"source")) != 0) {
				/* error */

				swlib_doif_writef(G->g_verboseG, 
					G->g_fail_loudly, &G->g_logspec, swc_get_stderr_fd(G),
				"write_scripts waitpid : exit value = %d\n",
					ret );
				swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);
				LCEXIT(
					sw_exitval(G, target_loop_count,	
						target_success_count));
			}
				
			swlib_doif_writef(G->g_verboseG, 
				SWC_VERBOSE_IDB, 
				&G->g_logspec, swc_get_stderr_fd(G), 
				"wait() on source script succeeded.\n");

			/* Read the start message and the pid */

			if (swc_read_start_ctl_message(G,
				target_fdar[0], 
				target_start_message,
				target_tramp_list,
				G->g_verboseG,
				&target_script_pid, "source") 
				< 0
				)
			{
				/* start message indicated failure, error */

				LC_RAISE(SIGTERM);
				swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);
				swlib_doif_writef(G->g_verboseG, 1, 
					&G->g_logspec, swc_get_stderr_fd(G),
					"read_start_ctl_message error"
					" (loc=start)\n");
				LCEXIT(sw_exitval(G,
					target_loop_count, 
					target_success_count));
			}

			swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB, 
					&G->g_logspec, swc_get_stderr_fd(G),
					"start_ctl_message(loc=start): %s\n",
						strob_str(target_start_message));
			
			if (target_nhops >= wopt_kill_hop_threshhold) {

				/* Construct the remote kill vector.  */

				G->g_killcmd = NULL;
				swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB2, 
					&G->g_logspec, swc_get_stderr_fd(G), 
				"Running swc_construct_newkill_vector\n");
				if ((ret=swc_construct_newkill_vector(
					target_kill_sshcmd[0], 
					target_nhops,
					target_tramp_list, 
					target_script_pid, 
					G->g_verboseG)) < 0) 
				{
					target_kill_sshcmd[0] = NULL;
					swlib_doif_writef(G->g_verboseG, 
							G->g_fail_loudly, 
							&G->g_logspec, swc_get_stderr_fd(G),
					"target kill command not constructed"
					"(ret=%d), maybe a shell does not "
					"have PPID.\n", ret);
				}
				G->g_target_kmd = target_kill_sshcmd[0];
			}
			swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);

			/* Read the leading control message from the 
			   output of the source script. */

			if ( SWINSTALL_DO_SOURCE_CTL_MESSAGE ) {
				/* Read the control message from the remote source.  */

				swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB,
					&G->g_logspec, swc_get_stderr_fd(G),
				"reading source script control messages\n");

				if (swc_read_target_ctl_message(G,
					target_fdar[0], 
					target_control_message,
					G->g_verboseG, "source") < 0) 
				{
					swlib_doif_writef(G->g_verboseG, 
						SWC_VERBOSE_IDB,
							&G->g_logspec, swc_get_stderr_fd(G),
						"read_target_ctl_message error"
						" (loc=source_start)\n");
					main_sig_handler(SIGTERM);
					LCEXIT(sw_exitval(G,
						target_loop_count,
						target_success_count));
				}
				swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB,
					&G->g_logspec, swc_get_stderr_fd(G),
					"Got source control message [%s]\n",
					strob_str(target_control_message));
			} else {
				swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB, 
				&G->g_logspec, swc_get_stderr_fd(G), 
				"No source control message expected\n");
			}

			/* Read the SW_SOURCE_ACCESS_BEGIN or
			   the SW_SOURCE_ACCESS_ERROR message */	

			swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB,
				&G->g_logspec, swc_get_stderr_fd(G),
				"reading source script access messages\n");

			if (swc_read_target_ctl_message(G,
				target_fdar[0], 
				target_access_message,
				G->g_verboseG, "source") < 0
			) 
			{
				swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB, 
						&G->g_logspec, swc_get_stderr_fd(G),
					"read_target_ctl_message error"
					" (loc=target_access)\n");
				main_sig_handler(SIGTERM);
				swc_shutdown_logger(G,SIGABRT);
				LCEXIT(sw_exitval(G,
					target_loop_count,
					target_success_count));
			}
			
			/* Analyze the source event */	

			if ((ret=swevent_get_value(
					swevent_get_events_array(),
					strob_str(target_access_message))) != 
					SW_SOURCE_ACCESS_BEGINS) 
			{
				/* Source access error */

				swlib_doif_writef(G->g_verboseG, 1, 
					&G->g_logspec, swc_get_stderr_fd(G),
					"source access error: ret=%d :%s\n",
					ret, 
					strob_str(target_access_message));
				main_sig_handler(SIGTERM);
				swc_shutdown_logger(G,SIGABRT);
				LCEXIT(sw_exitval(G,
					target_loop_count,
					target_success_count));
			}
		} else if (source_write_pid == 0) {

			/* fork did not happen.
			   This is Normal, source script not required.  */

			E_DEBUG("");
			swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB,
				&G->g_logspec, swc_get_stderr_fd(G), 
				"No fork required for target control script\n"
				);
		} else {
			/* error */

			E_DEBUG("");
			swlib_doif_writef(G->g_verboseG, 1, &G->g_logspec, swc_get_stderr_fd(G),
				"fatal internal error. fork error.\n");
			main_sig_handler(SIGTERM);
			swc_shutdown_logger(G,SIGABRT);
			LCEXIT(sw_exitval(G, target_loop_count, target_success_count));
		}
		
		if (0) {
			;
		} else if (opt_do_distribution) {
			E_DEBUG("");
			/* Decode the package catalog section.
			   If '-d' option was specified then target_fdar[0]
			   contains a distribution */
			E_DEBUG("into do_decode");
			if (swi) {
				E_DEBUG("");
				xformat_close(swi->xformatM);
				swi_delete(swi);
				swi = (SWI*)NULL;
				if (uxfio_lseek(target_fdar[0], 0, SEEK_SET) != 0) {
					fprintf(stderr, "%s: uxfio_lseek error: %s : %d\n",
						swlib_utilname_get(),  __FILE__, __LINE__);
					exit(2);
				}
			}

			swgp_signal(SIGINT, main_sig_handler);
			swi = swi_create();
			SWLIB_ASSERT(swi != NULL);
			swi_set_utility_id(swi, SWC_U_L);

			E_DEBUG("into  swi_do_decode");
			ret = swi_do_decode(swi,
				G->g_swutil,
				G->g_nullfd,
				dup(target_fdar[0]),
				target_path,
				NULL /* source_path */,
				swspecs,
				target_terminal_host,
				opta,
				G->g_is_seekable,
				G->g_do_debug_events,
				G->g_verboseG,
				&G->g_logspec,
				-1 /* open flags, use default */);
			E_DEBUG("");

			if (ret) {
				E_DEBUG("");
				swlib_doif_writef(G->g_verboseG,
					G->g_fail_loudly,
					&G->g_logspec, swc_get_stderr_fd(G),
					"error decoding source\n");
				main_sig_handler(SIGTERM);
				swc_shutdown_logger(G,SIGABRT);
				LCEXIT(sw_exitval(G,
					target_loop_count, 
					target_success_count));
			}

			E_DEBUG("");
			G->g_xformat = swi->xformatM;

			swi->sh_dash_sM = strdup(sh_dash_s);
			swi->dash_rM = opt_alt_catalog_root;
			swi->swi_pkgM->target_pathM = strdup(target_path);
			swi->swi_pkgM->installed_software_catalogM =
				strdup(get_opta(opta, SW_E_installed_software_catalog));

			if (swlib_check_clean_path(swi->swi_pkgM->installed_software_catalogM)) {
				SWLIB_FATAL("tainted path");
			}
		
			/* FIXME, ?? eventually need to support a catalog location that is
			   outside of the target path */

			swlib_squash_all_leading_slash(swi->swi_pkgM->installed_software_catalogM);

			swicol_set_targetpath(swi->swicolM, target_path);
			swicol_set_delaytime(swi->swicolM, SWC_SCRIPT_SLEEP_DELAY);
			swicol_set_nhops(swi->swicolM, target_nhops);
			swicol_set_verbose_level(swi->swicolM, G->g_verboseG);

			/* Validate some basic information about the package.  */
			retval = swi_distdata_resolve(swi, distdataO,
					1 /*enforce swinstall policy*/);
			if (retval) {
				swlib_doif_writef(G->g_verboseG,
					G->g_fail_loudly,
					&G->g_logspec, swc_get_stderr_fd(G),
					"error decoding source INDEX file: swbis_code=%d\n",
					retval);
					swc_shutdown_logger(G,SIGABRT);
					LCEXIT(sw_exitval(G, target_loop_count, target_success_count));
			}

			pax_read_command = swc_get_pax_read_command(
				G->g_pax_read_commands,
				pax_read_command_key, 
				G->g_verboseG >= SWC_VERBOSE_3, 
				0 /* not used */,
				DEFAULT_PAX_R);

			swi->distdataM = distdataO;
			
			if (G->g_verboseG >= SWC_VERBOSE_7) {
				tmp_s = swi_dump_string_s(swi, "swinstall: (SWI*)");
				fprintf(fver, "%s\n", tmp_s);
			}

			/* Use the swinstall routine setup in "preview mode"
			   to list the distribution */

			E_DEBUG("");
			ret = swinstall_arfinstall(G,
					swi,
					G->g_nullfd,
					G->g_t_efd,
					&G->g_signal_flag,
					target_path,
					strob_str(target_catalog_message),
					swspecs,
					SWI_SECTION_BOTH,
					-1,
					1, 		/*opt_preview*/
					pax_read_command_key,
					opt_alt_catalog_root,
					target_fdar[2],
					opta,
					&G->g_logspec,
					0, /*keep_old_files*/
					NULL /* prorgess meter */);

			E_DEBUG2("swinstall_arfinstall returned %d", ret);
			if (ret) retval++;
			xformat_close(swi->xformatM);
			swi_delete(swi);
			swi = (SWI*)NULL;
		} else {
			fprintf(stderr, "swlist: product list mode not implemented yet\n");
			swc_shutdown_logger(G, SIGABRT);
			LCEXIT(1);
		}

		swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);

		/* This sanity check is not valid here for swlist.
		if (ss_pid && 
			waitpid(ss_pid, &tmp_status, WNOHANG) > 0) {
			swc_shutdown_logger(G, SIGABRT);
			LCEXIT(sw_exitval(G,
				target_loop_count, 
				target_success_count));
		}
		*/
		
		if (G->g_verboseG >= SWC_VERBOSE_8) {
			swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB2, 
				&G->g_logspec, swc_get_stderr_fd(G),
				"target_fdar[0] = %d\n", target_fdar[0]);
			swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB2, 
				&G->g_logspec, swc_get_stderr_fd(G),
				"target_fdar[1] = %d\n", target_fdar[1]);
			swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB2, 
				&G->g_logspec, swc_get_stderr_fd(G),
				"target_fdar[2] = %d\n", target_fdar[2]);
		}
			
		tty_raw_ctl(2);

		if (strstr(strob_str(target_control_message), 
			"SW_SOURCE_ACCESS_ERROR :") != (char*)NULL) {
			/* Error */	
			swlib_doif_writef(G->g_verboseG, 
				G->g_fail_loudly, &G->g_logspec, swc_get_stderr_fd(G),
				"SW_SOURCE_ACCESS_ERROR : []\n"
				);
			swc_shutdown_logger(G, SIGABRT);
			LCEXIT(sw_exitval(G,
				target_loop_count, 
				target_success_count));
		}

		swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);

ENTER_WITH_FAILURE:

		if (kill_sshcmd[0]) {
			shcmd_close(kill_sshcmd[0]);
			kill_sshcmd[0] = (SHCMD*)NULL;
		}

		if (target_kill_sshcmd[0]) {
			shcmd_close(target_kill_sshcmd[0]);
			target_kill_sshcmd[0] = (SHCMD*)NULL;
		}

		/* Now close down  */
			
		if (swi) {
			xformat_close(swi->xformatM);
			swi_delete(swi);
			swi = (SWI*)NULL;
		}

		swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);
		close(target_fdar[0]);
		if (target_fdar[1] != STDOUT_FILENO) 
			close(target_fdar[1]);

		swlib_wait_on_all_pids(
				G->g_pid_array, 
				G->g_pid_array_len, 
				G->g_status_array, 0 /*waitpid flags*/, 
				G->g_verboseG - 2);

		if (retval == 0) {
			retval = swc_analyze_status_array(G->g_pid_array,
						G->g_pid_array_len, 
						G->g_status_array,
						G->g_verboseG - 2);
		}
		if (retval == 0 && ret ) retval++;

		/* Now re-Initialize to prepare for the next target. */

		G->g_pid_array_len = 0;

		if (soc_spec_target) free(soc_spec_target);
		soc_spec_target = NULL;

		if (working_arg) free(working_arg);
		working_arg = NULL;

		if (cl_target_target) free(cl_target_target);
		cl_target_target = NULL;
		
		if (cl_target_selections) free(cl_target_selections);
		cl_target_selections = NULL;

		if (target_path) free(target_path);
		target_path = NULL;

		/* End real copy, not a preview */
TARGET1:
		G->g_pid_array_len = 0;

		swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);
		strar_close(target_tramp_list);
		shcmd_close(target_sshcmd[0]);
		strar_close(target_cmdlist);
		strob_close(target_control_message);
		strob_close(target_start_message);
		strob_close(target_catalog_message);
		strob_close(target_access_message);

		if (target_script_pid) free(target_script_pid);
		target_script_pid = NULL;

		target_loop_count++;
		if (retval == 0) target_success_count++;
		swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_3 + SWLIST_UPVERBOSE,
				&G->g_logspec, retval ? swc_get_stderr_fd(G) : swevent_fd,
			"SWBIS_TARGET_ENDS for %s: status=%d\n",
						current_arg,
						retval);
		swc_check_for_current_signals(G, __LINE__, wopt_no_remote_kill);
		free(current_arg);
   		current_arg = swc_get_next_target(argv, 
						argc, 
						&optind, 
						G->g_targetfd_array,
					eopt_distribution_target_directory, &num_remains);
	} /* target loop */
	swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB, 
			&G->g_logspec, swc_get_stderr_fd(G), "Finished processing targets\n");
	if (targetlist_fd >= 0) close(targetlist_fd);
	swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_IDB, &G->g_logspec, swc_get_stderr_fd(G), 
		"exiting at %s:%d with value %d\n",
		__FILE__, __LINE__,
		sw_exitval(G, target_loop_count, target_success_count));

	swlib_doif_writef(G->g_verboseG, SWC_VERBOSE_6, 
			&G->g_logspec, swc_get_stderr_fd(G), "SWI_NORMAL_EXIT: status=%d\n",
		sw_exitval(G, target_loop_count, target_success_count));

	swutil_close(swutil);
	swc_shutdown_logger(G,SIGTERM);
	return(sw_exitval(G, target_loop_count, target_success_count));	
}
