/*  swproglib.c -- general purpose routines common among the sw<utiltities>

 Copyright (C) 2006, 2007 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "strob.h"
#include "cplob.h"
#include "vplob.h"
#include "swlib.h"
#include "usgetopt.h"
#include "ugetopt_help.h"
#include "swcommon0.h"
#include "swcommon.h"
#include "swparse.h"
#include "swfork.h"
#include "swgp.h"
#include "etar.h"
#include "strar.h"
#include "swssh.h"
#include "progressmeter.h"
#include "swevents.h"
#include "to_oct.h"
#include "tarhdr.h"
#include "swinstall.h"
#include "swheader.h"
#include "swheaderline.h"
#include "swicat.h"
#include "swicat_e.h"
#include "strar.h"
#include "swi.h"
#include "atomicio.h"
#include "swutilname.h"
#include "swproglib.h"
#include "shlib.h"
#include "swgpg.h"
#include "ls_list.h"

static SCAR * g_script_array[SCAR_ARRAY_LEN+1];

static
void
abort_script(SWICOL * swicol, GB * G, int fd)
{
	swicol_set_master_alarm(swicol);
	swpl_send_abort(swicol, fd, G->g_swi_event_fd, "");
}
		
static
int
determine_ls_list_flags(int attr, struct new_cpio_header * file_hdr)
{

	FILE_DIGS * digs;
	int ls_verbose;

	ls_verbose = 0;

	if (attr & TARU_UM_UID && attr & TARU_UM_OWNER) {
		ls_verbose |= LS_LIST_VERBOSE_WITH_SYSTEM_IDS;
		ls_verbose |= LS_LIST_VERBOSE_WITH_SYSTEM_NAMES;
	} else if (attr & TARU_UM_UID) {
		ls_verbose |= LS_LIST_VERBOSE_WITH_SYSTEM_IDS;
		ls_verbose &= ~LS_LIST_VERBOSE_WITH_SYSTEM_NAMES;
	} else if (attr & TARU_UM_OWNER) {
		ls_verbose &= ~LS_LIST_VERBOSE_WITH_SYSTEM_IDS;
		ls_verbose |= LS_LIST_VERBOSE_WITH_SYSTEM_NAMES;
	}

	digs = file_hdr->digsM;
	if (digs) {
		if (digs->do_md5)
			ls_verbose |= LS_LIST_VERBOSE_WITH_MD5;
		if (digs->do_sha1)
			ls_verbose |= LS_LIST_VERBOSE_WITH_SHA1;
		if (digs->do_sha512)
			ls_verbose |= LS_LIST_VERBOSE_WITH_SHA512;
	}
	return ls_verbose;
}

static
int
check_here_document_word(SWI_FILELIST * fl, char * stop_word)
{
	char * name;
	int ix;

	E_DEBUG("");
	ix = 0;
	while ((name=swi_fl_get_path(fl, ix)) != NULL) {
		if (strcmp(stop_word, name) == 0) {
			return 0;
		}
		ix++;
	}
	E_DEBUG("");
	return 1;
}

static
int
determine_here_document_stop_word(SWI_FILELIST * fl, STROB * buf)
{
	int ret;
	int n;
	n = 0;
	E_DEBUG("");
	do {
		strob_set_length(buf, L_tmpnam+1);		
		tmpnam(strob_str(buf));
		ret = check_here_document_word(fl, strob_str(buf));
		if (ret != 0) {
			E_DEBUG("");
			return 0;
		}	
		n++;
	} while (ret == 0 && n < 10);
	E_DEBUG("");
	return 1; /* error */
}

int
swpl_retrieve_files(GB * G, SWI * swi, SWICOL * swicol, SWICAT_E * e, SWI_FILELIST * file_list,
	int ofd, int ifd, int archive_fd, char * pax_write_command_key, int ls_fd, int ls_verbose, FILE_DIGS * digs)
{
	TARU * taru;
	STROB * scriptbuf;
	int ret;

	scriptbuf = strob_open(300);

	strob_sprintf(scriptbuf, STROB_DO_APPEND, "rm_retval=1\n");
	strob_sprintf(scriptbuf, STROB_DO_APPEND, "sw_retval=1\n");

	/* Every task script read stdin even if it doesn't need to */	
	/* Add the requisite dd bs=512 count=1 of=/dev/null */

	E_DEBUG("");
	strob_sprintf(scriptbuf, STROB_DO_APPEND,
		"dd bs=512 count=1 of=/dev/null 2>/dev/null\n"
		"sw_retval=$?\n"
		);

	E_DEBUG("");

	swpl_make_verify_command_script_fragment(G, scriptbuf,
			file_list, pax_write_command_key, ls_fd < 0);

	E_DEBUG("");
	ret = swicol_rpsh_task_send_script2(
		swicol,
		ofd,
		512,
		".",
		strob_str(scriptbuf),
		SWBIS_TS_retrieve_files_archive);

	if (ret != 0) {
		/* Set master_alarm ?? */
		swicol_set_master_alarm(swicol);
		return -1;
	}

	/* Send the gratuitous data block because 'count=0' is busted for
	   some 'dd' programs */

	ret = etar_write_trailer_blocks(NULL, ofd, 1);
	if (ret <= 0) {
		return -1;
	}

	/* Now we have to read the archive */

	E_DEBUG("");
	taru = taru_create();
	E_DEBUG("");

	/* here, the archive is read.  This is a tar archive of the
	   package files as lifted from the file system */

	ret = taru_process_copy_out(taru, ifd, archive_fd,
			NULL, NULL, arf_ustar, ls_fd, ls_verbose, (intmax_t*)NULL, digs);

	/*
	ret = swlib_pump_amount(archive_fd, ifd, 4608);
	fprintf(stderr, "JLJL [%d]\n", ret);
	*/

	taru_delete(taru);
	if (ret < 0) {
		swicol_set_master_alarm(swicol);
	}

	E_DEBUG("");
	ret = swicol_rpsh_task_expect(swicol, G->g_swi_event_fd, SWICOL_TL_4);

	E_DEBUG("");
	strob_close(scriptbuf);
	E_DEBUG("");
	return ret;
}

static
int
construct_script_cases(GB * G, STROB * buf, SWI * swi, 
		SWI_CONTROL_SCRIPT * script, 
		char * tagspec,
		char * script_tag,
		int error_event_value,
		int warning_event_value)
{
	int ret;
	struct extendedOptions * opta;
	int script_retcode;
	int swi_retcode;
	STROB * tmp2;
	STROB * tmp3;

	tmp2= strob_open(48);
	tmp3 = strob_open(48);
	opta = swi->optaM;
	SWLIB_ASSERT(script != NULL);

	/*
	 * write main script fragment
	 */

	ret = swpl_write_control_script_code_fragment(G, swi, script, tagspec, buf);
	SWLIB_ASSERT(ret == 0);

	/*
	 * write some shell code that monitors
	 * return status of the script
	 */

	if (swextopt_is_option_true(SW_E_enforce_scripts, opta)) {
		script_retcode = SW_ERROR;
		swi_retcode = 1;
	} else {
		script_retcode = SW_WARNING;
		swi_retcode = 0;
	}

	strob_sprintf(tmp2, 0, "%s: status=$sw_retval", script_tag);
	strob_sprintf(tmp3, 0, "%s: status=$script_retval", script_tag);

	strob_sprintf(buf, STROB_DO_APPEND,
		"	# Start of construct_script_cases\n"
		"	case \"$sw_retval\" in\n"
		"		" SWBIS_STATUS_COMMAND_NOT_FOUND ")\n"
		"			# Special return code of control.sh which means\n"
		"			# no script for the specified control_script tag\n"
		"			sw_retval=0\n"
		"			;;\n"
					
		"		%d)\n"
		"			;;\n"
					/* Do nothing */
		"		%d)\n"
		"			%s\n"
		"			sw_retval=0\n"
		"			;;\n"
	
		"		%d)\n"
		"			script_retval=%d\n"
		"			%s\n"
		"			sw_retval=0 # %d\n"
		"			;;\n"
		"		*)\n"
		"			sw_retval=1\n"
		"			;;\n"
		"	esac\n"
		"	# End of construct_script_cases\n" ,
	SW_SUCCESS,
	SW_WARNING,
	TEVENT(2, (swi->verboseM), warning_event_value, strob_str(tmp2)),
	SW_ERROR,
	script_retcode,
	TEVENT(2, (swi->verboseM), error_event_value, strob_str(tmp3)),
	swi_retcode
	);	
	strob_close(tmp2);
	strob_close(tmp3);
	return 0;
}

int
swpl_send_null_task(SWICOL * swicol, int ofd, int event_fd, char * msgtag, int retcode)
{
	int ret;
	STROB * tmp;
	tmp = strob_open(10);
	strob_sprintf(tmp, 0, "sw_retval=%d", retcode);
	ret = swpl_send_null_task2(swicol, ofd, event_fd, msgtag, strob_str(tmp));
	strob_close(tmp);
	return ret;
}

int
swpl_send_null_task2(SWICOL * swicol, int ofd, int event_fd, char * msgtag, char * status_expression)
{
	int ret = 0;
	STROB * tmp;
	STROB * namebuf;
	STROB * ts_msg;

	ts_msg = strob_open(10);
	tmp = strob_open(10);
	namebuf = strob_open(10);

	strob_strcpy(namebuf, ".");

	strob_strcat(ts_msg, msgtag);
	/* swicol_set_task_idstring(swicol, strob_str(ts_msg)); */
	E_DEBUG("");
	/*
	 * Here is the minimal task scriptlet that throws an error
	 */
	strob_sprintf(tmp, 0,
		"# sw_retval=%%d\n"
		"%s\n"
		"sleep 0\n"
		"dd bs=512 count=1 of=/dev/null 2>/dev/null\n"
		"case $sw_retval in 0) exit 0 ;; *) exit $sw_retval;; esac\n"
		, status_expression);
	E_DEBUG("");

	/*
	 * Send the script into stdin of the POSIX shell
	 * invoked with the '-s' option.
	 */
	E_DEBUG("");
	ret = swicol_rpsh_task_send_script2(
		swicol,
		ofd, 
		512,  
		strob_str(namebuf),
		strob_str(tmp), strob_str(ts_msg));
	E_DEBUG2("ret=%d", ret);

	if (ret == 0) {
		/*
		 * Now send the stdin payload which must be
		 * exactly stdin_file_size bytes long.
		 */
		
		/* 
		 * Send the payload
		 */
		ret = etar_write_trailer_blocks(NULL, ofd, 1);
		if (ret < 0) {
			fprintf(stderr, "%s: swpl_get_utsname_attributes(): etar_write_trailer_blocks(): ret=%d\n",
				swlib_utilname_get(), ret);
		}

		/*
		 * Reap the events from the event pipe.
		 */
		E_DEBUG2("ret=%d",ret);
		if (ret > 0)
			ret = swicol_rpsh_task_expect(swicol,
				event_fd, SWICOL_TL_4);

		E_DEBUG2("ret=%d",ret);
		/* swicol_show_events_to_fd(swicol, STDERR_FILENO, -1); */	
	}
	strob_close(ts_msg);
	strob_close(tmp);
	strob_close(namebuf);
	swicol_clear_task_idstring(swicol);
	E_DEBUG2("ret=%d",ret);
	return ret;
}

void
swpl_init_header_root(ETAR * etar)
{
	etar_set_typeflag(etar, REGTYPE);
	etar_set_mode_ul(etar, (unsigned int)(0640));
	etar_set_uid(etar, 0);
	etar_set_gid(etar, 0);
	etar_set_uname(etar, "root");
	etar_set_gname(etar, "root");
}

void
swpl_scary_init_script_array(void)
{
	int i;
	for (i=0; i<SCAR_ARRAY_LEN; i++) {
		g_script_array[i] = (SCAR*)NULL;
	}
}

SCAR **
swpl_get_script_array(void)
{
	return g_script_array;
}

SCAR *
swpl_scary_create(char * tag, char * tagspec, SWI_CONTROL_SCRIPT * script)
{
	SCAR * scary;
	scary = (SCAR *)malloc(sizeof(SCAR));
	if (!scary) return scary;
	scary->tagM = strdup(tag);		/* e.g. postinstall or preinstall */
	scary->tagspecM = strdup(tagspec);      /* <product_tag> or <product_tag>.<fileset_tag> */
	scary->scriptM = script;                /* pointer to the script object */
	return scary;
}

void
swpl_scary_delete(SCAR * scary)
{
	free(scary->tagM);
	free(scary->tagspecM);
	free(scary);
}

SCAR *
swpl_scary_add(SCAR ** array, SCAR * script)
{
	int i;
	for (i=0; i<SCAR_ARRAY_LEN; i++) {
		if (array[i] == (SCAR*)NULL) {
			array[i] = script;
			return script;
		}
	}
	return NULL;
}

void
swpl_scary_show_array(SCAR ** array)
{
	int i;
	STROB * tmp;
	tmp = strob_open(18);
	for (i=0; i<SCAR_ARRAY_LEN; i++) {
		if (array[i] == (SCAR*)NULL) {
			break;
		} else {
			swlib_writef(STDERR_FILENO, tmp, "%d tag=[%s] tagspec=[%s] script=[%p]\n",
				i, array[i]->tagM,
				array[i]->tagspecM,
				array[i]->scriptM);
		}
	}
	strob_close(tmp);
	return;
}

SWI_CONTROL_SCRIPT *
swpl_scary_find_script(SCAR ** array, char * tag, char * tagspec)
{
	int i;
	STROB * tmp;
	SWI_CONTROL_SCRIPT * retval = NULL;

	tmp = strob_open(18);
	for (i=0; i<SCAR_ARRAY_LEN; i++) {
		if (array[i] == (SCAR*)NULL) {
			break;
		} else {
			if (
				strcmp(array[i]->tagM, tag) == 0 &&
				strcmp(array[i]->tagspecM, tagspec) == 0 &&
				1
			) {
				retval = array[i]->scriptM;
				break;
			}
		}
	}
	strob_close(tmp);
	return retval;
}

void
swpl_audit_execution_scripts(GB * G, SWI * swi, SCAR ** scary_scripts)
{
	SWI_PRODUCT * product;
	SWI_XFILE * fileset;
	SWI_CONTROL_SCRIPT * product_xxinstall_script;
	SWI_CONTROL_SCRIPT * fileset_xxinstall_script;
	STROB * tagspec;
	SCAR * scary_script;
	int fileset_index;
	char ** ts;
	char * tag;
	char * execution_scripts[] = {
			SW_A_checkinstall,
			SW_A_postinstall,
			SW_A_preinstall,
			SW_A_configure,
			SW_A_checkremove,
			SW_A_preremove,
			SW_A_postremove,
			SW_A_unconfigure,
			SW_A_unpostinstall,
			SW_A_unpreinstall,
			SW_A_request,
			(char*)(NULL) };

	/* SWBIS_DEBUG_PRINT(); */
	tagspec = strob_open(32);
	swpl_scary_init_script_array();
	
	/*
	 * FIXME, allow more than one product
	 */

	product = swi_package_get_product(swi->swi_pkgM, 0 /* The first product */);
	ts = execution_scripts;
	for (;tag=(*ts),*ts != (char*)NULL; ts++) {	
		product_xxinstall_script = swi_product_get_control_script_by_tag(product, tag);
		if (product_xxinstall_script) {
			scary_script = swpl_scary_create(tag, product->baseM.tagM, product_xxinstall_script);
			swpl_scary_add(scary_scripts, scary_script);
		}
	}

	/*
	 * Loop over the filesets
	 */
	/* SWBIS_DEBUG_PRINT(); */

	fileset_index = 0;
	fileset = swi_product_get_fileset(product, fileset_index++);
	while(fileset) {	
		strob_sprintf(tagspec, STROB_NO_APPEND, "%s.%s", product->baseM.tagM, fileset->baseM.tagM);
		ts = execution_scripts;
		for (;tag=(*ts),*ts != (char*)NULL; ts++) {	
			fileset_xxinstall_script = swi_xfile_get_control_script_by_tag(fileset, tag);
			if (fileset_xxinstall_script) {
				scary_script = swpl_scary_create(tag, strob_str(tagspec), fileset_xxinstall_script);
				swpl_scary_add(scary_scripts, scary_script);
			}
		}
		fileset = swi_product_get_fileset(product, fileset_index++);
	}
	strob_close(tagspec);
}

int
swpl_write_control_script_code_fragment(GB * G, SWI * swi, SWI_CONTROL_SCRIPT * script, char * swspec_tags, STROB * buf)
{
	STROB * tmp;
	
	tmp = strob_open(100);
	strob_sprintf(tmp, STROB_DO_APPEND,
		"%s %s",
		swspec_tags,
		script->baseM.tagM);

	strob_sprintf(buf, STROB_DO_APPEND,
		"	# Start of swpl_write_control_script_code_fragment\n"
		"	cd \"%s\" || exit 44\n"
		"	cd \"%s\" || exit 45\n"
		"	script_control_val=$?\n"
		"	case \"$swbis_ignore_scripts\" in yes) script_control_val=_ignore_;; esac\n"
		"	case $script_control_val in  # Case_swproglib.c_002\n"
		"		0)\n"
		"			%s\n"
		"			sh control.sh \"%s\" \"%s\"\n"
		"			sw_retval=$?\n"
		"			%s\n"
		"			;;\n"
		"		_ignore_)\n"
		"			sw_retval=0  # swbis_ignore_scripts=yes\n"
		"			;;\n"
		"		*)\n"
		"			sw_retval=" SWBIS_STATUS_COMMAND_NOT_FOUND "\n"
		"			;;\n"
		"	esac  # Case_swproglib.c_002\n"
		"	# End of swpl_write_control_script_code_fragment\n",
		swi->swi_pkgM->target_pathM,
		swi->swi_pkgM->catalog_entryM,
		TEVENT(2, (swi->verboseM), SW_CONTROL_SCRIPT_BEGINS, strob_str(tmp)),
		swspec_tags,
		script->baseM.tagM,
		TEVENT(2, (swi->verboseM), SW_CONTROL_SCRIPT_ENDS, "status=$sw_retval")
		);
	
	strob_close(tmp);
	return 0;
}

int
swpl_write_case_block(SWI * swi, STROB * buf, char * tag)
{
	STROB * tmp;
	tmp = strob_open(100);

	swicat_write_script_cases(swi, tmp, tag);

	strob_sprintf(buf, STROB_DO_APPEND,
		"# generated by swpl_write_case_block\n"
		"	%s)\n"
		"%s"
		"		;;\n",
		tag, strob_str(tmp));

	strob_close(tmp);
	return 0;
}

uintmax_t
swpl_get_whole_block_size(uintmax_t size)
{
	uintmax_t ret;
	if (size == 0) return 0;
	ret = ((size / TARRECORDSIZE) + 1) * TARRECORDSIZE;
	return ret;
}

int
swpl_write_session_options_filename(STROB * name, SWI * swi)
{
	strob_strcpy(name, swi->swi_pkgM->catalog_entryM);
	swlib_unix_dircat(name, SW_A_session_options);
	return 0;
}

int 
swpl_write_session_options_file(STROB * buf, SWI * swi)
{
	strob_strcpy(buf, "");
	swextopt_writeExtendedOptions_strob(buf, (struct extendedOptions *)(swi->optaM), swi->swc_idM, 1);
	return strob_strlen(buf);
}

int
swpl_write_single_file_tar_archive(SWI * swi, int ofd, char * name, char * data)
{
	ETAR * etar;
	int ret;
	int retval = 0;

	etar = etar_open(swi->xformatM->taruM);
	etar_init_hdr(etar);
	swpl_init_header_root(etar);
	etar_set_size(etar, strlen(data));
	if (etar_set_pathname(etar, name)) SWLIB_FATAL("name too long");
	etar_set_chksum(etar);

	/*
	 * Emit the header 
	 */
	ret = etar_emit_header(etar, ofd);
	if (ret < 0) {
		fprintf(stderr, "%s: swpl_write_single_file_tar_archive(): etar_emit_header(): ret=%d\n",
			swlib_utilname_get(), ret);
		return ret;
	}
	retval += ret;

	/*
	 * Emit the file data
	 */
	ret = etar_emit_data_from_buffer(etar, ofd, data, strlen(data));
	if (ret < 0) {
		fprintf(stderr, "%s: swpl_write_single_file_tar_archive(): etar_emit_data_from_buffer(): ret=%d\n",
			swlib_utilname_get(), ret);
		return ret;
	}
	retval += ret;

	/*
	 * Emit the trailer blocks
	 */	
	ret = etar_write_trailer_blocks(NULL, ofd, 2);
	if (ret < 0) {
		fprintf(stderr, "%s: swpl_write_single_file_tar_archive(): etar_write_trailer_blocks(): ret=%d\n",
			swlib_utilname_get(), ret);
		return ret;
	}
	retval += ret;

	etar_close(etar);
	return retval;
}

int
swpl_load_single_file_tar_archive (GB * G,
	SWI * swi,
	int ofd, 
	char * catalog_path,
	char * pax_read_command,
	int alt_catalog_root,
	int event_fd,
	char * id_str,
	char * name,
	char * data
	)
{
	int ret;
	unsigned long int stdin_file_size;
	STROB * tmp;
	STROB * namebuf;

	tmp = strob_open(10);
	namebuf = strob_open(10);

	/*
	 * Compute the data size that will be sent to the stdin of the 'sh -s'
	 * process on the target host.
	 */

	/* (*f_archive_data)(tmp, swi); */

	stdin_file_size = \
		swpl_get_whole_block_size((unsigned long int)strlen(data)) +  /* data plue tar block padding */
		TARRECORDSIZE + /* ustar header */
		TARRECORDSIZE + /* trailer block */
		TARRECORDSIZE + /* trailer block */
		0;
	/*
	 * Here is the task scriptlet to load the installed file.
	 */

	strob_sprintf(tmp, 0,
		"dd 2>/dev/null | (%s; sw_retval=$?; dd of=/dev/null 2>/dev/null; exit $sw_retval) \n"
		"sw_retval=$?\n"	/* This line is required */
		"# dd of=/dev/null 2>/dev/null\n"
		,
		pax_read_command
		);

	/*
	 * Now send the task script to the target host 'sh -s'
	 */
	/* swicol_set_task_idstring(swi->swicolM, id_str); */
	ret = swicol_rpsh_task_send_script2(
		swi->swicolM,
		ofd, 			/* file descriptor */
		stdin_file_size,	/* script stdin file length */
		".",   			/* i.e. stay in the target path */
		strob_str(tmp),		/* The actual task script */
		id_str			/* Id string */
		);
	
	if (ret == 0) {
		/*
		 * Now send the data on the same stdin.
		 * In this case it is a tar archive with one file member
		 */

		/* ret = (*f_write_tar_archive)(swi, ofd, name, data); */
		ret = swpl_write_single_file_tar_archive(swi, ofd, name, data);
		if (ret <= 0) {
			SWBIS_ERROR_IMPL();
			return -1;
		}

		/*
		 * Assert what must be true.
		 */

		if (ret != (int)stdin_file_size) {
			fprintf(stderr, "ret=%d  stdin_file_size=%lu\n", ret, stdin_file_size);
			SWBIS_ERROR_IMPL();
			SWI_internal_error();
			return -1;
		}
	
		/*
		 * Reap the events from the event pipe.
		 */
		ret = swicol_rpsh_task_expect(swi->swicolM,
					event_fd,
				SWICOL_TL_4 /*time limit*/);
		if (swi->debug_eventsM)
			swicol_show_events_to_fd(swi->swicolM, STDERR_FILENO, -1);

		if (ret < 0) {
			SWBIS_ERROR_IMPL();
			SWI_internal_error();
			return -1;
		}
	}
	/*
	 * close and return
	 */
	strob_close(tmp);
	strob_close(namebuf);
	return ret;
}

int
swpl_write_tar_installed_software_index_file (GB * G, SWI * swi, int ofd,
	char * catalog_path,
	char * pax_read_command,
	int alt_catalog_root,
	int event_fd,
	char * id_str
	)
{
	int ret = 0;
	STROB * name;
	STROB * data;

	name = strob_open(100);
	data = strob_open(100);

	swicat_isf_installed_software(data, swi);

	/*
	 * catalog_entryM = [var/lib/swbis/catalog/swbis/swbis/0.000/0]
	 */

	strob_strcpy(name, swi->swi_pkgM->catalog_entryM);
	swlib_unix_dircat(name, SW_A__INSTALLED);

	ret = swpl_load_single_file_tar_archive(G,
		swi,
		ofd, 
		catalog_path,
		pax_read_command,
		alt_catalog_root,
		event_fd,
		id_str,
		strob_str(name),
		strob_str(data));

	strob_close(name);
	strob_close(data);
	return ret;
}


int
swpl_construct_configure_script(GB * G, STROB * buf, SWI * swi, int do_configure)
{
	int ret;
	strob_sprintf(buf, STROB_DO_APPEND,
		"	# Start of code generated by swpl_construct_configure_script \n"
		"		ssv_do_configure=%d\n"
		"		case \"$ssv_do_configure\" in\n"
		"		1)\n",
			do_configure);	

	ret = swpl_construct_script(G,  buf, swi, SW_A_configure);

	strob_sprintf(buf, STROB_DO_APPEND,
		"		;;\n"
		"		esac\n"
		"	# End of code generated by swpl_construct_configure_script \n"
	);
	return 0;
}

int
swpl_construct_script(GB * G, STROB * buf, SWI * swi, char * script_tag)
{
	STROB * tmp;
	STROB * toap;
	SWI_PRODUCT * product;
	SWI_XFILE * fileset;
	SWI_CONTROL_SCRIPT * product_xxinstall_script;
	SWI_CONTROL_SCRIPT * fileset_xxinstall_script;
	char * target_path;
	struct extendedOptions * opta;
	int script_retcode;
	int swi_retcode;
	int event_error_value;
	int event_warning_value;

	opta = swi->optaM;
	tmp = strob_open(20);
	toap = strob_open(20);

	/*
	 * script_tag is either preinstall, postinstall, or configure
	 */

	if (
		strcmp(script_tag, SW_A_postinstall) == 0 ||
		strcmp(script_tag, SW_A_postremove) == 0 ||
		0
	) {
		event_error_value = SW_POST_SCRIPT_ERROR;
		event_warning_value = SW_POST_SCRIPT_WARNING;
	} else if (
		strcmp(script_tag, SW_A_preinstall) == 0 ||
		strcmp(script_tag, SW_A_preremove) == 0 ||
		0
	) {
		event_error_value = SW_PRE_SCRIPT_ERROR;
		event_warning_value = SW_PRE_SCRIPT_WARNING;
	} else if (
		strcmp(script_tag, SW_A_configure) == 0 ||
		strcmp(script_tag, SW_A_unconfigure) == 0 ||
		0
	) {
		event_error_value = SW_CONFIGURE_ERROR;
		event_warning_value = SW_CONFIGURE_WARNING;
	} else {
		event_error_value = SW_CONFIGURE_ERROR;
		event_warning_value = SW_CONFIGURE_ERROR;
		SWLIB_INTERNAL("");
	}

	product = swi_package_get_product(swi->swi_pkgM, 0 /* The first product */);
	product_xxinstall_script = swi_product_get_control_script_by_tag(product, script_tag);

	fileset = swi_product_get_fileset(product, 0 /* the first one */);
	fileset_xxinstall_script = swi_xfile_get_control_script_by_tag(fileset, script_tag);

	if (
		!product_xxinstall_script &&
		!fileset_xxinstall_script
	) {
		/*
		 * no script
		 */
		strob_sprintf(toap, STROB_DO_APPEND, "sw_retval=0\n");
		return 0;
	}

	/*
	 * FIXME -- need to set the state to "transient"
	 */

	/*
	 * write code to run the product {pre|post}install script
	 */
	if (swi->swi_pkgM->target_pathM) {
		target_path = swi->swi_pkgM->target_pathM;
	} else {
		target_path = ".";
	}
	
	if (product_xxinstall_script) {
		/*
		 * construct the product script's execution
		 */
		strob_sprintf(toap, STROB_DO_APPEND, 
			"# Start of code generated by swproglib.c:swpl_construct_script\n",
			"cd \"%s\"\n",
			target_path);
		construct_script_cases(G, toap, swi,
			product_xxinstall_script,
			product->baseM.tagM, script_tag,
			event_error_value,
			event_warning_value);
	}
	
	if (swextopt_is_option_true(SW_E_enforce_scripts, opta)) {
		script_retcode = SW_ERROR;
		swi_retcode = 1;
	} else {
		script_retcode = SW_WARNING;
		swi_retcode = 0;
	}

	if (fileset_xxinstall_script) {
		strob_sprintf(toap, STROB_DO_APPEND,
		"	case \"$sw_retval\" in  # Case_construct_script_003\n"
		"	0)\n"
		);
		strob_sprintf(tmp, 0, "%s.%s", product->baseM.tagM, fileset->baseM.tagM);

		strob_sprintf(toap, STROB_DO_APPEND, "\tcd \"%s\"\n", target_path);
		construct_script_cases(G, toap, swi,
			fileset_xxinstall_script,
			strob_str(tmp), script_tag,
			event_error_value,
			event_warning_value);
		strob_sprintf(toap, STROB_DO_APPEND,
		"	;;\n"
		"	esac # Case_construct_script_003\n"
		);
	}

	strob_sprintf(toap, STROB_DO_APPEND,
		"# End of code generated by swproglib.c:swpl_construct_script\n");

	strob_sprintf(buf, STROB_DO_APPEND, "%s", strob_str(toap));

	strob_close(toap);
	strob_close(tmp);
	return 0;
}

int
swpl_construct_analysis_script(GB * G, STROB * buf, SWI * swi, SWI_CONTROL_SCRIPT ** p_script)
{
	int ret;
	SWI_PRODUCT * prod;
	SWI_CONTROL_SCRIPT * script;
	struct extendedOptions * opta;
	int checkscript_retcode;
	int swi_retcode;

	opta = swi->optaM;

	prod = swi_package_get_product(swi->swi_pkgM, 0 /* The first product */);
	if (swi_product_has_control_file(prod, SW_A_checkinstall)) {
	
		strob_sprintf(buf, STROB_DO_APPEND,
		"	cd \"%s\"\n",
		swi->swi_pkgM->target_pathM);
	
		/*
		 * Write the code for the checkinstall script
		 */
	
		script = swi_product_get_control_script_by_tag(prod, SW_A_checkinstall);
		SWLIB_ASSERT(script != NULL);
		ret = swpl_write_control_script_code_fragment(G, swi, script, prod->baseM.tagM, buf);
		SWLIB_ASSERT(ret == 0);

		/*
		 * write some shell code that monitors
		 * return status of the checkinstall script
		 */

		if (swextopt_is_option_true(SW_E_enforce_scripts, opta)) {
			checkscript_retcode = SW_ERROR;
			swi_retcode = 1;
		} else {
			checkscript_retcode = SW_WARNING;
			swi_retcode = 0;
		}

		*p_script = script;
		strob_sprintf(buf, STROB_DO_APPEND,
		"# Generated by swproglib.c:construct_analysis script\n"
		"case \"$sw_retval\" in\n"
		"	%d)\n"
		"		;;\n"
				/* Do nothing */
		"	%d)\n"
		"		%s\n"
		"		sw_retval=0\n"
		"		;;\n"

		"	%d)\n"
		"		script_retval=%d\n"
		"		%s\n"
		"		sw_retval=%d\n"
		"		;;\n"
		"esac\n"
		"dd of=/dev/null 2>/dev/null\n",
		SW_SUCCESS,
		SW_WARNING,
		TEVENT(2, (swi->verboseM), SW_CHECK_SCRIPT_WARNING, "status=$sw_retval"),
		SW_ERROR,
		checkscript_retcode,
		TEVENT(2, (swi->verboseM), SW_CHECK_SCRIPT_ERROR, "status=$script_retval"),
		swi_retcode
		);	
	} else {
		*p_script = NULL;
		strob_sprintf(buf, STROB_DO_APPEND, "sw_retval=0\n");
	}
	return 0;
}

int
swpl_compare_name(char * name1, char * name2, char * att, char * filename)
{
	int ret;
	if (strlen(name1) == 0 || strlen(name2) == 0) return 0;
	ret = swlib_dir_compare(name1, name2, 1);
	if (ret) {
		if (swlib_compare_8859(name1, name2) != 0) {
			fprintf(stderr, "%s: attribute mismatch: %s: att=%s: storage=[%s] INFO=[%s]\n",
				swlib_utilname_get(), filename, att,
				name1, name2);
		} else {
			ret = 0;
		}
	}
	return ret ? 1 : 0;
}

void
swpl_safe_check_pathname(char * s)
{
	if (swlib_is_sh_tainted_string(s)) {
		SWLIB_FATAL("tainted string");
	}
}

void
swpl_sanitize_pathname(char * s)
{
	swlib_squash_all_leading_slash(s);
	/* swpl_safe_check_pathname(s); */
}

char * 
swpl_get_attribute(SWHEADER * header, char * att, int * len)
{
	char * line;
	char * value;
        line = swheader_get_attribute(header, att);
	value = swheaderline_get_value(line, len);
	return value;
}

void
swpl_enforce_one_prod_one_fileset(SWI * swi)
{
	if (
		(swi->swi_pkgM->swi_coM[0]) == NULL || 
		(swi->swi_pkgM->swi_coM[0]->swi_coM[0]) == NULL
	) 
	{
		/*
		 * No product or no fileset
		 */
		fprintf(stderr, "%s: currently,  only one (1) products/filesets.\n",
			swlib_utilname_get());
		SWI_internal_fatal_error();
	}
	
	if (
		swi->swi_pkgM->swi_coM[1] ||
		swi->swi_pkgM->swi_coM[0]->swi_coM[1]
	) {
		/*
		 * More than one product or fileset
		 */
		fprintf(stderr, "%s: currently, multiple products/filesets not yet supported\n",
			swlib_utilname_get());
		SWI_internal_fatal_error();
	}	
	return;
}

int
swpl_does_have_prod_postinstall(SWI * swi)
{
	int ret;
	SWI_PRODUCT * prod;
	prod = swi_package_get_product(swi->swi_pkgM, 0 /* The first product */);
	ret = swi_product_has_control_file(prod, SW_A_postinstall);
	return ret;
}

int
swpl_get_fileset_file_count(SWHEADER * infoheader)
{
	int count = 0;
	char * next_line;
	swheader_reset(infoheader);
	next_line = swheader_get_next_object(infoheader, (int)UCHAR_MAX, (int)UCHAR_MAX);
	while (next_line){
		count++;
		next_line = swheader_get_next_object(infoheader, (int)UCHAR_MAX, (int)UCHAR_MAX);
	}
	return count++;
}

int
swpl_write_out_signature_member(SWI * swi, struct tar_header * ptar_hdr,
		struct new_cpio_header * file_hdr,
		int ofd, int startoffset,
		int endoffset, int signum,
		int *package_ret)
{
	int ifd;
	XFORMAT * xformat = swi->xformatM;
	int retval = 0;
	int ret;
	unsigned long filesize;
	unsigned long package_filesize;
	char * sig;
	int siglen;
	STROB * tmp = strob_open(16);
	ETAR * etar;
	
	ifd = xformat_get_ifd(xformat);
	etar = etar_open(swi->xformatM->taruM);
	etar_init_hdr(etar);

	/*
	 * Set the basic tar header fields
	 */
	swpl_init_header_root(etar);

	/*
	 * This reads the signature tar header from the package.
	 */
	ret = uxfio_read(ifd, (void*)(ptar_hdr), TARRECORDSIZE);
	if (ret != TARRECORDSIZE) {
		SWI_internal_fatal_error();
	}

	/*
	 * Determine the filesize of the signature file
	 * It damn well should be 512 or 1024
	 */
	taru_otoul(ptar_hdr->size, &filesize);
	package_filesize = filesize + TARRECORDSIZE;
	*package_ret = package_filesize;

	/*
	 * Do a sanity check on the size.
	 */
	if (filesize != 512 && filesize != 1024) {
		SWI_internal_fatal_error();
	}

	/*
	 * allocate some temporary memory for this
	 */
	sig = malloc((size_t)filesize);
	if (!sig) SWI_internal_fatal_error();

	/*
	 * This reads the sigfile archive member data
	 */	
	ret = uxfio_read(ifd, (void*)(sig), (size_t)filesize);
	if ((int)ret != (int)filesize) {
		SWI_internal_fatal_error();
	}

	sig[filesize-1] = '\0';
	siglen = strlen(sig);

	/*
	 * The package contains a sigfile padded with NULs.
	 * We will only install the ascii bytes which means the
	 * the sig file in the installed catalog will be shorter in
	 * length than in the package.
	 */

	etar_set_size(etar, siglen);
	etar_set_mode_ul(etar, (unsigned int)(0640));

	strob_strcpy(tmp, SWINSTALL_INCAT_NAME);
	swlib_unix_dircat(tmp, SWINSTALL_CATALOG_TAR);
	swlib_squash_all_leading_slash(strob_str(tmp));  /* FIXME */
	if (signum <= 1) {
		strob_sprintf(tmp, 1, ".sig");
	} else {
		strob_sprintf(tmp, 1, ".sig%d", signum);
	}

	if (etar_set_pathname(etar, strob_str(tmp))) SWLIB_FATAL("name too long");
	etar_set_chksum(etar);

	ret = uxfio_unix_safe_write(ofd, (void*)(etar_get_hdr(etar)), TARRECORDSIZE);
	if (ret != TARRECORDSIZE) {
		SWI_internal_fatal_error();
	}
	retval += ret;

	if (siglen <= 512)
		filesize = 512;
	else if (siglen <= 1024)
		filesize = 1024;
	else
		SWI_internal_fatal_error();
	
	ret = atomicio((ssize_t (*)(int, void *, size_t))write,
			ofd, (void*)(sig), filesize);
	if (ret != (int)filesize) {
		fprintf(stderr, "%s: swpl_write_out_signature_member(): ret=%d filesize=%d\n",
			swlib_utilname_get(), ret, (int)filesize);
		if (ret < 0)
			fprintf(stderr, "%s: swpl_write_out_signature_member(): %s\n",
				swlib_utilname_get(), strerror(errno));
		SWI_internal_fatal_error();
	}
	retval += ret;

	etar_close(etar);
	strob_close(tmp);
	free(sig);
	return retval;
}

int
swpl_write_out_all_signatures(SWI * swi, struct tar_header * ptar_hdr,
		struct new_cpio_header * file_hdr,
		int ofd, int startoffset,
		int endoffset, unsigned long filesize)
{
	int curpos;
	int ifd;
	int ret = 0;
	int sig_number;
	int current = 0;
	int package_current = 0;
	int package_ret = 0;
	int sig_block_length = endoffset - startoffset;
	XFORMAT * xformat = swi->xformatM;
	
	ifd = xformat_get_ifd(xformat);
	curpos = uxfio_lseek(ifd, 0L, SEEK_CUR);
	if (curpos < 0) {
		SWI_internal_fatal_error();
	}

	if (sig_block_length < 1024) {
		/*
		* FIXME: tar format specific.
		* Sanity check.
		*/
		return -1;
	}

	/*
	 * Seek to the beginning of the signature archive members.
	 */

	if (uxfio_lseek(ifd, startoffset, SEEK_SET) < 0) {
		SWI_internal_fatal_error();
	}

	/*
	 * all the sigfiles are the same length, filesize.
	 * sig_number is the number of signatures present, this
	 * needs to be determined because it is decremented to
	 * '1'.  This means the last signature in the package
	 * will have the name 'catalog.tar.sig', the next to last
	 * will have the name 'catalog.tar.sig2', and so on.
	 */

	sig_number = sig_block_length / (int)(filesize + TARRECORDSIZE);

	/* fprintf(stderr, "eraseme filesize=%d sig_number=%d\n", (int)filesize, sig_number); */

	/*
	 * do a sanity check
	 */

	if (sig_block_length % (int)(filesize + TARRECORDSIZE)) {
		SWI_internal_fatal_error();
	}

	/*
	 * Loop to write out all the signatures.
	 */

	while (package_current < sig_block_length) {
		if (sig_number <= 0) {
			/* Sanity check */
			SWI_internal_fatal_error();
		}
		ret = swpl_write_out_signature_member(swi, ptar_hdr,
				file_hdr, ofd,
				startoffset, endoffset,
				sig_number--, &package_ret);
		if (ret < 0) {
			return ret;
		}
		package_current += package_ret;
		current += ret;
	}

	/*
	 * Now restore the old offset.
	 */
	if (uxfio_lseek(ifd, curpos, SEEK_SET) < 0) {
		SWI_internal_fatal_error();
	}
	return current;
}

int
swpl_write_catalog_data(SWI * swi, int ofd, int sig_block_start, int sig_block_end)
{
	int curpos;
	int ifd;
	int iend;
	int amount;
	XFORMAT * xformat = swi->xformatM;
	SWI_PACKAGE * package = swi->swi_pkgM;
	int retval;
	int ret;

	ifd = xformat_get_ifd(xformat);
	curpos = uxfio_lseek(ifd, 0L, SEEK_CUR);
	if (curpos < 0) {
		SWI_internal_fatal_error();
		return -1;
	}

	if (uxfio_lseek(ifd, package->catalog_start_offsetM, SEEK_SET) < 0) {
		SWI_internal_fatal_error();
		return -1;
	}

	if (sig_block_start > 0) {
		iend = sig_block_start;
	} else {
		iend = package->catalog_end_offsetM;
	}
	amount = iend - package->catalog_start_offsetM;

	if (swlib_pump_amount(ofd, ifd, amount) != amount) {
		SWI_internal_fatal_error();
		return -1;
	}
	retval = amount;
	if (sig_block_start > 0) {
		/* 
		 * skip the signatures and write the remaining.
		 */
		amount = sig_block_end - sig_block_start;
		if (uxfio_lseek(ifd, amount, SEEK_CUR) < 0) {
			SWBIS_ERROR_IMPL();
			SWI_internal_fatal_error();
		}
		amount = package->catalog_end_offsetM - sig_block_end;
		if (swlib_pump_amount(ofd, ifd, amount) != amount) {
			SWBIS_ERROR_IMPL();
			SWI_internal_fatal_error();
			return -1;
		}
		retval += amount;
	} else {
		/*
		 * done
		 */
		;
	}
	if (uxfio_lseek(ifd, curpos, SEEK_SET) < 0) {
		SWBIS_ERROR_IMPL();
		SWI_internal_fatal_error();
	}

	/*
	 * Now write 2 NUL trailer blocks
	 */
	ret = etar_write_trailer_blocks(NULL, ofd, 2);
	if (ret < 0) {
		fprintf(stderr, "%s: swpl_write_catalog_data(): etar_write_trailer_blocks(): ret=%d\n",
			swlib_utilname_get(), ret);
		return ret;
	}
	retval += ret;
	return retval;
} 

int
swpl_send_abort(SWICOL * swicol, int ofd, int event_fd, char * msgtag)
{
	int ret = 0;
	ret = swpl_send_null_task(swicol, ofd, event_fd, msgtag, SW_ERROR);
	return ret;
}

int
swpl_report_status(SWICOL * swicol, int ofd, int event_fd)
{
	int ret = 0;
	ret = swpl_send_null_task2(swicol, ofd, event_fd, SWBIS_TS_report_status, "sw_retval=$rp_status");
	return ret;
}

int
swpl_send_success(SWICOL * swicol, int ofd, int event_fd, char * msgtag)
{
	int ret = 0;
	ret = swpl_send_null_task(swicol, ofd, event_fd, msgtag, SW_SUCCESS);
	return ret;
}

int
swpl_send_nothing_and_wait(SWICOL * swicol, int ofd, int event_fd, char * msgtag, int tl, int retcode)
{
	int ret = 0;
	STROB * tmp;
	STROB * namebuf;

	E_DEBUG("");
	tmp = strob_open(10);
	namebuf = strob_open(10);

	strob_strcpy(namebuf, ".");

	/*
	 * Here is the minimal task scriptlet
	 */
	strob_sprintf(tmp, 0,
		"sw_retval=%d\n"
		"dd of=/dev/null 2>/dev/null\n",
		retcode
		);

	/*
	 * Send the script into stdin of the POSIX shell
	 * invoked with the '-s' option.
	 */
	E_DEBUG("");
	ret = swicol_rpsh_task_send_script2(
		swicol,
		ofd, 
		512,  
		strob_str(namebuf),
		strob_str(tmp), msgtag
		);

	E_DEBUG("");
	if (ret == 0) {
		/*
		 * Now send the stdin payload which must be
		 * exactly stdin_file_size bytes long.
		 */
	
		/* 
		 * Send the payload
		 */
		E_DEBUG("");
		ret = etar_write_trailer_blocks(NULL, ofd, 1);
		if (ret < 0) {
			fprintf(stderr, "%s: send_nothing_and_wait(): etar_write_trailer_blocks(): ret=%d\n",
				swlib_utilname_get(), ret);
		}
		/*
		 * Reap the events from the event pipe.
		 */
		E_DEBUG("");
		ret = swicol_rpsh_task_expect(swicol,
				event_fd,
				tl /*time limit*/);
		if (ret < 0) {
			SWLIB_INTERNAL("");
		}
	}
	strob_close(tmp);
	strob_close(namebuf);
	E_DEBUG("");
	return ret;
}

int
swpl_send_signature_files(SWI * swi, int ofd,
	char * catalog_path, char * pax_read_command,
	int alt_catalog_root, int event_fd,
	struct tar_header * ptar_hdr,
	int sig_block_start, int sig_block_end,
	unsigned long filesize)
{
	int ret = 0;
	int padamount;
	int stdin_file_size;
	STROB * tmp;
	STROB * namebuf;
	int sig_block_length;
	struct new_cpio_header * file_hdr;
	struct tar_header * tar_hdr;

	tar_hdr = (struct tar_header *)malloc(TARRECORDSIZE+1);
	tmp = strob_open(10);
	namebuf = strob_open(10);
	file_hdr = taru_make_header();

	memcpy((void*)tar_hdr, (void*)ptar_hdr, TARRECORDSIZE);
	sig_block_length = sig_block_end - sig_block_start;

	stdin_file_size = sig_block_length +
			TARRECORDSIZE +  /* Trailer block */
			TARRECORDSIZE;   /* Trailer block */

	/*
	 * FIXME    ''catalog_path'' is swi->catalog_entryM 
	 */

	strob_strcpy(namebuf, catalog_path);
	if (alt_catalog_root == 0) {
		swlib_squash_all_leading_slash(strob_str(namebuf));
	} else {
		/*
		 * FIXME alternate catalog root not supported
		 */
		swlib_squash_all_leading_slash(strob_str(namebuf));
	}
	
	/*
	 * Here is the task scriptlet.
	 */
	strob_sprintf(tmp, 0,
		"dd 2>/dev/null | %s\n"
		"sw_retval=$?\n"
		"dd of=/dev/null 2>/dev/null\n"
		,
		pax_read_command
		);

	/*
	 * Send the script into stdin of the POSIX shell
	 * invoked with the '-s' option.
	 */
	/* SWBIS_TS_Load_signatures */
	/* swicol_set_task_idstring(swi->swicolM, SWBIS_TS_Load_signatures); */
	ret = swicol_rpsh_task_send_script2(
		swi->swicolM,
		ofd, 
		stdin_file_size,
		strob_str(namebuf),
		strob_str(tmp), SWBIS_TS_Load_signatures
		);

	if (ret == 0) {
		/*
		 * Now send the stdin payload which must be
		 * exactly stdin_file_size bytes long.
		 */
	
		ret = swpl_write_out_all_signatures(swi, tar_hdr, file_hdr,
			ofd, sig_block_start, sig_block_end, filesize);

		if (ret < 0) {
			SWBIS_ERROR_IMPL();
			return -1;
		}

		if (ret > (stdin_file_size - TARRECORDSIZE - TARRECORDSIZE)) {
			/*
			* Sanity check
			*/
			SWBIS_ERROR_IMPL();
			return -1;
		}

		/*
		 * Now pad the remaining output which will be at least
		 * 2 * 512 bytes long.
		 */
		padamount = stdin_file_size - ret;

		ret = swlib_pad_amount(ofd, padamount);
		if (ret < 0 || ret != padamount) {
			SWBIS_ERROR_IMPL();
			return -1;
		}

		/*
		 * Reap the events from the event pipe.
		 */
		ret = swicol_rpsh_task_expect(swi->swicolM,
				event_fd,
				SWICOL_TL_4 /*time limit*/);
		if (swi->debug_eventsM)
			swicol_show_events_to_fd(swi->swicolM, STDERR_FILENO, -1);
	}
	taru_free_header(file_hdr);
	strob_close(tmp);
	strob_close(namebuf);
	free(tar_hdr);
	return 0; /* ret; */
}

int
swpl_common_catalog_tarfile_operation(SWI * swi, int ofd, 
	char * catalog_path, char * pax_read_command,
	int alt_catalog_root, int event_fd,
	char * script, char * id_str)
{
	int ret = 0;
	STROB * namebuf;

	namebuf = strob_open(10);

	/*
	 * Here is the directory that is chdir'ed into.
	 */
	strob_strcpy(namebuf, catalog_path);
	if (alt_catalog_root == 0) {
		/*
		 * Unless alt_catalog_root is true,
		 * the catalog path is relative to the
		 * target path.
		 */
		swlib_squash_all_leading_slash(strob_str(namebuf));
	} else {
		/* FIXME */
		/* not supported yet */
		SWLIB_FATAL("alt_catalog_root not supported");
	}

	/*
	 * Now send the script.
	 */

	/* swicol_set_task_idstring(swi->swicolM, id_str); */
	ret = swicol_rpsh_task_send_script2(
		swi->swicolM,
		ofd, 
		512,  /* Some dd's can't read zero bytes */
		strob_str(namebuf),
		script,
		id_str);

	if (ret == 0) {
		/* 
		 * Now Send the payload 
		 * which in this case is just a gratuitous 512 bytes.
		 * This is needed because some dd(1) on some Un*xes can't
		 * read zero blocks.
		 */
		ret = etar_write_trailer_blocks(NULL, ofd, 1);
		if (ret < 0) {
			fprintf(stderr, "%s: swpl_common_catalog_tarfile_operation(): etar_write_trailer_blocks(): ret=%d\n",
				swlib_utilname_get(), ret);
			SWBIS_ERROR_IMPL();
			SWI_internal_error();
			return -1;
		}

		/*
		 * Now reap the events from the event pipe.
		 */
		ret = swicol_rpsh_task_expect(swi->swicolM,
				event_fd,
				SWICOL_TL_4 /*time limit*/);

		if (swi->debug_eventsM)
			swicol_show_events_to_fd(swi->swicolM, STDERR_FILENO, -1);
	}
	strob_close(namebuf);
	return ret;
}

void
swpl_update_fileset_state(SWI * swi, char * swsel, char * state)
{

	SWI_PRODUCT * product;
	SWI_XFILE * fileset;
	int fileset_index = 0;

	/*
	 * FIXME, supprt software selections
	 */
	product = swi_package_get_product(swi->swi_pkgM, 0 /* The first product */);
	fileset = swi_product_get_fileset(product, fileset_index++);
	while(fileset) {	
		swi_xfile_set_state(fileset, state);
		fileset = swi_product_get_fileset(product, fileset_index++);
	}
}

int
swpl_update_execution_script_results(SWI * swi, SWICOL * swicol, SCAR ** array)
{
	int i;
	STROB * buf;
	STROB * tmp;
	SWI_CONTROL_SCRIPT * script;
	int event_index = -1;
	int event_start_index;
	int status;
	char * tag;
	char * tagspec;
	char * message;
	
	buf = strob_open(100);
	tmp = strob_open(100);

	event_start_index = swicol->event_indexM;

	/*
	swicol_print_events(swicol, buf, -1);	
	fprintf(stderr, "%s", strob_str(buf));
	swpl_scary_show_array(array);
	*/

	/*
	 * loop over the events
	 */
	message = swicol_rpsh_get_event_message(swicol, SW_CONTROL_SCRIPT_BEGINS,
				event_start_index, &event_index);
	event_index++;
	while (message) {
		/* fprintf(stderr, "message=[%s]\n", message);
			*/
		tagspec = message;
		tag = strchr(message, (int)(' '));
		SWLIB_ASSERT(tag != NULL);
		*tag='\0';
		tag++;
		/* fprintf(stderr, "tag=[%s] tagspec=[%s]\n", tag, tagspec);
			*/
		/*
		 * Now find the script that belongs to this tag and tagspec
		 */
		script = swpl_scary_find_script(array, tag, tagspec);
		SWLIB_ASSERT(script != NULL);
		status = swicol_rpsh_get_event_status(swicol, (char*)(NULL),
                		SW_CONTROL_SCRIPT_ENDS, event_index, &event_index);
		SWLIB_ASSERT(status >= 0);
		script->resultM = status;
		message = swicol_rpsh_get_event_message(swicol,
				SW_CONTROL_SCRIPT_BEGINS,
				event_index+1,
				&event_index);
	}


	strob_close(tmp);
	strob_close(buf);
	return 0;
}

int
swpl_unpack_catalog_tarfile(SWI * swi, int ofd, 
	char * catalog_path, char * pax_read_command,
	int alt_catalog_root, int event_fd)
{
	int ret = 0;
	STROB * tmp;

	tmp = strob_open(10);
	E_DEBUG("");

	strob_sprintf(tmp, 0,
		"#set -vx\n"
		"# echo unpacking catalog %s 1>&2\n"
		"dd of=/dev/null 2>/dev/null\n"
		"# pwd 1>&2\n"
		"cd  " SWINSTALL_INCAT_NAME  "\n"
		"%s %s <catalog.tar\n"
		"sw_retval=$?\n"
		,
		swi->exported_catalog_prefixM,
		pax_read_command,
		swi->exported_catalog_prefixM
		);

	E_DEBUG("");
	ret = swpl_common_catalog_tarfile_operation(swi, ofd, catalog_path,
				pax_read_command, alt_catalog_root,
				event_fd, strob_str(tmp),
				SWBIS_TS_Catalog_unpack);
	E_DEBUG("");
	strob_close(tmp);
	return ret;
}

/** swpl_remove_catalog_directory - remove the unpacked catalog from catalog
 *
 */

int
swpl_remove_catalog_directory(SWI * swi, int ofd, 
	char * catalog_path, char * pax_read_command,
	int alt_catalog_root, int event_fd)
{
	int ret = 0;
	STROB * tmp;
	STROB * path;
	STROB * tmptok;
	STROB * rmdir_command;
	char * token;
	char * start;

	path = strob_open(10);
	tmp = strob_open(10);
	tmptok = strob_open(10);
	rmdir_command = strob_open(10);

	/*
	 * perform some sanity checks on swi->exported_catalog_prefixM
	 * It should have the force of <path>/catalog
	 */

	strob_strcpy(path, swi->exported_catalog_prefixM);
	if (swlib_check_clean_relative_path(strob_str(path))) return 1;
	swlib_squash_trailing_slash(strob_str(path));
	if (strstr(strob_str(path), SW_A_catalog) == NULL) return 2;

	/*
	 * OK , swi->exported_catalog_prefixM is now qualified as sane
	 */

	/*
	 * swi->exported_catalog_prefixM is typically :  <path>/catalog
	 * therefore we must execute:
	 *     rmdir <path>
	 *  If there is more than one leading path component
	 *  then they must be rmdir'ed individually
	 *  
	 *  If the exported catalog path is 
	 *      aaaa/bbbb/cccc/catalog    then
	 *  form a commmand string to remove aaaa/bbbb/cccc
         *  using rmdir since it is safer to user than rm -fr
	 *  The command will look like this:
	 *     rmdir aaaa/bbbb/cccc && rmdir aaaa/bbbb && rmdir aaaa
	 */

	strob_strcpy(rmdir_command, "");
	if (strchr(strob_str(path), '/')) {
		start = strob_str(path);
		token = strrchr(start, '/');	
		while(token) {
			*token = '\0';
			strob_sprintf(rmdir_command, 1, " && rmdir \"%s\"", start); 
			token = strrchr(start, '/');	
		}
	}

	strob_sprintf(tmp, 0,
		"cd " SWINSTALL_INCAT_NAME "\n"
		"/bin/rm -fr \"%s\" %s\n"
		"sw_retval=$?\n"
		"#echo rmdir command is [\"%s\"] 1>&2\n"
		"#echo rm command is [\"%s\"] 1>&2\n"
		"dd of=/dev/null 2>/dev/null\n"
		,
		swi->exported_catalog_prefixM,
		strob_str(rmdir_command),
		strob_str(rmdir_command),
		swi->exported_catalog_prefixM
		);


	ret = swpl_common_catalog_tarfile_operation(swi, ofd, catalog_path,
				pax_read_command, alt_catalog_root,
				event_fd, strob_str(tmp),
				SWBIS_TS_Catalog_dir_remove);
	strob_close(tmp);
	strob_close(path);
	strob_close(rmdir_command);
	strob_close(tmptok);
	return ret;
}

int
swpl_get_utsname_attributes(GB * G, SWICOL * swicol, SWUTS * uts, int ofd, int event_fd)
{
	int ret;
	STROB * tmp = strob_open(10);
	STROB * tmp1 = strob_open(10);

	strob_sprintf(tmp, 0,
			"sw_retval=0\n"
			"%s\n" /* shls_config_guess() */
			"%s\n" /* shls_run_config_guess() */
			"%s\n"
			"%s\n"
			"%s\n"
			"%s\n"
			"%s\n"
			"dd of=/dev/null 2>/dev/null\n"
			"exit $sw_retval\n"
			"%s"		/* nil line */
			,
			shlib_get_function_text_by_name("shls_config_guess", tmp1, NULL),
			shlib_get_function_text_by_name("shls_run_config_guess", tmp1, NULL),
			TEVENT(2, 1, SWI_ATTRIBUTE, SW_A_machine_type "=\"$(uname -m)\""),
			TEVENT(2, 1, SWI_ATTRIBUTE, SW_A_os_name      "=\"$(uname -s)\""),
			TEVENT(2, 1, SWI_ATTRIBUTE, SW_A_os_release   "=\"$(uname -r)\""),
			TEVENT(2, 1, SWI_ATTRIBUTE, SW_A_os_version   "=\"$(uname -v)\""),
			TEVENT(2, 1, SWI_ATTRIBUTE, SW_A_architecture "=\"$(shls_run_config_guess)\""),
			"");
	/* E_DEBUG2("get_utsname_script=[%s]", strob_str(tmp)); */

	/* TS_uts_query */
	/* swicol_set_task_idstring(swicol, SWBIS_TS_uts); */
	ret = swicol_rpsh_task_send_script2(
		swicol,
		ofd, 
		512,
		".",
		strob_str(tmp), SWBIS_TS_uts
		);

	if (ret == 0) {
		ret = etar_write_trailer_blocks(NULL, ofd, 1);
		if (ret < 0) {
			fprintf(stderr, "%s: swpl_get_utsname_attributes(): etar_write_trailer_blocks(): ret=%d\n",
				swlib_utilname_get(), ret);
		}

		ret = swicol_rpsh_task_expect(swicol,
			event_fd,
			SWICOL_TL_100 /*timelimit*/);
			/* 100 seconds needed for cygwin hosts */
	
		/*
		if (swi->debug_eventsM)
			swicol_show_events_to_fd(swi->swicolM, STDERR_FILENO, -1);
		*/

		/*
		 * print the events to memory
		 */
		swicol_print_events(swicol, tmp, swicol->event_indexM);

		/*
		 * Parse and Store the uts attributes
		 */
		swuts_read_from_events(/* swi->target_version_idM->swutsM */ uts, strob_str(tmp));

		E_DEBUG2("utsname=[%s]", strob_str(tmp));

		if (ret != 0) {
			/*
			 * Examine the events in swicol->evemt_listM to determine
			 * what action to take
			 */
			if (ret == 2) {
				swlib_doif_writef(G->g_verboseG,  1,
					(struct sw_logspec *)(NULL), STDERR_FILENO,
					"SW_RESOURCE_ERROR on target host:  %d second time limit expired\n", 5);
			}
			ret = -1;
		}
	}
	strob_close(tmp);
	strob_close(tmp1);
	return ret;
}

int
swpl_determine_tar_listing_verbose_level(SWI * swi)
{
	int taru_ls_verbose_level;

	E_DEBUG("");
	if (swi->swc_idM == SWC_U_I /* swinstall */) {
		if (swi->verboseM >= SWC_VERBOSE_3) {
			E_DEBUG("");
			taru_ls_verbose_level = LS_LIST_VERBOSE_L1;
		} else {
			E_DEBUG("");
			taru_ls_verbose_level = LS_LIST_VERBOSE_L0;
		}
	} else if (swi->swc_idM == SWC_U_L /* swlist */) {
		if (swi->verboseM >= SWC_VERBOSE_2) {
			E_DEBUG("");
			taru_ls_verbose_level = LS_LIST_VERBOSE_L1;
		} else {
			E_DEBUG("");
			taru_ls_verbose_level = LS_LIST_VERBOSE_L0;
		}
	} else {
		E_DEBUG("");
		taru_ls_verbose_level = LS_LIST_VERBOSE_L0;
	}
	E_DEBUG2("[%d]", taru_ls_verbose_level);
	return taru_ls_verbose_level;
}

int
swpl_assert_all_file_definitions_installed(SWI * swi, SWHEADER * infoheader)
{
	int ret;
	char * next_line;
	char * keyword;
	char * missing_name;
	
	ret = 0;
	swheader_store_state(infoheader, NULL);
	swheader_reset(infoheader);
	while((next_line=swheader_get_next_object(infoheader, (int)UCHAR_MAX, (int)UCHAR_MAX))) {
		keyword = swheaderline_get_keyword(next_line);
		SWLIB_ASSERT(keyword != NULL);
		if (strcmp(keyword, SW_A_control_file) == 0) {
			continue;
		}
		if (swheaderline_get_flag1(next_line) == 0) {
			missing_name = swpl_get_attribute(infoheader, SW_A_path, NULL);
			swlib_doif_writef(swi->verboseM, SWC_VERBOSE_1,
				(struct sw_logspec *)(NULL), STDERR_FILENO,
				"missing from storage section: %s\n", missing_name);
			ret++;
		}
	}
	swheader_restore_state(infoheader, NULL);
	return ret;
}

VPLOB *
swpl_get_same_revision_specs(GB * G, SWI * swi, int product_number, char * location)
{
	char * revision;
	char * tag;
	VPLOB * swspecs;
	SWI_PRODUCT * product;
	SWHEADER * global_index;
	SWVERID * swverid;
	STROB * tmp;

	tmp = strob_open(10);
	swspecs = vplob_open(); 

	if (location && strlen(location) == 0) location = NULL;

	product = swi_package_get_product(swi->swi_pkgM, product_number/* The first product */);
	SWLIB_ASSERT(product != NULL);
	
	/* Get the global INDEX access header object */
	global_index = swi_get_global_index_header(swi);
	swheader_store_state(global_index, NULL);
	swheader_reset(global_index);

	swheader_set_current_offset(global_index, product->baseM.header_indexM);

	tag = swheader_get_single_attribute_value(global_index, SW_A_tag);
	SWLIB_ASSERT(tag != NULL);

	revision = swheader_get_single_attribute_value(global_index, SW_A_revision);
	SWLIB_ASSERT(revision != NULL);
	
	/* First, LT */
	strob_sprintf(tmp, STROB_NO_APPEND, "%s,r<%s", tag, revision);
	if (location)
		strob_sprintf(tmp, STROB_DO_APPEND, ",l=%s", location);
	swverid = swverid_open(NULL, strob_str(tmp));
	vplob_add(swspecs, swverid);	

	/* Second,  EQ */
	strob_sprintf(tmp, STROB_NO_APPEND, "%s,r==%s", tag, revision);
	if (location)
		strob_sprintf(tmp, STROB_DO_APPEND, ",l=%s", location);
	swverid = swverid_open(NULL, strob_str(tmp));
	vplob_add(swspecs, swverid);	

	/* Third, GT */
	strob_sprintf(tmp, STROB_NO_APPEND, "%s,r>%s", tag, revision);
	if (location)
		strob_sprintf(tmp, STROB_DO_APPEND, ",l=%s", location);
	swverid = swverid_open(NULL, strob_str(tmp));
	vplob_add(swspecs, swverid);	

	/* Fouth, EQ but any location */
	strob_sprintf(tmp, STROB_NO_APPEND, "%s,r==%s", tag, revision);
	swverid = swverid_open(NULL, strob_str(tmp));
	vplob_add(swspecs, swverid);	

	swheader_restore_state(global_index, NULL);
	strob_close(tmp);
	return swspecs;
}

VPLOB *
swpl_get_dependency_specs(GB * G, SWI * swi, char * requisite_keyword, int product_number, int fileset_number)
{
	char * depspec;
	char * value;
	VPLOB * swspecs;
	SWI_PRODUCT * product;
	SWI_XFILE * fileset;
	char * next_line;
	char * keyword;
	char * missing_name;
	SWHEADER * global_index;
	SWVERID * swverid;
	STROB * tmp;
	STROB * tmp2;
	char ** xlist;
	char ** list;
	
	tmp = strob_open(10);
	tmp2 = strob_open(10);

	/* Get the dependency specs from the fileset per spec */

	swspecs = vplob_open(); /* List object that will contain a
				   list of SWVERID objects */

	product = swi_package_get_product(swi->swi_pkgM, product_number/* The first product */);
	SWLIB_ASSERT(product != NULL);

	fileset = swi_product_get_fileset(product, fileset_number);
	SWLIB_ASSERT(fileset != NULL);

	/* Now get the dependencies which are stored in the 'prerequisites' attrbute */

	/* Get the global INDEX access header object */
	global_index = swi_get_global_index_header(swi);
	swheader_store_state(global_index, NULL);
	swheader_reset(global_index);

	/* Now set the offset of the relevant part of the global INDEX file */
	swheader_set_current_offset(global_index, fileset->baseM.header_indexM);

	xlist = swheader_get_attribute_list(global_index, requisite_keyword, (int*)NULL);
	list = xlist;	
	while (*list) {
		value = swheaderline_get_value(*list, NULL);
		/* Now token-ize this as space delimeted */
		
		/* The data is in escaped internal form, hence we must
		   (de)expand the "\\n" (for example) sequences to turn them
		   into the real char (a '\n' for example */
		swlib_expand_escapes((char **)(NULL), NULL, value, tmp);

		depspec = strob_strtok(tmp, strob_str(tmp), " \n\r\t"); /* FIXME supported quoted spaces ??? */
		while(depspec) {
			swverid = swverid_open(NULL, depspec);
			if (swverid == NULL) {
				sw_e_msg(G, "error processing software spec: %s\n", depspec);
			} else {
				SWVERID * next;
				next = swverid;
				vplob_add(swspecs, next);	
				while((next=swverid_get_alternate(next))) {
					vplob_add(swspecs, next);	
				}
				swverid_disconnect_alternates(swverid);
				/*
				strob_strcpy(tmp2, "");
				swverid_show_object_debug(swverid, tmp2, "");
				fprintf(stderr, "%s\n", strob_str(tmp2));
				*/
			}
			/* fprintf(stderr, "JL [%s]\n", depspec); */
			depspec = strob_strtok(tmp, NULL, " \n\r\t");
		}
		list++;
	}

	free(xlist);
	strob_close(tmp);
	strob_close(tmp2);
	swheader_restore_state(global_index, NULL);
	return swspecs;
}

int
swpl_get_catalog_entries(GB * G,
			VPLOB * swspecs,
			VPLOB * pre_swspecs,
			VPLOB * co_swspecs,
			VPLOB * ex_swspecs,
			char * target_path,
			SWICOL * swicol,
			int target_fd0,
			int target_fd1,
			struct extendedOptions * opta,
			char * pgm_mode)
{
	STROB * target_catalog_dir;
	STROB * isc_script_buf;
	int aa_fd;
	int aa_len;
	int aa_len2;
	int aa_i;
	int ret;
	int retval;
	
	E_DEBUG("");
	retval = 0;
	isc_script_buf = strob_open(10);
	target_catalog_dir = strob_open(10);

	/* This section writes the product_tag revision vendor_tag
	   to  stdout */

	/* write the task script into a buffer */
	if (swpl_test_pgm_mode(pgm_mode, SWLIST_PMODE_PROD) == 0) {
		swicat_write_isc_script(isc_script_buf, G, swspecs, NULL, NULL, NULL, target_path, SWICAT_FORM_P1);
	} else if (swpl_test_pgm_mode(pgm_mode, SWLIST_PMODE_DIR) == 0) {
		swicat_write_isc_script(isc_script_buf, G, swspecs, NULL, NULL, NULL, target_path, SWICAT_FORM_DIR1);
	} else if (swpl_test_pgm_mode(pgm_mode, SWLIST_PMODE_DEP1) == 0) {
		swicat_write_isc_script(isc_script_buf, G, NULL, pre_swspecs, NULL, ex_swspecs, target_path, SWICAT_FORM_DEP1);
	} else {
		sw_e_msg(G, "bad internal mode: %s\n", pgm_mode);
		swicat_write_isc_script(isc_script_buf, G, NULL, pre_swspecs, NULL, ex_swspecs, target_path, SWICAT_FORM_DEP1);
	}
	
	/* Form the directory name of the catalog location */
	strob_strcpy(target_catalog_dir, target_path);
	swlib_unix_dircat(target_catalog_dir, get_opta(opta, SW_E_installed_software_catalog));

	/* Now send the SWBIS_TS_Get_iscs_listing task script */
	/* swicol_set_task_idstring(swicol, SWBIS_TS_Get_iscs_listing); */
	E_DEBUG("");
	ret = swicol_rpsh_task_send_script2(swicol,
		target_fd1,			/* file descriptor of the task shell's stdin */
		512,				/* data size, here just a gratuitous block of NULs */
		strob_str(target_catalog_dir),	/* Directory to run in */
		strob_str(isc_script_buf),	/* The actual script */
		SWBIS_TS_Get_iscs_listing);
			
	if (ret != 0) {
		E_DEBUG("");
		fprintf(stderr, "swicol_rpsh_task_send_script2 error\n");
		retval = -1;
		return -1;
	}

	/* Send 1 block to satisfy the task shell, all task shells
	   get atleast 1 block because some dd()'s can't read zero (0)
	   block */
	E_DEBUG("");
	ret = etar_write_trailer_blocks(NULL, target_fd1, 1);
	if (ret < 0) {
		fprintf(stderr, "etar_write_trailer_blocks error\n");
		retval = -2;
		return retval;
	}

	/* Open a mem file just to collect the output and
	   run a sanity check */
	aa_fd = swlib_open_memfd();	

	/* Now read the output from the target process */
	E_DEBUG("");
	ret = swlib_synct_suck(aa_fd, target_fd0);
	E_DEBUG("");

	if (ret < 0) {
		/* This can happen for good reasons such as 'no such file'
		   as well as internal error bad reasons */
		/* fprintf(stderr, "swlib_synct_suck error\n"); */
		E_DEBUG("");
		retval = -3;
		return retval;
	}

	/* Now reap the task shell events */
	ret = swicol_rpsh_task_expect(swicol, G->g_swi_event_fd, SWICOL_TL_3);
	if (ret != 0) {
		if (ret < 0) {
			SWLIB_INTERNAL("");
		}
		retval = -4;
		sw_e_msg(G, "swicol_rpsh_task_expect failed: status=%d\n", ret);
		return retval;
	}
	E_DEBUG("");
	uxfio_lseek(aa_fd, 0, SEEK_SET);
	swicat_squash_null_bytes(aa_fd);
	uxfio_lseek(aa_fd, 0, SEEK_SET);

	retval = aa_fd;
	strob_close(isc_script_buf);
	strob_close(target_catalog_dir);
	return retval;
}


int
swpl_do_list_catalog_entries2(GB * G,
			VPLOB * swspecs,
			VPLOB * pre_swspecs,
			VPLOB * co_swspecs,
			VPLOB * ex_swspecs,
			char * target_path,
			SWICOL * swicol,
			int target_fd0,
			int target_fd1,
			struct extendedOptions * opta,
			char * pgm_mode)
{
	int retval;
	int memfd;
	char * memtext;

	retval = 0;
	memfd = swpl_get_catalog_entries(G,
			swspecs,
			pre_swspecs,
			co_swspecs,
			ex_swspecs,
			target_path,
			swicol,
			target_fd0,
			target_fd1,
			opta,
			pgm_mode);

	if (memfd < 0) return memfd;
	uxfio_lseek(memfd, 0, SEEK_SET);

	/* Now write the response from the target to local stdout */
	if (
		swpl_test_pgm_mode(pgm_mode, SWLIST_PMODE_PROD) == 0 ||
		swpl_test_pgm_mode(pgm_mode, SWLIST_PMODE_DIR) == 0 ||
		G->g_verboseG >= SWC_VERBOSE_3 ||
		0
	) {
		swlib_pipe_pump(STDOUT_FILENO, memfd);
	}

	if (swpl_test_pgm_mode(pgm_mode, SWLIST_PMODE_DEP1) == 0) {
		SWICAT_REQ  * req;
		int ret;
		/* Analyze the dependencies */
	
		req = swicat_req_create();
		/* Now get the NUL terminated text image */
		memtext = uxfio_get_fd_mem(memfd, (int *)NULL);

		ret = swicat_req_analyze(G, req, memtext, NULL);
		if (ret < 0 || ret > 0) {
			sw_e_msg(G, "internal error analyzing dependencies, ret=%d\n", ret);
		} else {
			;
			/* no error, dependencies successfully
			   queried independent of query result */
		}
		if (
			swicat_req_get_pre_result(req) != 0 ||
			swicat_req_get_ex_result(req) != 0 ||
			0
		) {
			/* Failed dependency */
			retval = 1;
			swicat_req_print(G, req);
		}
		swicat_req_delete(req);
	}
	uxfio_close(memfd);
	return retval;
}

int
swpl_test_pgm_mode(char * pgm_mode, char * test_mode)
{
	if (strcmp(test_mode, pgm_mode) == 0) {
		return 0;
	} else {
		return 1;
	}
}

int
swpl_get_catalog_tar(GB * G,
	SWI * swi,
	char * target_path,
	VPLOB * upgrade_specs,
	int target_fd0,
	int target_fd1)
{
	char * path;
	struct stat st;
	int oflags;
	SWVARFS * swvarfs;
	STROB * isc_script_buf;
	STROB * target_catalog_dir;
	struct extendedOptions * opta;
	int ret;
	int cfd;

	E_DEBUG("");
	opta = swi->optaM;

	isc_script_buf = strob_open(100);
	target_catalog_dir = strob_open(100);

	/* write a tar archive of the selection that will be upgraded because a 
	   removal of the fileset file and catalog entry is required */

	/* Note: the following function is used in the 'swlist -c -' operation,
	   we reuse it here,  this will get the tarblob catalog entries of all
	   the specs in the list (VPLOB *) upgrade_specs  */

	E_DEBUG("");
	swicat_write_isc_script(isc_script_buf, G, upgrade_specs,
				NULL, NULL, NULL, target_path, SWICAT_FORM_TAR1);
	E_DEBUG("");
	strob_strcpy(target_catalog_dir, target_path);
	swlib_unix_dircat(target_catalog_dir, get_opta(opta, SW_E_installed_software_catalog));

	/* swicol_set_task_idstring(swi->swicolM, SWBIS_TS_Get_iscs_entry); */

	E_DEBUG("");
	ret = swicol_rpsh_task_send_script2(swi->swicolM,
		target_fd1,
		512,          
		strob_str(target_catalog_dir),
		strob_str(isc_script_buf),   
		SWBIS_TS_Get_iscs_entry);

	E_DEBUG("");
	if (ret != 0) {
		E_DEBUG("");
		swicol_set_master_alarm(swi->swicolM);
		sw_e_msg(G, "swicol: fatal: %s:%d\n", __FILE__, __LINE__);
	}

	if (ret == 0) {
		E_DEBUG("");
		ret = etar_write_trailer_blocks(NULL, target_fd1, 1);
	} else {
		E_DEBUG("");
		ret = -1;
	}

	E_DEBUG("");
	cfd = swlib_open_memfd();
	if (swicol_get_master_alarm_status(swi->swicolM) == 0 && ret == 512) {
		TARU * taru = taru_create();
		E_DEBUG("");
		ret = taru_process_copy_out(taru, target_fd0, cfd,
					NULL, NULL, arf_ustar, -1, -1, (intmax_t*)NULL, NULL);
		taru_delete(taru);
		if (ret < 0) {
			return -1;
		}
	} else {
		E_DEBUG("");
		return -2;
	}
	E_DEBUG("");
	ret = swicol_rpsh_task_expect(swi->swicolM, G->g_swi_event_fd, SWICOL_TL_3);
	if (uxfio_lseek(cfd, (off_t)0, SEEK_SET) < 0) {
		E_DEBUG("");
		return -3;
	}

	E_DEBUG("");
	if (uxfio_lseek(cfd, (off_t)0, SEEK_SET) < 0) {
		E_DEBUG("");
		return -4;
	}
	/*
	swlib_tee_to_file("/tmp/_catalog1.tar", cfd, NULL, -1, 0);
	*/

	E_DEBUG("");
	if (uxfio_lseek(cfd, (off_t)0, SEEK_SET) < 0) {
		return -5;
	}
	oflags = 0;

	E_DEBUG("");
	swvarfs = swvarfs_opendup(cfd, oflags, (mode_t)0);
	while ((path=swvarfs_get_next_dirent(swvarfs, &st)) != NULL && strlen(path)) {
		E_DEBUG("");
		if (G->devel_verboseM)
			fprintf(stderr, "JL path=[%s]\n", path);
	}

	E_DEBUG("");
	swvarfs_dirent_reset(swvarfs);
	E_DEBUG("");

	while ((path=swvarfs_get_next_dirent(swvarfs, &st)) != NULL && strlen(path)) {
		E_DEBUG3("catalog_tar: %s: %s", strob_str(target_catalog_dir), path);
		if (G->devel_verboseM)
			fprintf(stderr, "JL path=[%s]\n", path);
	}
	E_DEBUG("");
	swvarfs_close(swvarfs);
	/* uxfio_close(cfd); */
	strob_close(isc_script_buf);
	strob_close(target_catalog_dir);
	E_DEBUG2("returning %d", cfd);
	return cfd;
}

void
swpl_tty_raw_ctl(GB * G, 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)
			sw_e_msg(G, "tty_raw error");
		}
	}
}

char *
swpl_get_samepackage_query_response(GB * G, SWICOL * swicol,
			char * target_path,
			int target_fd0,
			int target_fd1,
			struct extendedOptions * opta,
			VPLOB * packagespecs,
			int * p_retval,
			int make_dummy_response)
{
	int ret;
	int uxfio_fd;
	char * mem;

	E_DEBUG("calling swpl_get_catalog_entries");
	uxfio_fd = swpl_get_catalog_entries(G, (VPLOB*)NULL,
				packagespecs,
				(VPLOB*)NULL,
				(VPLOB *)NULL,
				target_path,
				swicol,
				target_fd0,
				target_fd1,
				opta,
				SWLIST_PMODE_DEP1);

	if (uxfio_fd < 0 ) {
		E_DEBUG("");
		return NULL;
	} else if (uxfio_fd < 0) {
		/* error, abort the target script */
		E_DEBUG("");
		abort_script(swicol, G, target_fd1);
		(*p_retval)++;
		return NULL;
	}
	/* The sync'ing dd on the target host injects blocks of NULs,
	   these must be squashed */
	E_DEBUG("");
	swicat_squash_null_bytes(uxfio_fd);

	/* Obtain a new image of the file */
	E_DEBUG("");
	uxfio_lseek(uxfio_fd, 0, SEEK_SET);
	mem = swi_com_new_fd_mem(uxfio_fd, (int*)NULL);

	E_DEBUG("");
	if (0 && G->devel_verboseM && 0)
		fprintf(stderr, "[[%s]]\n", mem);

	uxfio_close(uxfio_fd);
	/* FIXME, possible memory leak */
	E_DEBUG("");
	return mem;
}

SWICAT_REQ *
swpl_analyze_samepackage_query_response(GB * G, char * response_image, SWICAT_SL ** p_sl)
{
	int ret;
	int i;
	int j;
	SWICAT_REQ  * req;
	SWICAT_SL * sl;
	SWICAT_SC * sc;
	SWICAT_SR * sr;

	if (response_image == NULL) return NULL;
	req = swicat_req_create();

	/* analyze the image and make the SWICAT_SL object */

	ret = swicat_req_analyze(G, req, response_image, p_sl);
	sl = *p_sl;
	if (ret < 0 || ret > 0) {
		sw_e_msg(G, "internal error from swicat_req_analyze, ret=%d\n", ret);
		return NULL;
	} else {
		;
	}
	return req;
}

char *
swpl_shellfrag_session_lock(STROB * buf, int vlv)
{
	
	/*
	 * implicit external variable interface
	 *
	 * Read Only:
	 *   LOCKPATH
	 *   LOCKENTRY
	 *   swexec_status   {0|1}
	 *   opt_allow_no_lock   {""|yes}
	 *   sw_retval
	 *   sh_dash_s
         *
	 * Write: 
	 *
	 *
	 */

	strob_sprintf(buf, 0,
	"#\n"
	"#  <<<<----- here's the code to lock a session \n"
	"#\n"
	"lock_did_lock=\"\"\n"
	"shls_bashin2 \"" SWBIS_TS_make_locked_session "\"\n"
	"sw_retval=$?\n"
	" # sw_retval:\n"
	" #   0: OK, proceed by invoking bash -s\n"
	" #   1: Not OK, either commanded abort or internal error\n"
	"lock_status=0\n"
	"case $sw_retval in\n"
	"	0) \n"
	"	# Ok to make test for lock\n"
	"	$sh_dash_s\n"
	"	sw_retval=$?\n"
	"	lock_status=$sw_retval\n"
	"	;;\n"
	"	# 2)  Dead Code, we never get here\n"
	"	# sw_retval=1\n"
	"	# opt_allow_no_lock=\"\"\n"
	"	# lock_status=2\n"
	"	# ;;\n"
	"	*)\n"
	"	sw_retval=1\n"
	"	opt_allow_no_lock=\"\"\n"
	"	lock_status=" SWBIS_STATUS_COMMAND_NOT_FOUND "\n"
	"	;;\n"
	"esac\n"
	"swexec_status=$sw_retval\n"
	"case \"$lock_status\" in\n"
	"0)\n"
	"       # Got Lock\n"
	"	lock_did_lock=true\n"
	"	case \"$opt_to_stdout\" in\n"
	"	True)\n"
	"		lock_did_lock=\"\"\n"
	"		;;\n"
	"	*)\n"
	"		%s\n"  /* SW_SOC_LOCK_CREATED */
	"		;;\n"
	"	esac\n"
	"	;;\n"
	"2) # Read-Only Access \n"
	"	case \"$opt_allow_no_lock\" in	\"\") ;; *) lock_status=0 ;; esac\n"
	"	case \"$opt_allow_no_lock\" in\n"
	"	*)\n"
	"		%s\n" /* SW_SOC_IS_READ_ONLY */
	"		%s\n" /* SW_SOC_LOCK_FAILURE */
	"		sw_retval=0\n"
	"		swexec_status=$sw_retval\n"
	"		;;\n"
	"	esac\n"
	"	;;\n"
	"1) # Lock failed \n"
	"	case \"$opt_allow_no_lock\" in\n"
	"	\"\")\n"
	"		%s\n" /* SW_CONFLICTING_SESSION_IN_PROGRESS */
	"		%s\n" /* SW_SOC_LOCK_FAILURE */
	"		;;\n"
	"	*)\n"
	"		%s\n" /* SW_CONFLICTING_SESSION_IN_PROGRESS */
	"		%s\n" /* SW_SOC_LOCK_FAILURE */
	"		lock_status=0\n"
	"		sw_retval=0\n"
	"		swexec_status=$sw_retval\n"
	"		;;\n"
	"	esac\n"
	"	;;\n"
	SWBIS_STATUS_COMMAND_NOT_FOUND ")\n"
	"	# do nothing \n"
	"	;;\n"
	"*)\n"
	"	%s\n" /* SW_SOC_LOCK_FAILURE */
	"	;;\n"
	"esac\n"
	"case \"$opt_force_lock\" in \"\") ;; *) lock_did_lock=true; ;; esac\n"
	"#\n"
	"#  <<<<----- here ends the code to lock a session \n"
	"#\n",
	TEVENT(2, vlv, SW_SOC_LOCK_CREATED, "lockpath=$LOCKPATH: status=$sw_retval"),
	TEVENT(2, vlv, SW_SOC_IS_READ_ONLY, "lockpath=$LOCKPATH: status=1"),
	TEVENT(2, vlv, SW_SOC_LOCK_FAILURE, "lockpath=$LOCKPATH: status=1"),
	TEVENT(2, vlv, SW_CONFLICTING_SESSION_IN_PROGRESS, "lockpath=${LOCKPATH}: status=1"),
	TEVENT(2, vlv, SW_SOC_LOCK_FAILURE, "lockpath=$LOCKPATH: status=1"),
	TEVENT(2, vlv, SW_CONFLICTING_SESSION_IN_PROGRESS, "lockpath=$LOCKPATH: status=2"),
	TEVENT(2, vlv, SW_SOC_LOCK_FAILURE, "lockpath=$LOCKPATH: status=2"),
	TEVENT(2, vlv, SW_SOC_LOCK_FAILURE, "lockpath=$LOCKPATH: status=$lock_status")
	);
	return strob_str(buf);
}

char *
swpl_shellfrag_session_unlock(STROB * buf, int vlv)
{
	strob_sprintf(buf, 0,
	"case \"$lock_did_lock\" in\n"
	"       \"\") ;;\n"
	"       *)\n" 
	"       lf_remove_lock \"$opt_force_lock\"\n"
	"       %s\n"  /* SW_SOC_LOCK_REMOVED */
	"       ;;\n"  
	"esac\n",
	TEVENT(2, vlv, SW_SOC_LOCK_REMOVED, "status=$?")
	);
	return strob_str(buf);
}

int
swpl_session_lock(GB * G, SWICOL * swicol, char * target_path, int ofd, int event_fd)
{
	int ret;
	STROB * tmp;
	STROB * shell_lib_buf;

	E_DEBUG("");
	shell_lib_buf = strob_open(24);
	tmp = strob_open(24);

	/* swicol_set_task_idstring(swicol, SWBIS_TS_make_locked_session); */
	strob_sprintf(tmp, 0,
		"%s\n"
		"%s\n"
		"%s\n"
		"%s\n"
		"%s\n"
		"lf_make_lock </dev/null\n"
		"sw_retval=$?\n"
		"dd count=1 bs=512 of=/dev/null 2>/dev/null\n"
		,
		shlib_get_function_text_by_name("lf_make_lockfile_name", shell_lib_buf, NULL),
		shlib_get_function_text_by_name("lf_make_lockfile_entry", shell_lib_buf, NULL),
		shlib_get_function_text_by_name("lf_append_lockfile_entry", shell_lib_buf, NULL),
		shlib_get_function_text_by_name("lf_test_lock", shell_lib_buf, NULL),
		shlib_get_function_text_by_name("lf_make_lock", shell_lib_buf, NULL)
		);

	E_DEBUG("");
	ret = swicol_rpsh_task_send_script2(
		swicol,
		ofd, 
		512, 			/* stdin_file_size */
		target_path, 		/* directory to run in*/
		strob_str(tmp),  	/* the task script */
		SWBIS_TS_make_locked_session
		);

	if (ret != 0) {
		E_DEBUG2("swicol_rpsh_task_send_script2 returned %d", ret);
		return -1;
	}

	E_DEBUG("");
	ret = etar_write_trailer_blocks(NULL, ofd, 1);
	if (ret < 0) {
		E_DEBUG("error from etar_write_trailer_blocks");
		SWBIS_ERROR_IMPL();
		SWI_internal_error();
		return -1;
	}

	E_DEBUG("");
	ret = swicol_rpsh_task_expect(swicol,
				event_fd,
				SWICOL_TL_4 /*time limit*/);

	E_DEBUG2("ret=%d", ret);
	if (ret < 0) {
		E_DEBUG2("lock returning %d", ret);
		return -1;
	} else if (ret > 0 && G->g_force_locks == 0) {
		E_DEBUG2("lock returning %d", ret);
		return ret;
	}

	strob_close(tmp);
	strob_close(shell_lib_buf);
	return 0;
}

char *
swpl_looper_payload_routine(STROB * buf, int vlv, char * locked_region)
{
	char * ret;
	STROB * lockfrag_buffer;
	STROB * unlockfrag_buffer;

	lockfrag_buffer = strob_open(164);
	unlockfrag_buffer = strob_open(164);

	strob_sprintf(buf, 0,
		"shls_looper_payload()\n"
		"{\n"
		"	catalog_entry_dir=\"$1\"\n"
		"	case \"$targetpath\" in \"\") return 1;; esac\n"
		"	cd \"$targetpath\"\n"
		"	case $? in\n"
		"		0)\n"
		"			test -d \"$catalog_entry_dir\" ||\n"
		"			echo error: \"$catalog_entry_dir\" is not a directory 1>&2 ||\n"
		"			return 1\n"
		"			shls_bashin2 \"" SWBIS_TS_check_loop "\"\n"
		"			sw_retval=$?\n"
		"			case $sw_retval in 0) $sh_dash_s;; *) return 1;; esac\n"
		"			sw_retval=$?\n"
		"			swexec_status=$sw_retval\n"
		"			xxb=\"$catalog_entry_dir\"\n"
		"			# remove the last two directory components\n"
		"			xxb=\"${xxb%%/*}\"\n"
		"			xxb=\"${xxb%%/*}\"\n"
		"			LOCKPATH=\"$xxb\"\n"
		"			LOCKENTRY=$$\n"
		"			# set the lock_status to an error\n"
		"			lock_status=3\n"
		"			lock_did_lock=\"\"\n"
		"			# the locking code gets put inline here\n"
		"			%s\n"	/* <---- swpl_shellfrag_session_lock() */
		"			case \"$lock_status\" in\n"
		"			0)\n"
		"				%s\n" /* locked region */
		"			;;\n"
		"			esac\n"
		"			%s\n"	/* <---- swpl_shellfrag_session_unlock() */
		"			return $swexec_status\n"
		"		;;\n"
		"		*)\n"
		"			return 1\n"
		"		;;\n"
		"	esac\n"
		"	#echo $1>>/tmp/looper.out\n"
		"}\n",
/*_% */		swpl_shellfrag_session_lock(lockfrag_buffer, vlv),
		locked_region,
/*_% */		swpl_shellfrag_session_unlock(unlockfrag_buffer, vlv)
		);
	strob_close(lockfrag_buffer);
	strob_close(unlockfrag_buffer);
	return strob_str(buf);
}

/**
 * swpl_signature_policy_accept - analyze gpg status line
 *
 * Return 0 if authenticity meets requiment, non-zero if not
 */

int
swpl_signature_policy_accept(GB * G, SWGPG_VALIDATE * w, int verbose_level, char * swspec_string)
{
	int retval;
	int n;
	int num_of_sigs;
	int ngood;
	int ret;
	int gotta_have_all;
	struct extendedOptions * opta;
	char * blob;
	char * name;
	char * sig;
	int result;
	int sig_level;
	int sig_fd;
	int logger_fd;
	int status_fd;

	opta = G->optaM;
	swgpg_set_status_array(w); /* harmless if already done so do it again */

	sig_level = swlib_atoi(get_opta(opta, SW_E_swbis_sig_level), &result);
	if (result) {
		return -1;
	}

	gotta_have_all = swextopt_is_option_true(SW_E_swbis_enforce_all_signatures, opta);

	n = 0;
	num_of_sigs = swgpg_get_number_of_sigs(w);	

	ngood = 0;
	while((blob=strar_get(w->list_of_status_blobsM, n)) != NULL) {
		sig_fd = -1;
		status_fd = -1;
		logger_fd = -1;
		ret = swgpg_get_status(w, n);
		switch (ret) {
			case SWGPG_SIG_VALID:
				ngood++;
				if (verbose_level >= SWC_VERBOSE_2) {
					logger_fd = STDOUT_FILENO;
				}
				if (verbose_level >= SWC_VERBOSE_3) {
					status_fd = STDOUT_FILENO;
				}
				break;
			default:
				logger_fd = STDERR_FILENO;
				if (verbose_level >= SWC_VERBOSE_3)
					status_fd = STDERR_FILENO;
				break;
		}
		swgpg_show(w, n, sig_fd, status_fd, logger_fd);
		n++;
	}
	
	retval = 1;
	if (sig_level == 0) {
		retval = 0;
	} else if (sig_level > 0 && !gotta_have_all) {
		if (ngood >= sig_level) {
			retval = 0;
		}
	} else if (sig_level > 0 && gotta_have_all) {
		if (
			ngood >= sig_level &&
			ngood == num_of_sigs &&
			ngood > 0 &&
			1
		) {
			retval = 0;
		}
	}

	if (retval) {
		swc_stderr_fd2_set(G, STDERR_FILENO);
		sw_l_msg(G, SWC_VERBOSE_1, "%s at sig_level=%d for %s: %d sigs, %d good: status=1\n",
			swevent_code(SW_ISC_INTEGRITY_NOT_CONFIRMED), sig_level, swspec_string, num_of_sigs, ngood);
		swc_stderr_fd2_restore(G);
	} else {
		if (sig_level == 0 && num_of_sigs != ngood) {
			sw_l_msg(G, SWC_VERBOSE_1, "Warning: %s at sig_level=%d for %s: %d sigs, %d good: status=2\n",
				swevent_code(SW_ISC_INTEGRITY_NOT_CONFIRMED), sig_level, swspec_string, num_of_sigs, ngood);
		} else if (
				(sig_level > 0 && ngood >= sig_level) ||
				(sig_level == 0 && num_of_sigs > 0 && num_of_sigs == ngood) ||
				0
		) {
			swc_stderr_fd2_set(G, STDOUT_FILENO);
			sw_l_msg(G, SWC_VERBOSE_2, "%s at sig_level=%d for %s: %d sigs, %d good: status=0\n",
				swevent_code(SW_ISC_INTEGRITY_CONFIRMED), sig_level, swspec_string, num_of_sigs, ngood);
			swc_stderr_fd2_restore(G);
		} else if (
				(sig_level == 0 && num_of_sigs == 0) ||
				0
		) {
			swc_stderr_fd2_set(G, STDOUT_FILENO);
			sw_l_msg(G, SWC_VERBOSE_1, "%s at sig_level=%d for %s: %d sigs, %d good: status=0\n",
				swevent_code(SW_ISC_INTEGRITY_NOT_CONFIRMED), sig_level, swspec_string, num_of_sigs, ngood);
			swc_stderr_fd2_restore(G);
		} else {
			swc_stderr_fd2_set(G, STDERR_FILENO);
			sw_l_msg(G, SWC_VERBOSE_1, "%s at sig_level=%d for %s: %d sigs, %d good: status=0\n",
				swevent_code(SW_ISC_INTEGRITY_NOT_CONFIRMED), sig_level, swspec_string, num_of_sigs, ngood);
			swc_stderr_fd2_restore(G);
		}
	}
	return retval;
}

/**
 * swpl_remove_catalog_entry - remove the [entire] catalog entry
 *  @e : entry to remove
 *
 * To remove an entry, remove the inactive name, then move the 
 * entry to the inactive name
 */

int
swpl_remove_catalog_entry(GB * G, SWICOL * swicol, SWICAT_E * e, int ofd, char * iscpath)
{
	STROB * btmp;
	STROB * tmp;
	STROB * tmp2;
	STROB * dir2;
	char * epath; 
	char * depath;
	char * s_ret1; 
	char * s_ret2; 
	int retval;
	int ret;
	
	retval = 0;
	tmp = strob_open(32);
	tmp2 = strob_open(32);
	btmp = strob_open(32);
	dir2 = strob_open(32);

	E_DEBUG("Entering");
	s_ret1 = swicat_e_form_catalog_path(e, tmp,
			iscpath /* get_opta(G->optaM, SW_E_installed_software_catalog) */,
			SWICAT_ACTIVE_ENTRY);
	epath = strob_str(tmp);

	/* SWLIB_INFO2("catalog entry (active) path = %s", epath); */
	s_ret2 = swicat_e_form_catalog_path(e, tmp2,
			iscpath /*get_opta(G->optaM, SW_E_installed_software_catalog) */,
			SWICAT_DEACTIVE_ENTRY);
	depath = strob_str(tmp2);

	/* SWLIB_INFO2("catalog entry (active) path = %s", depath); */

	if (swlib_check_clean_relative_path(epath) != 0) {
		sw_e_msg(G, "tainted path name: %s\n", epath);
		epath = NULL;
	}
	
	if (swlib_check_clean_relative_path(depath) != 0) {
		sw_e_msg(G, "tainted path name: %s\n", depath);
		depath = NULL;
	}

	if (s_ret1 == NULL || s_ret2 == NULL) {
		SWLIB_INFO("error: entry not removed: test, test");
		ret = swpl_send_nothing_and_wait(swicol, ofd, G->g_swi_event_fd,
			SWBIS_TS_remove_catalog_entry,
			/* wait this long */ SWICOL_TL_8,
			/* exit with this return status */ SW_SUCCESS);
		if (ret < 0) retval++;
		goto error_out;
	}
	
	E_DEBUG2("epath=[%s]", epath);
	E_DEBUG2("depath=[%s]", depath);
	E_DEBUG2("e->entry_prefix=[%s]", e->entry_prefixM);

	/* For example
	DEBUG:         swproglib.c:2907  , swpl_remove_catalog_entry : epath=[var/lib/swbis/catalog/swbis/swbis/0.730/0]
	DEBUG:         swproglib.c:2908  , swpl_remove_catalog_entry : depath=[var/lib/swbis/catalog/swbis/swbis/0.730/_0]
	*/

	strob_strcpy(dir2, epath);
	swlib_unix_dirtrunc_n(dir2, 2);

	strob_sprintf(btmp, 0,
		"	# Remove all old catalog entries\n"
		" 	(cd \"%s\" && find . -type d -name '_[0-9]*' -exec rm -fr {} \\; 2>/dev/null ) </dev/null \n"
		"	rm -fr \"%s\" 1>&2\n"
		"	mv -f \"%s\" \"%s\" 1>&2\n"
		"	sw_retval=$?\n"
		" 	(cd \"%s\" && rmdir * 2>/dev/null ) </dev/null \n"
		"	case $sw_retval in 0) ;; *) sw_retval=2 ;; esac\n"
		"	dd count=1 bs=512 of=/dev/null 2>/dev/null\n",
		strob_str(dir2),
		depath,
		epath,
		depath,
		strob_str(dir2)
		);

	/* swicol_set_task_idstring(swicol, SWBIS_TS_remove_catalog_entry); */
	ret = swicol_rpsh_task_send_script2(
		swicol,
		ofd, 		/* file descriptor */
		512,		/* null dummy block */
		".",   		/* i.e. stay in the target path */
		strob_str(btmp),/* The actual task script */
		SWBIS_TS_remove_catalog_entry
		);
	if (ret < 0) {
		retval++;
		goto error_out;
	}

	ret = etar_write_trailer_blocks(NULL, ofd, 1);
	if (ret < 0) {
		retval++;
		goto error_out;
	}

	ret = swicol_rpsh_task_expect(swicol, G->g_swi_event_fd,
			SWICOL_TL_9 /*time limit*/);

	if (ret < 0) {
		retval = ret;
		SWLIB_INTERNAL("");
		goto error_out;
	}

	if (ret > 0) {
		retval = ret;
	}

	error_out:

	strob_close(tmp);
	strob_close(tmp2);
	strob_close(btmp);
	strob_close(dir2);
	return retval;
}

char *
swpl_rename_suffix(STROB * buf)
{
	/*
	time_t t;
	struct tm * m;
	t = time(NULL);
	m = localtime(&t);
	strob_sprintf(buf, 0, "swbis_%04d%02d%02dT%02d%02d%02dZ",
			m->tm_year+1900, m->tm_mon + 1, m->tm_mday, m->tm_hour, m->tm_min, m->tm_sec);
	*/
	/* No, I don't like this, just use "swbisold" as the suffix */

	strob_sprintf(buf, 0, "%s", "swbisold");
	return strob_str(buf);
}

void
swpl_tag_volatile_files(SWI_FILELIST * fl)
{
	int ix;
	char * sx;
	int is_volatile;
	char * prefix;
	int type;	

	swi_fl_qsort_forward(fl);
	ix = 0;
	prefix = NULL;
	while ((sx=swi_fl_get_path(fl, ix)) != NULL) {
		type = swi_fl_get_type(fl, ix),
		is_volatile = swi_fl_is_volatile(fl, ix);
		if (prefix == NULL) {
			if (type == DIRTYPE && is_volatile) {
				/* tag every file in this directory as volatile */
				if (prefix) free(prefix);
				prefix = strdup(sx);
			}
		} else {
			if (strstr(sx, prefix) == sx) {
				/* contained in current directory */
				swi_fl_set_is_volatile(fl, (char*)NULL, ix, 1);
			} else {
				/* out of the directory */
				if (prefix) free(prefix);
				prefix = NULL;
			}
		}
		ix++;
	}
	if (prefix) free(prefix);
}

int
swpl_show_file_list(GB * G, SWI_FILELIST * fl)
{
	char * name;
	int ix;

	E_DEBUG("");
	swi_fl_qsort_forward(fl);
	ix = 0;
	while ((name=swi_fl_get_path(fl, ix)) != NULL) {
		sw_l_msg(G, SWC_VERBOSE_1, "%s\n", name);
		ix++;
	}
	E_DEBUG("");
	return 0;
}

int
swpl_make_verify_command_script_fragment(GB * G,
		STROB * scriptbuf,
		SWI_FILELIST * fl,
		char * pax_write_command_key, int be_silent)
{
	int ret;
	STROB * stop_word;
	char * name;
	int ix;
	
	/* Tag every file in a volatile directory as being volatile itself
	   FIXME ??? is this the correct thing to do */

	E_DEBUG("");
	swpl_tag_volatile_files(fl);
	
	stop_word = strob_open(32);

	ret = determine_here_document_stop_word(fl, stop_word);
	if (ret != 0) {
		/* this really should never happen */
		exit(12);
	}

	E_DEBUG("");

	/* sort the files in forward direction */
	swi_fl_qsort_forward(fl);

	strob_sprintf(scriptbuf, STROB_DO_APPEND, "rm_retval=0\n");

	/* Construct the here document of filenames that feed
	   GNU tar's stdin to make an archive */
	/* Something like this:
		(
		cat <<'/tmp/End'
		a
		c
		/tmp/End
		) | tar  cf - --no-recursion --files-from=-
	*/

	/* Start of hear document */
	strob_sprintf(scriptbuf, STROB_DO_APPEND,
		"(\n"
		"cat <<'%s'\n",
		strob_str(stop_word));

	/* priint each file */
	E_DEBUG("");
	ix = 0;
	while ((name=swi_fl_get_path(fl, ix)) != NULL) {
		if (G->devel_verboseM) {
			SWLIB_INFO3("INFO; file=[%s] type=[%c]", name, (int)swi_fl_get_type(fl, ix));
		}
		strob_sprintf(scriptbuf, STROB_DO_APPEND, "%s\n", name);
		ix++;
	}

	/* End of here document */
	E_DEBUG("");
	strob_sprintf(scriptbuf, STROB_DO_APPEND,
		"%s\n"
		") |",
		strob_str(stop_word));


	/* Sanity check on pax_write_command_key */

	if (strcmp(pax_write_command_key, "tar") == 0) {
		;
	} else if (strcmp(pax_write_command_key, "gtar") == 0) {
		;
	} else {
		/* This is an error, should write a warning  */
		pax_write_command_key = "tar";
	}
	
	/* write the tar writing command */


	E_DEBUG("");
	strob_sprintf(scriptbuf, STROB_DO_APPEND,
				" %s %scf - -b 1 --no-recursion --files-from=- %s\n",
				pax_write_command_key,
				(char*)(G->g_verboseG > SWC_VERBOSE_2 ? "v" : ""),
				(be_silent ? "2>/dev/null" : "")
				);
	strob_sprintf(scriptbuf, STROB_DO_APPEND, "retrieve_retval=$?\n");

	E_DEBUG("");
	strob_close(stop_word);
	return 0;
}

int
swpl_ls_fileset_from_iscat(SWI * swi, int ofd, int ls_verbose, int * available_attributes, int skip_volatile)
{
	int retval;
	SWHEADER_STATE state1;
	SWHEADER * indexheader;
	SWHEADER * infoheader;
	SWI_PRODUCT * current_product;
	SWI_XFILE * current_fileset;
	struct new_cpio_header * file_hdr;
	char * next_line;
	char * next_attr;
	char * keyword;
	char * value;
	AHS * info_ahs2;
	int ret;
	STROB * ls_line;
	int file_attribute_usage;
	FILE_DIGS * digs;

	E_DEBUG("");
	file_attribute_usage = 0;
	retval = 0;
	info_ahs2 = ahs_open();
	ls_line = strob_open(60);

	/* FIXME: Eventually support multiple products and filesets  */

	swpl_enforce_one_prod_one_fileset(swi);

	/* Get the current product and fileset, for now, the first ones */

	current_product = swi_package_get_product(swi->swi_pkgM, 0 /* the first one */);
	current_fileset = swi_product_get_fileset(current_product, 0 /* the first one */);

	indexheader = swi_get_global_index_header(swi);

	/* Loop over the INFO file definitions, these are found
		in the SWHEADER for the fileset */

	infoheader = swi_get_fileset_info_header(swi, 0, 0); /* FIXME */
	swheader_store_state(infoheader, NULL);
	swheader_reset(infoheader);

	file_hdr = ahs_vfile_hdr(info_ahs2);
	taru_init_header_digs(file_hdr);
	digs = file_hdr->digsM;
	taru_digs_init(digs, 1 /*enable*/);

        while ((next_line=swheader_get_next_object(infoheader, (int)UCHAR_MAX, (int)UCHAR_MAX))) {

		E_DEBUG2("next_line=%s\n", next_line);
		if (swheaderline_get_type(next_line) != SWPARSE_MD_TYPE_OBJ) {
			/* Sanity check */
			SWBIS_IMPL_ERROR_DIE(1);
		}

		keyword = swheaderline_get_keyword(next_line);

		/* skip control files */

		SWLIB_ASSERT(keyword != NULL);
		if (strcmp(keyword, SW_A_control_file) == 0) {
			continue;
		}

		taru_init_header(file_hdr);
		file_hdr->digsM = digs;
		taru_digs_init(digs, 1 /*enable*/);
		
		swheader_store_state(infoheader, &state1);

		ret = swheader_fileobject2filehdr(infoheader, file_hdr);
		if (ret) {
			SWLIB_FATAL("");
		}

		if (file_attribute_usage == 0) {
			/* first time */
			file_attribute_usage = file_hdr->usage_maskM;
		} else {
			/* construct the minimum attributes that all the files have */
			file_attribute_usage &= file_hdr->usage_maskM;
		}

		if (available_attributes) {
			/* file_attribute_usage are the TARU_UM_* flags and it returns
			   the policy in terms of the LS_LIST_VERBOSE flags  */
			*available_attributes = determine_ls_list_flags(file_attribute_usage, file_hdr);
			/* fprintf(stderr, "=========== %d\n", *available_attributes); */
		}

		swheader_restore_state(infoheader, &state1);

		/*  Here is some example code for accessing and
			printing the file attributes */

		if (0) {
			/* example code */
			value = swheaderline_get_value(next_line, (int*)(NULL));
			swlib_doif_writef(swi->verboseM, SWC_VERBOSE_1,
				(struct sw_logspec *)(NULL), STDERR_FILENO,
				"%s %s\n", keyword, value?value:"");
			while((next_attr=swheader_get_next_attribute(infoheader))) {
				keyword = swheaderline_get_keyword(next_attr);
				value = swheaderline_get_value(next_attr, (int*)(NULL));
				swlib_doif_writef(swi->verboseM, SWC_VERBOSE_1,
					(struct sw_logspec *)(NULL), STDERR_FILENO,
					"%s %s\n", keyword, value?value:"");
			}	
		}

		/* construct the string to print */
		taru_print_tar_ls_list(ls_line, file_hdr, ls_verbose);

		/* Now print the line */
		if (skip_volatile && file_hdr->usage_maskM & TARU_UM_IS_VOLATILE) {
			;
		} else {
			if (ofd >= 0) {
				uxfio_unix_atomic_write(ofd, strob_str(ls_line), strob_strlen(ls_line));
			}
		}
        }

	swheader_restore_state(infoheader, NULL);
	free(digs);
	taru_init_header(file_hdr); /* clears digsM */
	ahs_close(info_ahs2);
	strob_close(ls_line);
	return retval;
}
