/* lxpsf.c -- A Package reading and translation tool.
 */

/*
 * Copyright (C) 1999  James H. Lowe, Jr. 
 * 
 * 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.
 */


#include "swuser_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <utime.h>
#include <time.h>
#include <unistd.h>
#include <utime.h>
#include "um_rpmlib.h"
#include "um_header.h"
#include "swfork.h"
#include "usgetopt.h"
#include "ugetopt_help.h"

#include "uxfio.h"
#include "rpmpsf.h"
#include "swlib.h"
#include "shcmd.h"
#include "swparse.h"
#include "swlex_supp.h"
#include "swparser_global.h"
#include "swutilname.h"
#include "swevents_array.h"
#include "swcommon_options.h"

static void usage (char * progname, FILE*);

YYSTYPE yylval;
int yydebug=0;
int swlex_definition_file = SW_PSF;

#define CHARTRUE  "true";

static
show_version(FILE * fp)
{
    fprintf (fp, "lxpsf (swbis) version " SWBIS_RELEASE "\n");
}

static
void
copyright_info(FILE * fp)
{
	fprintf(fp,  "%s",
	"Copyright (C) 2003,2004,2005 Jim Lowe\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 
void  usage (char * progname, FILE * fp) {
    fprintf (fp, "Usage: lxpsf [options] [file]\n");
    fprintf (fp, " Read any format (only RPM so far) package and write an Posix archive to stdout\n");
    fprintf (fp, " that is able to be converted to a Posix package by swpackage.\n");
    fprintf (fp, "    --psf-form1  default form.\n");
    fprintf (fp, "    --psf-form2  used by swpackage, includes leading path in archive.\n");
    fprintf (fp, "    --create-time=cal_time  Use this time for archive header times\n");
    fprintf (fp, "    -D, --debug-level=TYPE    always use 'link'\n");
    fprintf (fp, "    -x, --use-recursive-fileset Use \"file *\" instead of individual file definitions.\n");
    fprintf (fp, "    -r, --no-leading-path   use \".\" as the leading archive path\n");
    fprintf (fp, "    -B buffertype   mem or file  Mem is default.\n");
    fprintf (fp, "    -H format     archive format: ustar, newc, crc, odc\n");
    fprintf (fp, "    -p, --psf-only   Write the PSF to stdout.\n");
    fprintf (fp, "    -o, --info-only   Write the INFO file for the rpm archive.\n");
    fprintf (fp, "    -r, --no-leading-path.\n");
    fprintf (fp, "    -L, --smart-leading-path  Use leading path for srpm and not rpm.\n");
    fprintf (fp, 
		 "Howto use with swpackage:\n"
		 "     lxpsf --psf-form2 -H ustar | swpackage -W source=- -s@PSF @-\n"
		   );

	fprintf (fp, "lxpsf is an implementation extension utility of the GNU swbis project\n");
	fprintf (fp, "Report bugs to <bug-swbis@gnu.org>\n");
	fprintf (fp, "\n");
	show_version(fp);
	copyright_info(fp);
}


int 
main(int argc, char **argv)
{
	int  nfd;
	TOPSF *topsf;
	int no_leading_path = 0;
	int ret=0;
  	int c=0;
	int info_only = 0;
	int psf_only = 0;
	int tarpipe[2];
	char  *progname;
	char * wopt_create_time = (char*)NULL;
	char *path_prefix;
	char format[21];
	pid_t pid;	
	int bufferflag = UINFILE_UXFIO_BUFTYPE_DYNAMIC_MEM;
	int use_recursive_fileset_spec = 0;
	int single_fileset_override = 0;
	int smart_path=0;        
	int form2 = 0;
	int do_drop_priv = 0;
	char * debug_level = NULL;
	unsigned long create_time = 0;

	progname = argv[0];

	yylval.strb = strob_open (8);
	strcpy(swlex_filename,"none");
	*format='\0';

	while (1)
           {
             int option_index = 0;
             static struct option long_options[] =
             {
               {"psf-only", 0, 0, 'p'},
               {"psf-form1", 0, 0, 'A'},
               {"psf-form2", 0, 0, 'M'},
               {"format", 1, 0, 'H'},
               {"debug_level", 1, 0, 'D'},
               {"no-leading-path", 0, 0, 'r'},
               {"use-recursive-fileset", 0, 0, 'x'},
               {"buffer-type", 1, 0, 'B'},
               {"help", 0, 0, 132},
               {"version", 0, 0, 133},
               {"single-fileset", 0, 0, 134},
               {"util-name", 1, 0, 135},
               {"info-only", 0, 0, 'o'},
               {"smart-leading-path", 0, 0, 'L'},
               {"drop-privilege", 0, 0, 198},
               {"create-time", 1, 0, 199},
               {0, 0, 0, 0}
             };

             c = ugetopt_long (argc, argv, "ArB:pH:xD:oLM", long_options, &option_index);
             if (c == -1)
                 break;

             switch (c)
               {
               case 'A':
		 break;
               case 'M':
		  form2 = 1;
		 break;
               case 'r':
                 no_leading_path=1;        
		 break;
               case 'x':
		 /* Use recursive fileset spec for binary packages */
                 use_recursive_fileset_spec=1;
		 break;
               case 'o':
                 info_only=1;        
		 break;
               case 'L':
                 smart_path=1;        
		 break;
               case 'p':
                 psf_only=1;        
		 break;
	       case 'B':
		 if (!optarg) usage(progname, stderr);
		 if (strstr(optarg, "mem")) {
			bufferflag = UINFILE_UXFIO_BUFTYPE_DYNAMIC_MEM;
		 } else if (strstr(optarg, "file")) {
			bufferflag = UINFILE_UXFIO_BUFTYPE_FILE;
		 }
                 break;
	       case 'D':
		 if (!optarg) usage(progname, stderr);
		 debug_level = strdup(optarg);
                 break;
	       case 'H':
		 if (!optarg) usage(progname, stderr);
		 strncpy(format,optarg, sizeof(format));
		 format[sizeof(format) - 1]='\0';
                 break;
               case 133:
	      	 show_version(stdout);
		 exit(0);
               case 134:
	      	 single_fileset_override = 1;
	       	 break;
               case 135:
	      	 swlib_utilname_set(optarg);
	       	 break;
	       case 132:
                 usage(progname, stdout);
		 exit(0);
		 break;
               case 198:
	      	 do_drop_priv = 1;
	       	 break;
               case 199:
		wopt_create_time = CHARTRUE;
		sscanf(optarg, "%lu", &create_time);
		break;
               default:
                 usage(progname, stderr);
		 exit(1);
                 break;
               }
          }

	if (optind < argc) {
		topsf = topsf_open(argv[optind], bufferflag);
	} else {
		topsf = topsf_open("-", bufferflag);	/* stdin */
	}
	if (!topsf) {
		exit(1);
	}

	if (wopt_create_time) {
		topsf_set_mtime(topsf, (time_t)(create_time));
	}

	topsf->smart_path_ = smart_path;
	path_prefix = topsf_make_package_prefix(topsf, "");
	if (smart_path) {
		strob_strcpy(topsf->control_directoryM, path_prefix);
		path_prefix = ".";
		topsf_set_cwd_prefix(topsf, path_prefix);
	}

	if (form2) {
		strob_strcpy(topsf->control_directoryM, path_prefix);
		path_prefix = ".";
		topsf_set_cwd_prefix(topsf, path_prefix);
		topsf->form_ = TOPSF_PSF_FORM2;
	}

	if (no_leading_path) {
		path_prefix = ".";
	}
	topsf_set_cwd_prefix(topsf, path_prefix);

	topsf->single_fileset_ = single_fileset_override;
	topsf->use_recursive_ = use_recursive_fileset_spec;
	if (debug_level) {
		topsf->debug_link_ = 1;
	}

	if (!strcmp(format,"ustar")) {
		topsf->reverse_links_ = 1;
	}

	if (do_drop_priv) {
		swlib_drop_root_privilege();
	}

	if (psf_only){
		ret=topsf_write_psf(topsf, STDOUT_FILENO, 1 /* do indent */);
	} else if (info_only){
		topsf->info_only_ = 1;
		ret=topsf_write_info(topsf, STDOUT_FILENO, 1 /* do indent */);
	} else {
		/* topsf_write_psf must be run here to cause the file list to be generated
	   	 * ahead of calling topsf_copypass_swacfl_list(topsf) 
		 */
	
		nfd=open("/dev/null", O_RDWR);
		topsf_write_psf(topsf, nfd, 0);
		close(nfd);		

		/* now the file link lists are generated.  
		 */

		if (!strcmp(format,"ustar")) {
			/*
			* Convert output format to ustar.
			*/
			pipe(tarpipe);
			pid = swfork((sigset_t*)(NULL));
			if (pid < 0) {
				fprintf (stderr, "lxpsf: fork failed.\n");
				_exit(1);
			}
			if (pid == 0) {
				close(tarpipe[0]);
				ret=topsf_copypass_swacfl_list(topsf, tarpipe[1]);
				topsf_close(topsf);	
				_exit(ret);
			} else {
				close(tarpipe[1]);
				ret = taru_process_copy_in(tarpipe[0], STDOUT_FILENO);	
			}
		} else {
			ret=topsf_copypass_swacfl_list(topsf, STDOUT_FILENO);
		}

	}
	topsf_close(topsf);	
	exit(ret ? 1 : 0);
}


