Radix cross Linux Package Tools

Package Tools – is a set of utilities to create, install, and update RcL packages

8 Commits   0 Branches   2 Tags
     5         kx 
     5         kx /**********************************************************************
     5         kx 
     5         kx   Copyright 2019 Andrey V.Kosteltsev
     5         kx 
     5         kx   Licensed under the Radix.pro License, Version 1.0 (the "License");
     5         kx   you may not use this file  except  in compliance with the License.
     5         kx   You may obtain a copy of the License at
     5         kx 
     5         kx      https://radix.pro/licenses/LICENSE-1.0-en_US.txt
     5         kx 
     5         kx   Unless required by applicable law or agreed to in writing, software
     5         kx   distributed under the License is distributed on an "AS IS" BASIS,
     5         kx   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
     5         kx   implied.
     5         kx 
     5         kx  **********************************************************************/
     5         kx 
     5         kx #include <config.h>
     5         kx 
     5         kx #include <stdlib.h>
     5         kx #include <stdio.h>
     5         kx #include <sys/types.h>
     5         kx #include <stdint.h>
     5         kx #include <dirent.h>
     5         kx #include <sys/stat.h> /* chmod(2)    */
     5         kx #include <sys/file.h> /* flock(2)    */
     5         kx #include <fcntl.h>
     5         kx #include <linux/limits.h>
     5         kx #include <alloca.h>   /* alloca(3)   */
     5         kx #include <string.h>   /* strdup(3)   */
     5         kx #include <strings.h>  /* index(3)    */
     5         kx #include <libgen.h>   /* basename(3) */
     5         kx #include <ctype.h>    /* tolower(3)  */
     5         kx #include <errno.h>
     5         kx #include <time.h>
     5         kx #include <sys/time.h>
     5         kx #include <pwd.h>
     5         kx #include <grp.h>
     5         kx #include <stdarg.h>
     5         kx #include <unistd.h>
     5         kx 
     5         kx #include <math.h>
     5         kx 
     5         kx #include <sys/wait.h>
     5         kx 
     5         kx #include <sys/resource.h>
     5         kx 
     5         kx #include <signal.h>
     5         kx #if !defined SIGCHLD && defined SIGCLD
     5         kx # define SIGCHLD SIGCLD
     5         kx #endif
     5         kx 
     5         kx #define _GNU_SOURCE
     5         kx #include <getopt.h>
     5         kx 
     5         kx 
     5         kx #include <msglog.h>
     5         kx #include <wrapper.h>
     5         kx #include <system.h>
     5         kx 
     5         kx #include <dlist.h>
     5         kx #include <pkglist.h>
     5         kx 
     5         kx #define PROGRAM_NAME "make-pkglist"
     5         kx 
     5         kx #include <defs.h>
     5         kx 
     5         kx 
     5         kx char *program = PROGRAM_NAME;
     5         kx char *srcdir = NULL, *pkglist_fname = NULL,
     5         kx      *tmpdir = NULL;
     5         kx 
     5         kx char *srclist_fname = NULL;
     5         kx 
     5         kx struct srcpkg_fname
     5         kx {
     5         kx   char *name;
     5         kx   int   line;
     5         kx };
     5         kx 
     5         kx struct dlist *srcpkg_fnames = NULL;
     5         kx 
     5         kx int   exit_status = EXIT_SUCCESS; /* errors counter */
     5         kx char *selfdir     = NULL;
     5         kx 
     5         kx int __done = 0, __child = 0;
     5         kx 
     5         kx enum _output_format {
     5         kx   OFMT_LIST = 0,
     5         kx   OFMT_JSON,
     5         kx 
     5         kx   OFMT_UNKNOWN
     5         kx } output_format = OFMT_LIST;
     5         kx 
     5         kx enum _tree_format tree_format = TFMT_BIN;
     5         kx 
     5         kx enum _input_type {
     5         kx   IFMT_PKG = 0,
     5         kx   IFMT_LOG,
     5         kx 
     5         kx   IFMT_UNKNOWN
     5         kx } input_format = IFMT_UNKNOWN;
     5         kx 
     5         kx enum _priority priority = REQUIRED;
     5         kx 
     5         kx /***************************************************************
     5         kx   Exclude declarations:
     5         kx  */
     5         kx static struct dlist *exclude = NULL;
     5         kx 
     5         kx static void add_exclude( const char *name );
     5         kx static void free_exclude( void );
     5         kx 
     5         kx static void read_exclude_list( const char *optarg );
     5         kx /*
     5         kx   End of exclude declarstions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx /***************************************************************
     5         kx   Source file names functions:
     5         kx  */
     5         kx static struct srcpkg_fname *srcpkg_fname_alloc( const char *name, int line )
     5         kx {
     5         kx   struct srcpkg_fname *fname = NULL;
     5         kx 
     5         kx   fname = (struct srcpkg_fname *)malloc( sizeof( struct srcpkg_fname ) );
     5         kx   if( !fname ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx   fname->name = xstrdup( name );
     5         kx   fname->line = line;
     5         kx 
     5         kx   return fname;
     5         kx }
     5         kx 
     5         kx static void srcpkg_fname_free( struct srcpkg_fname *fname )
     5         kx {
     5         kx   if( fname )
     5         kx   {
     5         kx     if( fname->name ) { free( fname->name ); fname->name    = NULL; }
     5         kx     free( fname );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __srcpkg_fname_free_func( void *data, void *user_data )
     5         kx {
     5         kx   struct srcpkg_fname *fname = (struct srcpkg_fname *)data;
     5         kx   if( fname ) { srcpkg_fname_free( fname ); }
     5         kx }
     5         kx 
     5         kx static void free_srcpkg_fnames( void )
     5         kx {
     5         kx   if( srcpkg_fnames ) { dlist_free( srcpkg_fnames, __srcpkg_fname_free_func ); srcpkg_fnames = NULL; }
     5         kx }
     5         kx 
     5         kx static void add_srcpkg_fname( struct srcpkg_fname *fname )
     5         kx {
     5         kx   if( fname )
     5         kx     srcpkg_fnames = dlist_append( srcpkg_fnames, (void *)fname );
     5         kx }
     5         kx /*
     5         kx   End of source file names functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx 
     5         kx void free_resources()
     5         kx {
     5         kx   if( selfdir )        { free( selfdir );        selfdir        = NULL; }
     5         kx   if( srcdir )         { free( srcdir );         srcdir         = NULL; }
     5         kx   if( srclist_fname )  { free( srclist_fname );  srclist_fname  = NULL; }
     5         kx   if( pkglist_fname )  { free( pkglist_fname );  pkglist_fname  = NULL; }
     5         kx 
     5         kx   free_exclude();
     5         kx 
     5         kx   free_tarballs();
     5         kx   free_packages();
     5         kx   free_srcpkg_fnames();
     5         kx   free_srcpkgs();
     5         kx }
     5         kx 
     5         kx void usage()
     5         kx {
     5         kx   free_resources();
     5         kx 
     5         kx   fprintf( stdout, "\n" );
     5         kx   fprintf( stdout, "Usage: %s [options] <pkglist>\n", program );
     5         kx   fprintf( stdout, "\n" );
     5         kx   fprintf( stdout, "Create Packages List in the installation order from set of PKGLOGs\n" );
     5         kx   fprintf( stdout, "or  set of PACKAGEs placed in the source directory.  If the source\n" );
     5         kx   fprintf( stdout, "directory is not defined then directory of <pkglist>  will be used\n" );
     5         kx   fprintf( stdout, "as source PACKAGE directory.\n" );
     5         kx   fprintf( stdout, "\n" );
     5         kx   fprintf( stdout, "Options:\n" );
     5         kx   fprintf( stdout, "  -h,--help                     Display this information.\n" );
     5         kx   fprintf( stdout, "  -v,--version                  Display the version of %s utility.\n", program );
     5         kx   fprintf( stdout, "  -s,--source=<DIR|pkg|log>     Setup Database packages directory or directory\n" );
     5         kx   fprintf( stdout, "                                where set of PACKAGEs is placed.\n" );
     5         kx   fprintf( stdout, "                                If the source argument is a PACKAGE or PKGLOG\n" );
     5         kx   fprintf( stdout, "                                file, then the source directory will be represented\n" );
     5         kx   fprintf( stdout, "                                as the base directory of the source file excluding\n" );
     5         kx   fprintf( stdout, "                                the group directory if defined.\n" );
     5         kx   fprintf( stdout, "  -F,--files-from=<FILE>        Get file names of PACKAGEs or PKGLOGs from FILE.\n" );
     5         kx   fprintf( stdout, "                                Each line of the FILE must contain a path to the\n" );
     5         kx   fprintf( stdout, "                                PACKAGE or PKGLOG file relative to the directory\n" );
     5         kx   fprintf( stdout, "                                specified by option --source.\n" );
     5         kx   fprintf( stdout, "  -e,--exclude=<pname|plist>    Ignore package with <pname> or the comma\n" );
     5         kx   fprintf( stdout, "                                separated list of package names.\n" );
     5         kx   fprintf( stdout, "  -i,--iformat=<pkg|log>        Input format: PACKAGEs or PKGLOGs.\n" );
     5         kx   fprintf( stdout, "  -o,--oformat=<list|json>      Output format: LIST or JSON.\n" );
     5         kx 
     5         kx   fprintf( stdout, "  -t,--tformat=<dag|bin>        Tree format: DAG or BIN (default BIN).\n" );
     5         kx 
     5         kx   fprintf( stdout, "  -m,--minimize                 Create .min.json files. Applicable\n" );
     5         kx   fprintf( stdout, "                                for JSON output format.\n" );
     5         kx 
     5         kx   fprintf( stdout, "  -p,--prioriy=<PRIORITY>       Default install priority: REQ|REC|OPT|SKP.\n" );
     5         kx   fprintf( stdout, "  -w,--hardware=<HARDWARE>      Hardware Name used for JSON output format.\n" );
     5         kx   fprintf( stdout, "  -H,--htmlroot=<HTMLROOT>      Optional Requires tree HTMLROOT name used\n" );
     5         kx   fprintf( stdout, "                                for JSON output format.\n" );
     5         kx 
     5         kx   fprintf( stdout, "\n" );
     5         kx   fprintf( stdout, "Parameter:\n" );
     5         kx   fprintf( stdout, "  <pkglist>                     Output PKGLIST file name or a target\n"  );
     5         kx   fprintf( stdout, "                                directory to save output PKGLIST.\n"  );
     5         kx   fprintf( stdout, "\n" );
     5         kx   fprintf( stdout, "If HTMLROOT is not defined by option --htmlroot then HTMLROOT will be set\n" );
     5         kx   fprintf( stdout, "as basename of target <pkglist> file in lower case without extension.\n" );
     5         kx   fprintf( stdout, "\n" );
     5         kx 
     5         kx   exit( EXIT_FAILURE );
     5         kx }
     5         kx 
     5         kx void to_lowercase( char *s )
     5         kx {
     5         kx   char *p = s;
     5         kx   while( p && *p ) { int c = *p; *p = tolower( c ); ++p; }
     5         kx }
     5         kx 
     5         kx void to_uppercase( char *s )
     5         kx {
     5         kx   char *p = s;
     5         kx   while( p && *p ) { int c = *p; *p = toupper( c ); ++p; }
     5         kx }
     5         kx 
     5         kx void version()
     5         kx {
     5         kx   char *upper = NULL;
     5         kx 
     5         kx   upper = (char *)alloca( strlen( program ) + 1 );
     5         kx 
     5         kx   strcpy( (char *)upper, (const char *)program );
     5         kx   to_uppercase( upper );
     5         kx 
     5         kx   fprintf( stdout, "%s (%s) %s\n", program, upper, PROGRAM_VERSION );
     5         kx 
     5         kx   fprintf( stdout, "Copyright (C) 2019 Andrey V.Kosteltsev.\n" );
     5         kx   fprintf( stdout, "This is free software.   There is NO warranty; not even\n" );
     5         kx   fprintf( stdout, "for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" );
     5         kx   fprintf( stdout, "\n" );
     5         kx 
     5         kx   free_resources();
     5         kx   exit( EXIT_SUCCESS );
     5         kx }
     5         kx 
     5         kx 
     5         kx static void remove_trailing_slash( char *dir )
     5         kx {
     5         kx   char *s;
     5         kx 
     5         kx   if( !dir || dir[0] == '\0' ) return;
     5         kx 
     5         kx   s = dir + strlen( dir ) - 1;
     5         kx   while( *s == '/' )
     5         kx   {
     5         kx     *s = '\0'; --s;
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static int _mkdir_p( const char *dir, const mode_t mode )
     5         kx {
     5         kx   char  *buf;
     5         kx   char  *p = NULL;
     5         kx   struct stat sb;
     5         kx 
     5         kx   if( !dir ) return -1;
     5         kx 
     5         kx   buf = (char *)alloca( strlen( dir ) + 1 );
     5         kx   strcpy( buf, dir );
     5         kx 
     5         kx   remove_trailing_slash( buf );
     5         kx 
     5         kx   /* check if path exists and is a directory */
     5         kx   if( stat( buf, &sb ) == 0 )
     5         kx   {
     5         kx     if( S_ISDIR(sb.st_mode) )
     5         kx     {
     5         kx       return 0;
     5         kx     }
     5         kx   }
     5         kx 
     5         kx   /* mkdir -p */
     5         kx   for( p = buf + 1; *p; ++p )
     5         kx   {
     5         kx     if( *p == '/' )
     5         kx     {
     5         kx       *p = 0;
     5         kx       /* test path */
     5         kx       if( stat( buf, &sb ) != 0 )
     5         kx       {
     5         kx         /* path does not exist - create directory */
     5         kx         if( mkdir( buf, mode ) < 0 )
     5         kx         {
     5         kx           return -1;
     5         kx         }
     5         kx       } else if( !S_ISDIR(sb.st_mode) )
     5         kx       {
     5         kx         /* not a directory */
     5         kx         return -1;
     5         kx       }
     5         kx       *p = '/';
     5         kx     }
     5         kx   }
     5         kx 
     5         kx   /* test path */
     5         kx   if( stat( buf, &sb ) != 0 )
     5         kx   {
     5         kx     /* path does not exist - create directory */
     5         kx     if( mkdir( buf, mode ) < 0 )
     5         kx     {
     5         kx       return -1;
     5         kx     }
     5         kx   } else if( !S_ISDIR(sb.st_mode) )
     5         kx   {
     5         kx     /* not a directory */
     5         kx     return -1;
     5         kx   }
     5         kx 
     5         kx   return 0;
     5         kx }
     5         kx 
     5         kx 
     5         kx static void _rm_tmpdir( const char *dirpath )
     5         kx {
     5         kx   DIR    *dir;
     5         kx   char   *path;
     5         kx   size_t  len;
     5         kx 
     5         kx   struct stat    path_sb, entry_sb;
     5         kx   struct dirent *entry;
     5         kx 
     5         kx   if( stat( dirpath, &path_sb ) == -1 )
     5         kx   {
     5         kx     return; /* stat returns error code; errno is set */
     5         kx   }
     5         kx 
     5         kx   if( S_ISDIR(path_sb.st_mode) == 0 )
     5         kx   {
     5         kx     return; /* dirpath is not a directory */
     5         kx   }
     5         kx 
     5         kx   if( (dir = opendir(dirpath) ) == NULL )
     5         kx   {
     5         kx     return; /* Cannot open direcroty; errno is set */
     5         kx   }
     5         kx 
     5         kx   len = strlen( dirpath );
     5         kx 
     5         kx   while( (entry = readdir( dir )) != NULL)
     5         kx   {
     5         kx 
     5         kx     /* skip entries '.' and '..' */
     5         kx     if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
     5         kx 
     5         kx     /* determinate a full name of an entry */
     5         kx     path = alloca( len + strlen( entry->d_name ) + 2 );
     5         kx     strcpy( path, dirpath );
     5         kx     strcat( path, "/" );
     5         kx     strcat( path, entry->d_name );
     5         kx 
     5         kx     if( stat( path, &entry_sb ) == 0 )
     5         kx     {
     5         kx       if( S_ISDIR(entry_sb.st_mode) )
     5         kx       {
     5         kx         /* recursively remove a nested directory */
     5         kx         _rm_tmpdir( path );
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         /* remove a file object */
     5         kx         (void)unlink( path );
     5         kx       }
     5         kx     }
     5         kx     /* else { stat() returns error code; errno is set; and we have to continue the loop } */
     5         kx 
     5         kx   }
     5         kx 
     5         kx   /* remove the devastated directory and close the object of this directory */
     5         kx   (void)rmdir( dirpath );
     5         kx 
     5         kx   closedir( dir );
     5         kx }
     5         kx 
     5         kx 
     5         kx static char *_mk_tmpdir( void )
     5         kx {
     5         kx   char   *buf = NULL, *p, *tmp = "/tmp";
     5         kx   size_t  len = 0, size = 0;
     5         kx 
     5         kx   (void)umask( S_IWGRP | S_IWOTH ); /* octal 022 */
     5         kx 
     5         kx   /* Get preferred directory for tmp files */
     5         kx   if( (p = getenv( "TMP" )) != NULL ) {
     5         kx     tmp = p;
     5         kx   }
     5         kx   else if( (p = getenv( "TEMP" )) != NULL ) {
     5         kx     tmp = p;
     5         kx   }
     5         kx 
     5         kx   size = strlen( tmp ) + strlen( DISTRO_NAME ) + strlen( program ) + 12;
     5         kx 
     5         kx   buf = (char *)malloc( size );
     5         kx   if( !buf ) return NULL;
     5         kx 
     5         kx   len = snprintf( buf, size, (const char *)"%s/%s/%s-%.7u", tmp, DISTRO_NAME, program, getpid() );
     5         kx   if( len == 0 || len == size - 1 )
     5         kx   {
     5         kx     free( buf ); return NULL;
     5         kx   }
     5         kx 
     5         kx   _rm_tmpdir( (const char *)&buf[0] );
     5         kx 
     5         kx   if( _mkdir_p( buf, S_IRWXU | S_IRWXG | S_IRWXO ) == 0 )
     5         kx   {
     5         kx     return buf;
     5         kx   }
     5         kx 
     5         kx   free( buf ); return NULL;
     5         kx }
     5         kx 
     5         kx 
     5         kx 
     5         kx void fatal_error_actions( void )
     5         kx {
     5         kx   logmsg( errlog, MSG_NOTICE, "Free resources on FATAL error..." );
     5         kx   if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
     5         kx   free_resources();
     5         kx }
     5         kx 
     5         kx void sigint( int signum )
     5         kx {
     5         kx   (void)signum;
     5         kx 
     5         kx   if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
     5         kx   free_resources();
     5         kx }
     5         kx 
     5         kx void sigchld( int signum )
     5         kx {
     5         kx   pid_t  pid = 0;
     5         kx   int    status;
     5         kx 
     5         kx   (void)signum;
     5         kx 
     5         kx   while( (pid = waitpid( -1, &status, WNOHANG )) > 0 )
     5         kx   {
     5         kx     ; /* One of children with 'pid' is terminated */
     5         kx 
     5         kx     if( WIFEXITED( status ) )
     5         kx     {
     5         kx       if( (int) WEXITSTATUS (status) > 0 )
     5         kx       {
     5         kx         ++exit_status; /* printf( "Child %d returned non zero status: %d\n", pid, (int)WEXITSTATUS (status) ); */
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         ; /* printf( "Child %d terminated with status: %d\n", pid, (int)WEXITSTATUS (status) ); */
     5         kx       }
     5         kx     }
     5         kx     else if( WIFSIGNALED( status ) )
     5         kx     {
     5         kx       ++exit_status; /* printf( "Child %d terminated on signal: %d\n", pid,  WTERMSIG( status ) ); */
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       ++exit_status; /* printf( "Child %d terminated on unknown reason\n", pid ); */
     5         kx     }
     5         kx 
     5         kx   }
     5         kx 
     5         kx   if( pid == -1 && errno == ECHILD )
     5         kx   {
     5         kx     /* No child processes: */
     5         kx     __done = 1;
     5         kx   }
     5         kx   return;
     5         kx }
     5         kx 
     5         kx 
     5         kx static void set_signal_handlers()
     5         kx {
     5         kx   struct sigaction  sa;
     5         kx   sigset_t          set;
     5         kx 
     5         kx   memset( &sa, 0, sizeof( sa ) );
     5         kx   sa.sa_handler = sigint;          /* TERM, INT */
     5         kx   sa.sa_flags = SA_RESTART;
     5         kx   sigemptyset( &set );
     5         kx   sigaddset( &set, SIGTERM );
     5         kx   sigaddset( &set, SIGINT );
     5         kx   sa.sa_mask = set;
     5         kx   sigaction( SIGTERM, &sa, NULL );
     5         kx   sigaction( SIGINT, &sa,  NULL );
     5         kx 
     5         kx   /* System V fork+wait does not work if SIGCHLD is ignored */
     5         kx   memset( &sa, 0, sizeof( sa ) );
     5         kx   sa.sa_handler = sigchld;         /* CHLD */
     5         kx   sa.sa_flags = SA_RESTART;
     5         kx   sigemptyset( &set );
     5         kx   sigaddset( &set, SIGCHLD );
     5         kx   sa.sa_mask = set;
     5         kx   sigaction( SIGCHLD, &sa, NULL );
     5         kx 
     5         kx   memset( &sa, 0, sizeof( sa ) );  /* ignore SIGPIPE */
     5         kx   sa.sa_handler = SIG_IGN;
     5         kx   sa.sa_flags = 0;
     5         kx   sigaction( SIGPIPE, &sa, NULL );
     5         kx }
     5         kx 
     5         kx 
     5         kx static enum _input_type check_input_file( char *uncompress, const char *fname )
     5         kx {
     5         kx   struct stat st;
     5         kx   size_t pkglog_size = 0;
     5         kx   unsigned char buf[8];
     5         kx   int rc, fd;
     5         kx 
     5         kx   /* SIGNATURES: https://www.garykessler.net/library/file_sigs.html */
     5         kx 
     5         kx   if( uncompress )
     5         kx   {
     5         kx     *uncompress = '\0';
     5         kx   }
     5         kx 
     5         kx   if( stat( fname, &st ) == -1 )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot access %s file: %s", basename( (char *)fname ), strerror( errno ) );
     5         kx   }
     5         kx 
     5         kx   pkglog_size = st.st_size;
     5         kx 
     5         kx   if( (fd = open( fname, O_RDONLY )) == -1 )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot open %s file: %s", basename( (char *)fname ), strerror( errno ) );
     5         kx   }
     5         kx 
     5         kx   rc = (int)read( fd, (void *)&buf[0], 7 );
     5         kx   if( rc != 7 )
     5         kx   {
     5         kx     close( fd ); return IFMT_UNKNOWN;
     5         kx   }
     5         kx   buf[7] = '\0';
     5         kx 
     5         kx   /* TEXT */
     5         kx   if( !strncmp( (const char *)&buf[0], "PACKAGE", 7 ) )
     5         kx   {
     5         kx     close( fd ); return IFMT_LOG;
     5         kx   }
     5         kx 
     5         kx   /* GZ */
     5         kx   if( buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x08 )
     5         kx   {
     5         kx     if( uncompress ) { *uncompress = 'x'; }
     5         kx     close( fd ); return IFMT_PKG;
     5         kx   }
     5         kx 
     5         kx   /* BZ2 */
     5         kx   if( buf[0] == 0x42 && buf[1] == 0x5A && buf[2] == 0x68 )
     5         kx   {
     5         kx     if( uncompress ) { *uncompress = 'j'; }
     5         kx     close( fd ); return IFMT_PKG;
     5         kx   }
     5         kx 
     5         kx   /* XZ */
     5         kx   if( buf[0] == 0xFD && buf[1] == 0x37 && buf[2] == 0x7A &&
     5         kx       buf[3] == 0x58 && buf[4] == 0x5A && buf[5] == 0x00   )
     5         kx   {
     5         kx     if( uncompress ) { *uncompress = 'J'; }
     5         kx     close( fd ); return IFMT_PKG;
     5         kx   }
     5         kx 
     5         kx   if( pkglog_size > 262 )
     5         kx   {
     5         kx     if( lseek( fd, 257, SEEK_SET ) == -1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot check signature of %s file: %s", basename( (char *)fname ), strerror( errno ) );
     5         kx     }
     5         kx     rc = (int)read( fd, &buf[0], 5 );
     5         kx     if( rc != 5 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot read signature of %s file", basename( (char *)fname ) );
     5         kx     }
     5         kx     /* TAR */
     5         kx     if( buf[0] == 0x75 && buf[1] == 0x73 && buf[2] == 0x74 && buf[3] == 0x61 && buf[4] == 0x72 )
     5         kx     {
     5         kx       close( fd ); return IFMT_PKG;
     5         kx     }
     5         kx   }
     5         kx 
     5         kx   close( fd ); return IFMT_UNKNOWN;
     5         kx }
     5         kx 
     5         kx 
     5         kx void get_args( int argc, char *argv[] )
     5         kx {
     5         kx   const char* short_options = "hvme:s:F:o:i:t:p:w:H:";
     5         kx 
     5         kx   const struct option long_options[] =
     5         kx   {
     5         kx     { "help",        no_argument,       NULL, 'h' },
     5         kx     { "version",     no_argument,       NULL, 'v' },
     5         kx     { "minimize",    no_argument,       NULL, 'm' },
     5         kx     { "exclude",     required_argument, NULL, 'e' },
     5         kx     { "source",      required_argument, NULL, 's' },
     5         kx     { "files-from",  required_argument, NULL, 'F' },
     5         kx     { "oformat",     required_argument, NULL, 'o' },
     5         kx     { "iformat",     required_argument, NULL, 'i' },
     5         kx     { "tformat",     required_argument, NULL, 't' },
     5         kx     { "priority",    required_argument, NULL, 'p' },
     5         kx     { "hardware",    required_argument, NULL, 'w' },
     5         kx     { "htmlroot",    required_argument, NULL, 'H' },
     5         kx     { NULL,          0,                 NULL,  0  }
     5         kx   };
     5         kx 
     5         kx   int ret;
     5         kx   int option_index = 0;
     5         kx 
     5         kx   while( (ret = getopt_long( argc, argv, short_options, long_options, &option_index )) != -1 )
     5         kx   {
     5         kx     switch( ret )
     5         kx     {
     5         kx       case 'h':
     5         kx       {
     5         kx         usage();
     5         kx         break;
     5         kx       }
     5         kx       case 'v':
     5         kx       {
     5         kx         version();
     5         kx         break;
     5         kx       }
     5         kx       case 'm':
     5         kx       {
     5         kx         minimize = 1;
     5         kx         break;
     5         kx       }
     5         kx 
     5         kx       case 'e':
     5         kx       {
     5         kx         if( optarg != NULL )
     5         kx         {
     5         kx           read_exclude_list( (const char *)optarg );
     5         kx         }
     5         kx         else
     5         kx           /* option is present but without value */
     5         kx           usage();
     5         kx         break;
     5         kx       }
     5         kx 
     5         kx       case 's':
     5         kx       {
     5         kx         if( optarg != NULL )
     5         kx         {
     5         kx           srcdir = xstrdup( (const char *)optarg );
     5         kx           remove_trailing_slash( srcdir );
     5         kx         }
     5         kx         else
     5         kx           /* option is present but without value */
     5         kx           usage();
     5         kx         break;
     5         kx       }
     5         kx       case 'F':
     5         kx       {
     5         kx         if( optarg != NULL )
     5         kx         {
     5         kx           srclist_fname = xstrdup( (const char *)optarg );
     5         kx           remove_trailing_slash( srclist_fname );
     5         kx         }
     5         kx         else
     5         kx           /* option is present but without value */
     5         kx           usage();
     5         kx         break;
     5         kx       }
     5         kx       case 'o':
     5         kx       {
     5         kx         char *fmt = (char *)alloca( strlen( optarg ) + 1 );
     5         kx 
     5         kx         strcpy( (char *)fmt, (const char *)optarg );
     5         kx         to_lowercase( fmt );
     5         kx 
     5         kx         if(      !strcmp( fmt, "list" ) ) { output_format = OFMT_LIST; }
     5         kx         else if( !strcmp( fmt, "json" ) ) { output_format = OFMT_JSON; }
     5         kx         else
     5         kx         {
     5         kx           ERROR( "Invalid output format: %s", fmt );
     5         kx           usage();
     5         kx         }
     5         kx         break;
     5         kx       }
     5         kx       case 'i':
     5         kx       {
     5         kx         char *fmt = (char *)alloca( strlen( optarg ) + 1 );
     5         kx 
     5         kx         strcpy( (char *)fmt, (const char *)optarg );
     5         kx         to_lowercase( fmt );
     5         kx 
     5         kx         if(      !strcmp( fmt, "pkg" ) ) { input_format = IFMT_PKG; }
     5         kx         else if( !strcmp( fmt, "log" ) ) { input_format = IFMT_LOG; }
     5         kx         else
     5         kx         {
     5         kx           ERROR( "Invalid input format: %s", fmt );
     5         kx           usage();
     5         kx         }
     5         kx         break;
     5         kx       }
     5         kx       case 't':
     5         kx       {
     5         kx         char *fmt = (char *)alloca( strlen( optarg ) + 1 );
     5         kx 
     5         kx         strcpy( (char *)fmt, (const char *)optarg );
     5         kx         to_lowercase( fmt );
     5         kx 
     5         kx         if(      !strcmp( fmt, "bin" ) ) { tree_format = TFMT_BIN; }
     5         kx         else if( !strcmp( fmt, "dag" ) ) { tree_format = TFMT_DAG; }
     5         kx         else
     5         kx         {
     5         kx           ERROR( "Invalid tree format: %s", fmt );
     5         kx           usage();
     5         kx         }
     5         kx         break;
     5         kx       }
     5         kx       case 'p':
     5         kx       {
     5         kx         char *p = (char *)alloca( strlen( optarg ) + 1 );
     5         kx 
     5         kx         strcpy( (char *)p, (const char *)optarg );
     5         kx         to_lowercase( p );
     5         kx 
     5         kx         if(      !strcmp( p, "required" )    || !strcmp( p, "req" ) ) { priority = REQUIRED;    }
     5         kx         else if( !strcmp( p, "recommended" ) || !strcmp( p, "rec" ) ) { priority = RECOMMENDED; }
     5         kx         else if( !strcmp( p, "optional" )    || !strcmp( p, "opt" ) ) { priority = OPTIONAL;    }
     5         kx         else if( !strcmp( p, "skip" )        || !strcmp( p, "skp" ) ) { priority = SKIP;        }
     5         kx         else
     5         kx         {
     5         kx           ERROR( "Invalid default install priority: %s", p );
     5         kx           usage();
     5         kx         }
     5         kx         break;
     5         kx       }
     5         kx       case 'w':
     5         kx       {
     5         kx         char *hw = (char *)alloca( strlen( optarg ) + 1 );
     5         kx 
     5         kx         strcpy( (char *)hw, (const char *)optarg );
     5         kx         to_lowercase( hw );
     5         kx 
     5         kx         hardware = xstrdup( (const char *)hw );
     5         kx         break;
     5         kx       }
     5         kx       case 'H':
     5         kx       {
     5         kx         char *root = (char *)alloca( strlen( optarg ) + 1 );
     5         kx 
     5         kx         strcpy( (char *)root, (const char *)optarg );
     5         kx         to_lowercase( root );
     5         kx 
     5         kx         htmlroot = xstrdup( (const char *)root );
     5         kx         break;
     5         kx       }
     5         kx 
     5         kx       case '?': default:
     5         kx       {
     5         kx         usage();
     5         kx         break;
     5         kx       }
     5         kx     }
     5         kx   }
     5         kx 
     5         kx 
     5         kx   /* last command line argument is the output PKGLIST file */
     5         kx   if( optind < argc )
     5         kx   {
     5         kx     struct stat st;
     5         kx     char   *buf = NULL;
     5         kx     size_t  hrl = 0;
     5         kx 
     5         kx     bzero( (void *)&st, sizeof( struct stat ) );
     5         kx 
     5         kx     if( htmlroot ) { hrl = strlen( htmlroot ); }
     5         kx 
     5         kx     buf = (char *)malloc( strlen( (const char *)argv[optind] ) + hrl + 10 );
     5         kx     if( !buf )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot allocate memory" );
     5         kx     }
     5         kx 
     5         kx     (void)strcpy( buf, (const char *)argv[optind++] );
     5         kx     remove_trailing_slash( (char *)&buf[0] );
     5         kx 
     5         kx     stat( (const char *)&buf[0], &st ); /* Do not check return status */
     5         kx 
     5         kx     if( S_ISDIR(st.st_mode) )
     5         kx     {
     5         kx       if( ! srcdir )
     5         kx       {
     5         kx         srcdir = xstrdup( (const char *)&buf[0] );
     5         kx       }
     5         kx       /* Add .pkglist or .json to the output dir name: */
     5         kx       if( htmlroot )
     5         kx       {
     5         kx         (void)strcat( buf, "/" );
     5         kx         (void)strcat( buf, htmlroot );
     5         kx 
     5         kx         if( output_format == OFMT_LIST )
     5         kx           (void)strcat( buf, ".pkglist" );
     5         kx         else
     5         kx           (void)strcat( buf, ".json" );
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         if( output_format == OFMT_LIST )
     5         kx           (void)strcat( buf, "/.pkglist" );
     5         kx         else
     5         kx           (void)strcat( buf, "/.json" );
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     if( !hardware )
     5         kx       hardware = xstrdup( "unknown" );
     5         kx 
     5         kx     /* Check output directory; set srcdir and htmlroot if needed */
     5         kx     {
     5         kx       char   *d, *f, *fname;
     5         kx       size_t  len;
     5         kx 
     5         kx       if( !rindex( (const char *)&buf[0], '/' ) )
     5         kx       {
     5         kx         d = ".";
     5         kx         f = (char *)&buf[0];
     5         kx         len = strlen( f ) + 3;
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         f = basename( (char *)&buf[0] );
     5         kx         d =  dirname( (char *)&buf[0] ); /* dirname() cuts the filename from buf[] */
     5         kx         len = strlen( d ) + strlen( f ) + 2;
     5         kx       }
     5         kx 
     5         kx       fname = (char *)alloca( len );
     5         kx       (void)sprintf( fname, "%s/%s", d, f );
     5         kx 
     5         kx       if( stat( (const char *)d, &st ) == -1 )
     5         kx       {
     5         kx         FATAL_ERROR( "Cannot access output '%s' directory: %s", d, strerror( errno ) );
     5         kx       }
     5         kx 
     5         kx       pkglist_fname = xstrdup( (const char *)fname );
     5         kx       if( pkglist_fname == NULL ) { usage(); }
     5         kx 
     5         kx       if( !srcdir ) { srcdir = xstrdup( (const char *)d ); }
     5         kx 
     5         kx       if( !htmlroot )
     5         kx       {
     5         kx         char *p = NULL;
     5         kx         if( (p = rindex( (const char *)f, '.' )) && p != f )
     5         kx         {
     5         kx           *p = '\0';
     5         kx           to_lowercase( f );
     5         kx           htmlroot = xstrdup( (const char *)f );
     5         kx         }
     5         kx         else if( *f != '.' )
     5         kx         {
     5         kx           to_lowercase( f );
     5         kx           htmlroot = xstrdup( (const char *)f );
     5         kx         }
     5         kx         else
     5         kx         {
     5         kx           htmlroot = xstrdup( (const char *)hardware );
     5         kx         }
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     free( buf );
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     usage();
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx /***************************************************************
     5         kx   Exclude functions:
     5         kx  */
     5         kx static void add_exclude( const char *name )
     5         kx {
     5         kx   exclude = dlist_append( exclude, (void *)xstrdup( name ) );
     5         kx }
     5         kx 
     5         kx static void __free_exclude( void *data, void *user_data )
     5         kx {
     5         kx   if( data ) { free( data ); }
     5         kx }
     5         kx 
     5         kx static void free_exclude( void )
     5         kx {
     5         kx   if( exclude ) { dlist_free( exclude, __free_exclude ); exclude = NULL; }
     5         kx }
     5         kx 
     5         kx static int __compare_exclude( const void *a, const void *b )
     5         kx {
     5         kx   return strncmp( (const char *)a, (const char *)b, (size_t)strlen((const char *)b) );
     5         kx }
     5         kx 
     5         kx static const char *find_exclude( const char *name )
     5         kx {
     5         kx   struct dlist *node = NULL;
     5         kx 
     5         kx   if( !exclude || !name ) return NULL;
     5         kx 
     5         kx   node = dlist_find_data( exclude, __compare_exclude, (const void *)name );
     5         kx   if( node )
     5         kx   {
     5         kx     return (const char *)node->data;
     5         kx   }
     5         kx 
     5         kx   return NULL;
     5         kx }
     5         kx 
     5         kx static void read_exclude_list( const char *optarg )
     5         kx {
     5         kx   char *name = NULL, *p = NULL;
     5         kx 
     5         kx   name = p = (char *)optarg;
     5         kx 
     5         kx   if( !p || *p == '\0' ) return;
     5         kx 
     5         kx   while( *p == ',' ) { *p = '\0'; ++p; }
     5         kx   name = p;
     5         kx 
     5         kx   while( p && *p != '\0' )
     5         kx   {
     5         kx     ++p;
     5         kx 
     5         kx     if( *p == ',' )
     5         kx     {
     5         kx       while( *p == ',' ) { *p = '\0'; ++p; }
     5         kx       if( name && *name != '\0' ) { add_exclude( (const char *)name ); }
     5         kx       name = p;
     5         kx     }
     5         kx 
     5         kx     if( *p == '\0' )
     5         kx     {
     5         kx       if( name && *name != '\0' ) { add_exclude( (const char *)name ); }
     5         kx     }
     5         kx   }
     5         kx }
     5         kx /*
     5         kx   End of exclude functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx 
     5         kx /***************************************************************
     5         kx   Extract functions:
     5         kx  */
     5         kx static void _extract_pkglog( const char *group, const char *fname )
     5         kx {
     5         kx   enum _input_type  type = IFMT_UNKNOWN;
     5         kx   char              uncompress = '\0';
     5         kx 
     5         kx   type = check_input_file( &uncompress, fname );
     5         kx 
     5         kx   if( type == IFMT_PKG )
     5         kx   {
     5         kx     int   len = 0;
     5         kx     char *tmp= NULL, *cmd = NULL, *tgz = NULL;
     5         kx 
     5         kx     tmp = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)tmp, PATH_MAX );
     5         kx 
     5         kx     if( group ) { (void)sprintf( &tmp[0], "%s/%s", tmpdir, group ); }
     5         kx     else        { (void)sprintf( &tmp[0], "%s", tmpdir ); }
     5         kx 
     5         kx     if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
     5         kx     {
     5         kx       ERROR( "Cannot save PKGLOG from '%s' file", basename( (char *)fname ) );
     5         kx       free( tmp );
     5         kx       return;
     5         kx     }
     5         kx 
     5         kx     cmd = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)cmd, PATH_MAX );
     5         kx 
     5         kx     len = snprintf( &cmd[0], PATH_MAX, "%s/pkglog -d %s %s > /dev/null 2>&1", selfdir, tmp, fname );
     5         kx     if( len == 0 || len == PATH_MAX - 1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot get PKGLOG from %s file", basename( (char *)fname ) );
     5         kx     }
     5         kx     (void)sys_exec_command( cmd );
     5         kx     ++__child;
     5         kx 
     5         kx     tgz = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !tgz ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)tgz, PATH_MAX );
     5         kx     (void)sprintf( &tgz[0], "%s/%s", group, basename( (char *)fname ) );
     5         kx     add_tarball( (char *)&tgz[0] );
     5         kx 
     5         kx     free( tmp );
     5         kx     free( cmd );
     5         kx     free( tgz );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void _search_packages( const char *dirpath, const char *grp )
     5         kx {
     5         kx   DIR    *dir;
     5         kx   char   *path;
     5         kx   size_t  len;
     5         kx 
     5         kx   struct stat    path_sb, entry_sb;
     5         kx   struct dirent *entry;
     5         kx 
     5         kx   if( stat( dirpath, &path_sb ) == -1 )
     5         kx   {
     5         kx     FATAL_ERROR( "%s: Cannot stat Setup Database or destination directory", dirpath );
     5         kx   }
     5         kx 
     5         kx   if( S_ISDIR(path_sb.st_mode) == 0 )
     5         kx   {
     5         kx     FATAL_ERROR( "%s: Setup Database or destination is not a directory", dirpath );
     5         kx   }
     5         kx 
     5         kx   if( (dir = opendir(dirpath) ) == NULL )
     5         kx   {
     5         kx     FATAL_ERROR( "Canot access %s directory: %s", dirpath, strerror( errno ) );
     5         kx   }
     5         kx 
     5         kx   len = strlen( dirpath );
     5         kx 
     5         kx   while( (entry = readdir( dir )) != NULL)
     5         kx   {
     5         kx     /* skip entries '.' and '..' */
     5         kx     if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
     5         kx 
     5         kx     /* determinate a full name of an entry */
     5         kx     path = alloca( len + strlen( entry->d_name ) + 2 );
     5         kx 
     5         kx     strcpy( path, dirpath );
     5         kx     strcat( path, "/" );
     5         kx     strcat( path, entry->d_name );
     5         kx 
     5         kx     if( stat( path, &entry_sb ) == 0 )
     5         kx     {
     5         kx       if( S_ISREG(entry_sb.st_mode) )
     5         kx       {
     5         kx         _extract_pkglog( grp, (const char *)path );
     5         kx       }
     5         kx       if( S_ISDIR(entry_sb.st_mode) && grp == NULL )
     5         kx       {
     5         kx         _search_packages( (const char *)path, (const char *)entry->d_name );
     5         kx       }
     5         kx     }
     5         kx     /* else { stat() returns error code; errno is set; and we have to continue the loop } */
     5         kx   }
     5         kx 
     5         kx   closedir( dir );
     5         kx }
     5         kx 
     5         kx /**************************************************************
     5         kx   extract_pkglogs() - returns number of extracted PKGLOGS
     5         kx                       or 0 if no packages found in the srcdir.
     5         kx                       The exit_status has been set.
     5         kx  */
     5         kx int extract_pkglogs( void )
     5         kx {
     5         kx   int ret = 0;
     5         kx 
     5         kx   __done = 0; __child = 0;
     5         kx 
     5         kx   _search_packages( (const char *)srcdir, NULL );
     5         kx 
     5         kx   if( __child > 0 )
     5         kx   {
     5         kx     while( !__done ) usleep( 1 );
     5         kx     ret = __child;
     5         kx   }
     5         kx 
     5         kx   __done = 0; __child = 0;
     5         kx 
     5         kx   return ret;
     5         kx }
     5         kx /*
     5         kx   End of Extract functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx 
     5         kx /***************************************************************
     5         kx   Copy functions:
     5         kx  */
     5         kx static void _copy_pkglog( const char *group, const char *fname )
     5         kx {
     5         kx   enum _input_type  type = IFMT_UNKNOWN;
     5         kx   char              uncompress = '\0';
     5         kx 
     5         kx   type = check_input_file( &uncompress, fname );
     5         kx 
     5         kx   if( type == IFMT_LOG )
     5         kx   {
     5         kx     int   len = 0;
     5         kx     char *tmp= NULL, *cmd = NULL;
     5         kx 
     5         kx     tmp = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)tmp, PATH_MAX );
     5         kx 
     5         kx     if( group ) { (void)sprintf( &tmp[0], "%s/%s", tmpdir, group ); }
     5         kx     else        { (void)sprintf( &tmp[0], "%s", tmpdir ); }
     5         kx 
     5         kx     if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
     5         kx     {
     5         kx       ERROR( "Cannot copy '%s' PKGLOG file", basename( (char *)fname ) );
     5         kx       free( tmp );
     5         kx       return;
     5         kx     }
     5         kx 
     5         kx     cmd = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)cmd, PATH_MAX );
     5         kx 
     5         kx     len = snprintf( &cmd[0], PATH_MAX, "cp %s %s/ > /dev/null 2>&1", fname, tmp );
     5         kx     if( len == 0 || len == PATH_MAX - 1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot copy %s PKGLOG file", basename( (char *)fname ) );
     5         kx     }
     5         kx     (void)sys_exec_command( cmd );
     5         kx     ++__child;
     5         kx 
     5         kx     free( tmp );
     5         kx     free( cmd );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void _search_pkglogs( const char *dirpath, const char *grp )
     5         kx {
     5         kx   DIR    *dir;
     5         kx   char   *path;
     5         kx   size_t  len;
     5         kx 
     5         kx   struct stat    path_sb, entry_sb;
     5         kx   struct dirent *entry;
     5         kx 
     5         kx   if( stat( dirpath, &path_sb ) == -1 )
     5         kx   {
     5         kx     FATAL_ERROR( "%s: Cannot stat Setup Database or destination directory", dirpath );
     5         kx   }
     5         kx 
     5         kx   if( S_ISDIR(path_sb.st_mode) == 0 )
     5         kx   {
     5         kx     FATAL_ERROR( "%s: Setup Database or destination is not a directory", dirpath );
     5         kx   }
     5         kx 
     5         kx   if( (dir = opendir(dirpath) ) == NULL )
     5         kx   {
     5         kx     FATAL_ERROR( "Canot access %s directory: %s", dirpath, strerror( errno ) );
     5         kx   }
     5         kx 
     5         kx   len = strlen( dirpath );
     5         kx 
     5         kx   while( (entry = readdir( dir )) != NULL)
     5         kx   {
     5         kx     /* skip entries '.' and '..' */
     5         kx     if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
     5         kx 
     5         kx     /* determinate a full name of an entry */
     5         kx     path = alloca( len + strlen( entry->d_name ) + 2 );
     5         kx 
     5         kx     strcpy( path, dirpath );
     5         kx     strcat( path, "/" );
     5         kx     strcat( path, entry->d_name );
     5         kx 
     5         kx     if( stat( path, &entry_sb ) == 0 )
     5         kx     {
     5         kx       if( S_ISREG(entry_sb.st_mode) )
     5         kx       {
     5         kx         _copy_pkglog( grp, (const char *)path );
     5         kx       }
     5         kx       if( S_ISDIR(entry_sb.st_mode) && grp == NULL )
     5         kx       {
     5         kx         _search_pkglogs( (const char *)path, (const char *)entry->d_name );
     5         kx       }
     5         kx     }
     5         kx     /* else { stat() returns error code; errno is set; and we have to continue the loop } */
     5         kx   }
     5         kx 
     5         kx   closedir( dir );
     5         kx }
     5         kx 
     5         kx /***********************************************************
     5         kx   copy_pkglogs() - returns number of copied PKGLOGS
     5         kx                    or 0 if no packages found in the srcdir.
     5         kx                    The exit_status has been set.
     5         kx  */
     5         kx int copy_pkglogs( void )
     5         kx {
     5         kx   int ret = 0;
     5         kx 
     5         kx   __done = 0; __child = 0;
     5         kx 
     5         kx   _search_pkglogs( (const char *)srcdir, NULL );
     5         kx 
     5         kx   if( __child > 0 )
     5         kx   {
     5         kx     while( !__done ) usleep( 1 );
     5         kx     ret = __child;
     5         kx   }
     5         kx 
     5         kx   __done = 0; __child = 0;
     5         kx 
     5         kx   return ret;
     5         kx }
     5         kx /*
     5         kx   Enf of Copy functions.
     5         kx  ***************************************************************/
     5         kx 
     5         kx 
     5         kx /***********************************************************
     5         kx   Remove leading spaces and take non-space characters only:
     5         kx   (Especialy for pkginfo lines)
     5         kx  */
     5         kx static char *skip_spaces( char *s )
     5         kx {
     5         kx   char *q, *p = (char *)0;
     5         kx 
     5         kx   if( !s || *s == '\0' ) return p;
     5         kx 
     5         kx   p = s;
     5         kx 
     5         kx   while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p;
     5         kx   while(  *q != ' ' && *q != '\t'  && *q != '\0' ) { ++q; } *q = '\0';
     5         kx 
     5         kx   if( *p == '\0' ) return (char *)0;
     5         kx 
     5         kx   return( xstrdup( (const char *)p ) );
     5         kx }
     5         kx 
     5         kx /*******************************
     5         kx   remove spaces at end of line:
     5         kx  */
     5         kx static void skip_eol_spaces( char *s )
     5         kx {
     5         kx   char *p = (char *)0;
     5         kx 
     5         kx   if( !s || *s == '\0' ) return;
     5         kx 
     5         kx   p = s + strlen( s ) - 1;
     5         kx   while( isspace( *p ) ) { *p-- = '\0'; }
     5         kx }
     5         kx 
     5         kx static size_t read_usize( char *s )
     5         kx {
     5         kx   size_t  size = 0;
     5         kx   size_t  mult = 1;
     5         kx   double  sz = 0.0;
     5         kx 
     5         kx   char    suffix;
     5         kx   char   *q, *p = (char *)0;
     5         kx 
     5         kx   if( !s || *s == '\0' ) return size;
     5         kx 
     5         kx   p = s;
     5         kx 
     5         kx   while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p;
     5         kx   while(  *q != ' ' && *q != '\t'  && *q != '\0' ) { ++q; } *q = '\0';
     5         kx 
     5         kx   if( *p == '\0' ) return size;
     5         kx 
     5         kx   --q;
     5         kx   suffix = *q;
     5         kx   switch( suffix )
     5         kx   {
     5         kx     /* by default size calculates in KiB - 1024 Bytes (du -s -h .) */
     5         kx     case 'G':
     5         kx     case 'g':
     5         kx       mult = 1024 * 1024;
     5         kx       *q = '\0';
     5         kx       break;
     5         kx     case 'M':
     5         kx     case 'm':
     5         kx       mult = 1024;
     5         kx       *q = '\0';
     5         kx       break;
     5         kx     case 'K':
     5         kx     case 'k':
     5         kx       *q = '\0';
     5         kx       break;
     5         kx     default:
     5         kx       break;
     5         kx   }
     5         kx 
     5         kx   if( sscanf( p, "%lg", &sz ) != 1 ) return size;
     5         kx 
     5         kx   return (size_t)round( sz * (double)mult );
     5         kx }
     5         kx 
     5         kx static int read_total_files( char *s )
     5         kx {
     5         kx   int   n = 0;
     5         kx   char *q, *p = (char *)0;
     5         kx 
     5         kx   if( !s || *s == '\0' ) return n;
     5         kx 
     5         kx   p = s;
     5         kx 
     5         kx   while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p;
     5         kx   while(  *q != ' ' && *q != '\t'  && *q != '\0' ) { ++q; } *q = '\0';
     5         kx 
     5         kx   if( *p == '\0' ) return n;
     5         kx 
     5         kx   if( sscanf( p, "%u", &n ) != 1 ) return 0;
     5         kx 
     5         kx   return n;
     5         kx }
     5         kx 
     5         kx 
     5         kx static struct pkg *input_package( const char *pkginfo_fname )
     5         kx {
     5         kx   char *ln      = NULL;
     5         kx   char *line    = NULL;
     5         kx 
     5         kx   FILE *pkginfo = NULL;
     5         kx 
     5         kx   struct pkg *pkg = NULL;
     5         kx   char *pkgname = NULL, *pkgver = NULL, *group = NULL;
     5         kx 
     5         kx   if( pkginfo_fname != NULL )
     5         kx   {
     5         kx     pkginfo = fopen( (const char *)pkginfo_fname, "r" );
     5         kx     if( !pkginfo )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot open %s file", pkginfo_fname );
     5         kx     }
     5         kx   }
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot allocate memory" );
     5         kx   }
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, pkginfo )) )
     5         kx   {
     5         kx     char *match = NULL;
     5         kx 
     5         kx     ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx     skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx     if( (match = strstr( ln, "pkgname" )) && match == ln ) {
     5         kx       char *p = index( match, '=' ) + 1;
     5         kx       if( p != NULL ) pkgname = skip_spaces( p );
     5         kx     }
     5         kx     if( (match = strstr( ln, "pkgver" )) && match == ln ) {
     5         kx       char *p = index( match, '=' ) + 1;
     5         kx       if( p != NULL ) pkgver = skip_spaces( p );
     5         kx     }
     5         kx     if( (match = strstr( ln, "group" )) && match == ln ) {
     5         kx       char *p = index( match, '=' ) + 1;
     5         kx       if( p != NULL ) group = skip_spaces( p );
     5         kx     }
     5         kx   }
     5         kx 
     5         kx   free( line );
     5         kx 
     5         kx   if( pkgname && pkgver )
     5         kx   {
     5         kx     pkg = pkg_alloc();
     5         kx     if( pkg )
     5         kx     {
     5         kx       if( group )
     5         kx       {
     5         kx         pkg->group = group;
     5         kx       }
     5         kx       pkg->name    = pkgname;
     5         kx       pkg->version = pkgver;
     5         kx     }
     5         kx 
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     if( group )      free( group );
     5         kx     if( pkgname )    free( pkgname );
     5         kx     if( pkgver )     free( pkgver );
     5         kx 
     5         kx     FATAL_ERROR( "Invalid input .PKGINFO file" );
     5         kx   }
     5         kx 
     5         kx   fclose( pkginfo );
     5         kx 
     5         kx   return( pkg );
     5         kx }
     5         kx 
     5         kx 
     5         kx 
     5         kx static void get_short_description( char *buf, const char *line )
     5         kx {
     5         kx   char *s, *p, *q;
     5         kx 
     5         kx   if( buf ) { buf[0] = '\0'; s = buf; }
     5         kx   if( !line || line[0] == '\0' ) return;
     5         kx 
     5         kx   p = index( line, '(' );
     5         kx   q = index( line, ')' );
     5         kx   if( p && q && q > p )
     5         kx   {
     5         kx     ++p;
     5         kx     while( *p && p < q )
     5         kx     {
     5         kx       *s = *p;
     5         kx       ++p; ++s;
     5         kx     }
     5         kx     *s = '\0';
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     /*
     5         kx       If short description declaration is incorrect at first line
     5         kx       of description; then we take whole first line of description:
     5         kx      */
     5         kx     p = index( line, ':' ); ++p;
     5         kx     while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; }
     5         kx     strcpy( buf, p );
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static int get_references_section( int *start, int *stop, unsigned int *cnt, FILE *log )
     5         kx {
     5         kx   int ret = -1, found = 0;
     5         kx 
     5         kx   if( !start || !stop || !cnt ) return ret;
     5         kx 
     5         kx   if( log != NULL )
     5         kx   {
     5         kx     char *ln   = NULL;
     5         kx     char *line = NULL;
     5         kx 
     5         kx     line = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !line )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot allocate memory" );
     5         kx     }
     5         kx 
     5         kx     ++ret;
     5         kx     *start = 0; *stop = 0;
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       char *match = NULL;
     5         kx 
     5         kx       if( (match = strstr( ln, "REFERENCE COUNTER:" )) && match == ln ) /* at start of line only */
     5         kx       {
     5         kx         *start = ret + 1;
     5         kx         ++found;
     5         kx 
     5         kx         /* Get reference counter */
     5         kx         {
     5         kx           unsigned int count;
     5         kx           int          rc;
     5         kx 
     5         kx           ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx           skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx           rc = sscanf( ln, "REFERENCE COUNTER: %u", &count );
     5         kx           if( rc == 1 && cnt != NULL )
     5         kx           {
     5         kx             *cnt = count;
     5         kx           }
     5         kx         }
     5         kx       }
     5         kx       if( (match = strstr( ln, "REQUIRES:" )) && match == ln )
     5         kx       {
     5         kx         *stop = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx 
     5         kx       ++ret;
     5         kx     }
     5         kx 
     5         kx     free( line );
     5         kx 
     5         kx     ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
     5         kx 
     5         kx     fseek( log, 0, SEEK_SET );
     5         kx   }
     5         kx 
     5         kx   return( ret );
     5         kx }
     5         kx 
     5         kx static int get_requires_section( int *start, int *stop, FILE *log )
     5         kx {
     5         kx   int ret = -1, found = 0;
     5         kx 
     5         kx   if( !start || !stop ) return ret;
     5         kx 
     5         kx   if( log != NULL )
     5         kx   {
     5         kx     char *ln   = NULL;
     5         kx     char *line = NULL;
     5         kx 
     5         kx     line = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !line )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot allocate memory" );
     5         kx     }
     5         kx 
     5         kx     ++ret;
     5         kx     *start = 0; *stop = 0;
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       char *match = NULL;
     5         kx 
     5         kx       if( (match = strstr( ln, "REQUIRES:" )) && match == ln ) /* at start of line only */
     5         kx       {
     5         kx         *start = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx       if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln )
     5         kx       {
     5         kx         *stop = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx 
     5         kx       ++ret;
     5         kx     }
     5         kx 
     5         kx     free( line );
     5         kx 
     5         kx     ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
     5         kx 
     5         kx     fseek( log, 0, SEEK_SET );
     5         kx   }
     5         kx 
     5         kx   return( ret );
     5         kx }
     5         kx 
     5         kx static int get_description_section( int *start, int *stop, FILE *log )
     5         kx {
     5         kx   int ret = -1, found = 0;
     5         kx 
     5         kx   if( !start || !stop ) return ret;
     5         kx 
     5         kx   if( log != NULL )
     5         kx   {
     5         kx     char *ln   = NULL;
     5         kx     char *line = NULL;
     5         kx 
     5         kx     line = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !line )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot allocate memory" );
     5         kx     }
     5         kx 
     5         kx     ++ret;
     5         kx     *start = 0; *stop = 0;
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       char *match = NULL;
     5         kx 
     5         kx       if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln ) /* at start of line only */
     5         kx       {
     5         kx         *start = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx       if( (match = strstr( ln, "RESTORE LINKS:" )) && match == ln )
     5         kx       {
     5         kx         *stop = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx 
     5         kx       ++ret;
     5         kx     }
     5         kx 
     5         kx     free( line );
     5         kx 
     5         kx     ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
     5         kx 
     5         kx     fseek( log, 0, SEEK_SET );
     5         kx   }
     5         kx 
     5         kx   return( ret );
     5         kx }
     5         kx 
     5         kx static int get_restore_links_section( int *start, int *stop, FILE *log )
     5         kx {
     5         kx   int ret = -1, found = 0;
     5         kx 
     5         kx   if( !start || !stop ) return ret;
     5         kx 
     5         kx   if( log != NULL )
     5         kx   {
     5         kx     char *ln   = NULL;
     5         kx     char *line = NULL;
     5         kx 
     5         kx     line = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !line )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot allocate memory" );
     5         kx     }
     5         kx 
     5         kx     ++ret;
     5         kx     *start = 0; *stop = 0;
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       char *match = NULL;
     5         kx 
     5         kx       if( (match = strstr( ln, "RESTORE LINKS:" )) && match == ln ) /* at start of line only */
     5         kx       {
     5         kx         *start = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx       if( (match = strstr( ln, "INSTALL SCRIPT:" )) && match == ln )
     5         kx       {
     5         kx         *stop = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx 
     5         kx       ++ret;
     5         kx     }
     5         kx 
     5         kx     free( line );
     5         kx 
     5         kx     ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
     5         kx 
     5         kx     fseek( log, 0, SEEK_SET );
     5         kx   }
     5         kx 
     5         kx   return( ret );
     5         kx }
     5         kx 
     5         kx 
     5         kx static int get_install_script_section( int *start, int *stop, FILE *log )
     5         kx {
     5         kx   int ret = -1, found = 0;
     5         kx 
     5         kx   if( !start || !stop ) return ret;
     5         kx 
     5         kx   if( log != NULL )
     5         kx   {
     5         kx     char *ln   = NULL;
     5         kx     char *line = NULL;
     5         kx 
     5         kx     line = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !line )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot allocate memory" );
     5         kx     }
     5         kx 
     5         kx     ++ret;
     5         kx     *start = 0; *stop = 0;
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       char *match = NULL;
     5         kx 
     5         kx       if( (match = strstr( ln, "INSTALL SCRIPT:" )) && match == ln ) /* at start of line only */
     5         kx       {
     5         kx         *start = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx       if( (match = strstr( ln, "FILE LIST:" )) && match == ln )
     5         kx       {
     5         kx         *stop = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx 
     5         kx       ++ret;
     5         kx     }
     5         kx 
     5         kx     free( line );
     5         kx 
     5         kx     ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
     5         kx 
     5         kx     fseek( log, 0, SEEK_SET );
     5         kx   }
     5         kx 
     5         kx   return( ret );
     5         kx }
     5         kx 
     5         kx 
     5         kx static int get_file_list_section( int *start, int *stop, FILE *log )
     5         kx {
     5         kx   int ret = -1, found = 0;
     5         kx 
     5         kx   if( !start || !stop ) return ret;
     5         kx 
     5         kx   if( log != NULL )
     5         kx   {
     5         kx     char *ln   = NULL;
     5         kx     char *line = NULL;
     5         kx 
     5         kx     line = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !line )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot allocate memory" );
     5         kx     }
     5         kx 
     5         kx     ++ret;
     5         kx     *start = 0; *stop = 0;
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       char *match = NULL;
     5         kx 
     5         kx       if( (match = strstr( ln, "FILE LIST:" )) && match == ln ) /* at start of line only */
     5         kx       {
     5         kx         *start = ret + 1;
     5         kx         ++found;
     5         kx       }
     5         kx 
     5         kx       ++ret;
     5         kx     }
     5         kx 
     5         kx     free( line );
     5         kx 
     5         kx     ret = ( found == 1 ) ? 0 : 1; /* 0 - success; 1 - not found. */
     5         kx 
     5         kx     fseek( log, 0, SEEK_SET );
     5         kx   }
     5         kx 
     5         kx   return( ret );
     5         kx }
     5         kx 
     5         kx 
     5         kx int read_pkginfo( FILE *log, struct package *package )
     5         kx {
     5         kx   int ret = -1;
     5         kx 
     5         kx   char *ln   = NULL;
     5         kx   char *line = NULL;
     5         kx 
     5         kx   char           *pkgname_pattern = "PACKAGE NAME:",
     5         kx                   *pkgver_pattern = "PACKAGE VERSION:",
     5         kx                     *arch_pattern = "ARCH:",
     5         kx               *distroname_pattern = "DISTRO:",
     5         kx                *distrover_pattern = "DISTRO VERSION:",
     5         kx                    *group_pattern = "GROUP:",
     5         kx                      *url_pattern = "URL:",
     5         kx                  *license_pattern = "LICENSE:",
     5         kx        *uncompressed_size_pattern = "UNCOMPRESSED SIZE:",
     5         kx              *total_files_pattern = "TOTAL FILES:";
     5         kx 
     5         kx 
     5         kx   if( !log || !package ) return ret;
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot allocate memory" );
     5         kx   }
     5         kx 
     5         kx   ++ret;
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx   {
     5         kx     char *match = NULL;
     5         kx 
     5         kx     ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx     skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx     if( (match = strstr( ln, pkgname_pattern )) && match == ln ) /* at start of line only */
     5         kx     {
     5         kx       package->pkginfo->name = skip_spaces( ln + strlen( pkgname_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, pkgver_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->version = skip_spaces( ln + strlen( pkgver_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, arch_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->arch = skip_spaces( ln + strlen( arch_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, distroname_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->distro_name = skip_spaces( ln + strlen( distroname_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, distrover_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->distro_version = skip_spaces( ln + strlen( distrover_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, group_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->group = skip_spaces( ln + strlen( group_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, url_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->url = skip_spaces( ln + strlen( url_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, license_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->license = skip_spaces( ln + strlen( license_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, uncompressed_size_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->uncompressed_size = read_usize( ln + strlen( uncompressed_size_pattern ) );
     5         kx     }
     5         kx     if( (match = strstr( ln, total_files_pattern )) && match == ln )
     5         kx     {
     5         kx       package->pkginfo->total_files = read_total_files( ln + strlen( total_files_pattern ) );
     5         kx     }
     5         kx 
     5         kx     if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln )
     5         kx     {
     5         kx       char *buf = NULL;
     5         kx 
     5         kx       buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx       if( !buf )
     5         kx       {
     5         kx         FATAL_ERROR( "Cannot allocate memory" );
     5         kx       }
     5         kx 
     5         kx       /* Get short_description from PACKAGE DESCRIPTION */
     5         kx       ln = fgets( line, PATH_MAX, log );
     5         kx       ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
     5         kx 
     5         kx       bzero( (void *)buf, PATH_MAX );
     5         kx       get_short_description( buf, (const char *)line );
     5         kx       if( buf[0] != '\0' )
     5         kx       {
     5         kx         package->pkginfo->short_description = xstrdup( (const char *)buf );
     5         kx       }
     5         kx       free( buf );
     5         kx     }
     5         kx 
     5         kx   } /* End of while() */
     5         kx 
     5         kx   free( line );
     5         kx 
     5         kx   if( package->pkginfo->name           == NULL ) ++ret;
     5         kx   if( package->pkginfo->version        == NULL ) ++ret;
     5         kx   if( package->pkginfo->arch           == NULL ) ++ret;
     5         kx   if( package->pkginfo->distro_name    == NULL ) ++ret;
     5         kx   if( package->pkginfo->distro_version == NULL ) ++ret;
     5         kx   /* group can be equal to NULL */
     5         kx 
     5         kx   fseek( log, 0, SEEK_SET );
     5         kx 
     5         kx   return( ret );
     5         kx }
     5         kx 
     5         kx 
     5         kx static unsigned int read_references( FILE *log, int start, unsigned int *cnt, struct package *package )
     5         kx {
     5         kx   char *ln   = NULL;
     5         kx   char *line = NULL;
     5         kx   char *p = NULL, *group = NULL, *name = NULL, *version = NULL;
     5         kx   int   n = 1;
     5         kx 
     5         kx   unsigned int counter, pkgs = 0;
     5         kx 
     5         kx   struct pkg *pkg = NULL;
     5         kx 
     5         kx   if( !log || !cnt || *cnt == 0 || !package ) return pkgs;
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot allocate memory" );
     5         kx   }
     5         kx 
     5         kx   counter = *cnt;
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
     5         kx 
     5         kx   n = 0;
     5         kx   while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx   {
     5         kx     ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx     skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx     if( strstr( ln, "REQUIRES:" ) ) break; /* if cnt greater than real number of references */
     5         kx 
     5         kx     if( n < counter )
     5         kx     {
     5         kx       if( (p = index( (const char *)ln, '=' )) )
     5         kx       {
     5         kx         *p = '\0'; version = ++p;
     5         kx         if( (p = index( (const char *)ln, '/' )) )
     5         kx         {
     5         kx           *p = '\0'; name = ++p; group = (char *)&ln[0];
     5         kx         }
     5         kx         else
     5         kx         {
     5         kx           name  = (char *)&ln[0]; group = NULL;
     5         kx         }
     5         kx 
     5         kx         pkg = pkg_alloc();
     5         kx 
     5         kx         if( group ) pkg->group = xstrdup( (const char *)group );
     5         kx         pkg->name    = xstrdup( (const char *)name );
     5         kx         pkg->version = xstrdup( (const char *)version );
     5         kx 
     5         kx         add_reference( package, pkg );
     5         kx         ++pkgs;
     5         kx       }
     5         kx       ++n;
     5         kx     }
     5         kx     else
     5         kx       break;
     5         kx   }
     5         kx 
     5         kx   free( line );
     5         kx 
     5         kx   fseek( log, 0, SEEK_SET );
     5         kx 
     5         kx   *cnt = pkgs;
     5         kx 
     5         kx   return pkgs;
     5         kx }
     5         kx 
     5         kx 
     5         kx static unsigned int read_requires( FILE *log, int start, int stop, struct package *package )
     5         kx {
     5         kx   char *ln   = NULL;
     5         kx   char *line = NULL;
     5         kx   char *p = NULL, *group = NULL, *name = NULL, *version = NULL;
     5         kx   int   n = 1;
     5         kx 
     5         kx   unsigned int pkgs = 0;
     5         kx 
     5         kx   struct pkg *pkg = NULL;
     5         kx 
     5         kx   if( !log || !package ) return pkgs;
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot allocate memory" );
     5         kx   }
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
     5         kx 
     5         kx   if( start && start < stop )
     5         kx   {
     5         kx     ++n; /* skip section header */
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx       skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx       if( strstr( ln, "PACKAGE DESCRIPTION:" ) ) break; /* if (stop - start - 1) greater than real number of requiress */
     5         kx 
     5         kx       if( (n > start) && (n < stop) )
     5         kx       {
     5         kx         if( (p = index( (const char *)ln, '=' )) )
     5         kx         {
     5         kx           *p = '\0'; version = ++p;
     5         kx           if( (p = index( (const char *)ln, '/' )) )
     5         kx           {
     5         kx             *p = '\0'; name = ++p; group = (char *)&ln[0];
     5         kx           }
     5         kx           else
     5         kx           {
     5         kx             name  = (char *)&ln[0]; group = NULL;
     5         kx           }
     5         kx 
     5         kx           pkg = pkg_alloc();
     5         kx 
     5         kx           if( group ) pkg->group = xstrdup( (const char *)group );
     5         kx           pkg->name    = xstrdup( (const char *)name );
     5         kx           pkg->version = xstrdup( (const char *)version );
     5         kx 
     5         kx           add_required( package, pkg );
     5         kx           ++pkgs;
     5         kx         }
     5         kx 
     5         kx       }
     5         kx       ++n;
     5         kx     }
     5         kx 
     5         kx   } /* End if( start && start < stop ) */
     5         kx 
     5         kx   free( line );
     5         kx 
     5         kx   fseek( log, 0, SEEK_SET );
     5         kx 
     5         kx   return pkgs;
     5         kx }
     5         kx 
     5         kx 
     5         kx static unsigned int read_description( FILE *log, int start, int stop, struct package *package )
     5         kx {
     5         kx   char *ln      = NULL;
     5         kx   char *line    = NULL;
     5         kx   char *pattern = NULL;
     5         kx   int   n = 1;
     5         kx 
     5         kx   char  *tmp_fname = NULL;
     5         kx   FILE  *tmp = NULL;
     5         kx 
     5         kx   unsigned int lines = 0;
     5         kx 
     5         kx   if( !log || !package ) return lines;
     5         kx 
     5         kx   tmp_fname = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx   bzero( (void *)tmp_fname, PATH_MAX );
     5         kx   (void)sprintf( (char *)&tmp_fname[0], "%s/.DESCRIPTION", tmpdir );
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line )    { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx   pattern = (char *)malloc( (size_t)strlen( package->pkginfo->name ) + 2 );
     5         kx   if( !pattern ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx   (void)sprintf( pattern, "%s:", package->pkginfo->name );
     5         kx 
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
     5         kx 
     5         kx   if( start && start < stop )
     5         kx   {
     5         kx     ++n; /* skip section header */
     5         kx 
     5         kx     tmp = fopen( (const char *)&tmp_fname[0], "w" );
     5         kx     if( !tmp )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[0] ) );
     5         kx     }
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       char *match = NULL;
     5         kx 
     5         kx       ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx       skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx       if( strstr( ln, "RESTORE LINKS:" ) ) break; /* if (stop - start - 1) greater than real number of lines */
     5         kx 
     5         kx       if( (n > start) && (n < stop) )
     5         kx       {
     5         kx         /*
     5         kx           skip non-significant spaces at beginning of line
     5         kx           and print lines started with 'pkgname:'
     5         kx          */
     5         kx         if( (match = strstr( ln, pattern )) && lines < DESCRIPTION_NUMBER_OF_LINES )
     5         kx         {
     5         kx           int mlen   = strlen( match ), plen = strlen( pattern );
     5         kx           int length = ( mlen > plen )  ? (mlen - plen - 1) : 0 ;
     5         kx 
     5         kx           if( length > DESCRIPTION_LENGTH_OF_LINE )
     5         kx           {
     5         kx             /* WARNING( "Package DESCRIPTION contains lines with length greater than %d characters", DESCRIPTION_LENGTH_OF_LINE ); */
     5         kx             match[plen + 1 + DESCRIPTION_LENGTH_OF_LINE] = '\0'; /* truncating description line  */
     5         kx             skip_eol_spaces( match );                            /* remove spaces at end-of-line */
     5         kx           }
     5         kx           fprintf( tmp, "%s\n", match );
     5         kx           ++lines;
     5         kx         }
     5         kx 
     5         kx       }
     5         kx       ++n;
     5         kx     }
     5         kx 
     5         kx     if( lines < (unsigned int)DESCRIPTION_NUMBER_OF_LINES )
     5         kx     {
     5         kx       /* WARNING( "Package DESCRIPTION contains less than %d lines", DESCRIPTION_NUMBER_OF_LINES ); */
     5         kx       while( lines < (unsigned int)DESCRIPTION_NUMBER_OF_LINES )
     5         kx       {
     5         kx         fprintf( tmp, "%s\n", pattern );
     5         kx         ++lines;
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     fflush( tmp );
     5         kx     fclose( tmp );
     5         kx 
     5         kx   } /* End if( start && start < stop ) */
     5         kx 
     5         kx   free( pattern );
     5         kx   free( line );
     5         kx 
     5         kx   fseek( log, 0, SEEK_SET );
     5         kx 
     5         kx   /* read temporary saved description */
     5         kx   {
     5         kx     struct stat sb;
     5         kx     size_t size = 0;
     5         kx     int    fd;
     5         kx 
     5         kx     char  *desc = NULL;
     5         kx 
     5         kx     if( stat( tmp_fname, &sb ) == -1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) );
     5         kx     }
     5         kx     size = (size_t)sb.st_size;
     5         kx 
     5         kx     if( size )
     5         kx     {
     5         kx       ssize_t rc = 0;
     5         kx 
     5         kx       desc = (char *)malloc( size + 1 );
     5         kx       if( !desc ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)desc, size + 1 );
     5         kx 
     5         kx       if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 )
     5         kx       {
     5         kx         FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) );
     5         kx       }
     5         kx 
     5         kx       rc = read( fd, (void *)desc, size );
     5         kx       if( rc != (ssize_t)size ) { ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) ); }
     5         kx 
     5         kx       package->description = desc;
     5         kx 
     5         kx       close( fd );
     5         kx     }
     5         kx 
     5         kx   }
     5         kx 
     5         kx   (void)unlink( tmp_fname );
     5         kx   free( tmp_fname );
     5         kx 
     5         kx   return lines;
     5         kx }
     5         kx 
     5         kx 
     5         kx static unsigned int read_restore_links( FILE *log, int start, int stop, struct package *package )
     5         kx {
     5         kx   char *ln      = NULL;
     5         kx   char *line    = NULL;
     5         kx   int   n = 1;
     5         kx 
     5         kx   char  *tmp_fname = NULL;
     5         kx   FILE  *tmp = NULL;
     5         kx 
     5         kx   unsigned int lines = 0;
     5         kx 
     5         kx   if( !log || !package ) return lines;
     5         kx 
     5         kx   tmp_fname = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx   bzero( (void *)tmp_fname, PATH_MAX );
     5         kx   (void)sprintf( (char *)&tmp_fname[0], "%s/.RESTORELINKS", tmpdir );
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line )    { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
     5         kx 
     5         kx   if( start && start < stop )
     5         kx   {
     5         kx     ++n; /* skip section header */
     5         kx 
     5         kx     tmp = fopen( (const char *)&tmp_fname[0], "w" );
     5         kx     if( !tmp )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[0] ) );
     5         kx     }
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx       skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx       if( strstr( ln, "INSTALL SCRIPT:" ) ) break; /* if (stop - start - 1) greater than real number of lines */
     5         kx 
     5         kx       if( (n > start) && (n < stop) )
     5         kx       {
     5         kx         fprintf( tmp, "%s\n", ln );
     5         kx         ++lines;
     5         kx       }
     5         kx       ++n;
     5         kx     }
     5         kx 
     5         kx     fflush( tmp );
     5         kx     fclose( tmp );
     5         kx 
     5         kx   } /* End if( start && start < stop ) */
     5         kx 
     5         kx   free( line );
     5         kx 
     5         kx   fseek( log, 0, SEEK_SET );
     5         kx 
     5         kx   /* read temporary saved description */
     5         kx   {
     5         kx     struct stat sb;
     5         kx     size_t size = 0;
     5         kx     int    fd;
     5         kx 
     5         kx     char  *links = NULL;
     5         kx 
     5         kx     if( stat( tmp_fname, &sb ) == -1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) );
     5         kx     }
     5         kx     size = (size_t)sb.st_size;
     5         kx 
     5         kx     if( size )
     5         kx     {
     5         kx       ssize_t rc = 0;
     5         kx 
     5         kx       links = (char *)malloc( size + 1 );
     5         kx       if( !links ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)links, size + 1 );
     5         kx 
     5         kx       if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 )
     5         kx       {
     5         kx         FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) );
     5         kx       }
     5         kx 
     5         kx       rc = read( fd, (void *)links, size );
     5         kx       if( rc != (ssize_t)size ) { ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) ); }
     5         kx 
     5         kx       package->restore_links = links;
     5         kx 
     5         kx       close( fd );
     5         kx     }
     5         kx 
     5         kx   }
     5         kx 
     5         kx   (void)unlink( tmp_fname );
     5         kx   free( tmp_fname );
     5         kx 
     5         kx   return lines;
     5         kx }
     5         kx 
     5         kx 
     5         kx static unsigned int read_install_script( FILE *log, int start, int stop, struct package *package )
     5         kx {
     5         kx   char *ln      = NULL;
     5         kx   char *line    = NULL;
     5         kx   int   n = 1;
     5         kx 
     5         kx   char  *tmp_fname = NULL;
     5         kx   FILE  *tmp = NULL;
     5         kx 
     5         kx   unsigned int lines = 0;
     5         kx 
     5         kx   if( !log || !package ) return lines;
     5         kx 
     5         kx   tmp_fname = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx   bzero( (void *)tmp_fname, PATH_MAX );
     5         kx   (void)sprintf( (char *)&tmp_fname[0], "%s/.INSTALL", tmpdir );
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line )    { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
     5         kx 
     5         kx   if( start && start < stop )
     5         kx   {
     5         kx     ++n; /* skip section header */
     5         kx 
     5         kx     tmp = fopen( (const char *)&tmp_fname[0], "w" );
     5         kx     if( !tmp )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[0] ) );
     5         kx     }
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx       skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx       if( strstr( ln, "FILE LIST:" ) ) break; /* if (stop - start - 1) greater than real number of lines */
     5         kx 
     5         kx       if( (n > start) && (n < stop) )
     5         kx       {
     5         kx         fprintf( tmp, "%s\n", ln );
     5         kx         ++lines;
     5         kx       }
     5         kx       ++n;
     5         kx     }
     5         kx 
     5         kx     fflush( tmp );
     5         kx     fclose( tmp );
     5         kx 
     5         kx   } /* End if( start && start < stop ) */
     5         kx 
     5         kx   free( line );
     5         kx 
     5         kx   fseek( log, 0, SEEK_SET );
     5         kx 
     5         kx   /* read temporary saved description */
     5         kx   {
     5         kx     struct stat sb;
     5         kx     size_t size = 0;
     5         kx     int    fd;
     5         kx 
     5         kx     char  *install = NULL;
     5         kx 
     5         kx     if( stat( tmp_fname, &sb ) == -1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) );
     5         kx     }
     5         kx     size = (size_t)sb.st_size;
     5         kx 
     5         kx     if( size )
     5         kx     {
     5         kx       ssize_t rc = 0;
     5         kx 
     5         kx       install = (char *)malloc( size + 1 );
     5         kx       if( !install ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)install, size + 1 );
     5         kx 
     5         kx       if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 )
     5         kx       {
     5         kx         FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) );
     5         kx       }
     5         kx 
     5         kx       rc = read( fd, (void *)install, size );
     5         kx       if( rc != (ssize_t)size ) { ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) ); }
     5         kx 
     5         kx       package->install_script = install;
     5         kx 
     5         kx       close( fd );
     5         kx     }
     5         kx 
     5         kx   }
     5         kx 
     5         kx   (void)unlink( tmp_fname );
     5         kx   free( tmp_fname );
     5         kx 
     5         kx   return lines;
     5         kx }
     5         kx 
     5         kx 
     5         kx static unsigned int read_file_list( FILE *log, int start, struct package *package )
     5         kx {
     5         kx   char *ln   = NULL;
     5         kx   char *line = NULL;
     5         kx   int   n = 1;
     5         kx 
     5         kx   unsigned int files = 0;
     5         kx 
     5         kx   if( !log || !package ) return files;
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot allocate memory" );
     5         kx   }
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
     5         kx 
     5         kx   if( start )
     5         kx   {
     5         kx     while( (ln = fgets( line, PATH_MAX, log )) )
     5         kx     {
     5         kx       ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx       skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx 
     5         kx       add_file( package, (const char *)ln );
     5         kx       ++files;
     5         kx     }
     5         kx 
     5         kx   } /* End if( start && start < stop ) */
     5         kx 
     5         kx   free( line );
     5         kx 
     5         kx   fseek( log, 0, SEEK_SET );
     5         kx 
     5         kx   return files;
     5         kx }
     5         kx 
     5         kx 
     5         kx static void _read_pkglog( const char *group, const char *fname )
     5         kx {
     5         kx   FILE *log   = NULL;
     5         kx   char *bname = NULL;
     5         kx 
     5         kx   if( fname != NULL )
     5         kx   {
     5         kx     log = fopen( (const char *)fname, "r" );
     5         kx     if( !log )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot open %s file", fname );
     5         kx     }
     5         kx     bname = (char *)fname + strlen( tmpdir ) + 1;
     5         kx   }
     5         kx 
     5         kx   if( log != NULL )
     5         kx   {
     5         kx     struct package *package = NULL;
     5         kx     int             rc, start, stop;
     5         kx     unsigned int    counter;
     5         kx 
     5         kx     package = package_alloc();
     5         kx 
     5         kx     if( read_pkginfo( log, package ) != 0 )
     5         kx     {
     5         kx       ERROR( "%s: Invalid PKGLOG file", bname );
     5         kx       package_free( package );
     5         kx       fclose( log );
     5         kx       return;
     5         kx     }
     5         kx 
     5         kx     if( hardware ) package->hardware = xstrdup( (const char *)hardware );
     5         kx     if( tarballs ) /* find tarball and allocate package->tarball */
     5         kx     {
     5         kx       struct pkginfo *info = package->pkginfo;
     5         kx       const char     *tgz  = NULL;
     5         kx       char           *buf  = NULL;
     5         kx       struct stat     sb;
     5         kx 
     5         kx       buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx       if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx 
     5         kx       if( info->group )
     5         kx       {
     5         kx         (void)sprintf( buf, "%s/%s-%s-%s-%s-%s",
     5         kx                              info->group, info->name, info->version, info->arch,
     5         kx                              info->distro_name, info->distro_version );
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         (void)sprintf( buf, "%s-%s-%s-%s-%s",
     5         kx                              info->name, info->version, info->arch,
     5         kx                              info->distro_name, info->distro_version );
     5         kx       }
     5         kx       tgz = find_tarball( (const char *)&buf[0] );
     5         kx       if( tgz )
     5         kx       {
     5         kx         package->tarball = xstrdup( (const char *)tgz );
     5         kx 
     5         kx         bzero( (void *)&buf[0], PATH_MAX );
     5         kx         (void)sprintf( buf, "%s/%s", srcdir, tgz );
     5         kx         if( stat( buf, &sb ) != -1 )
     5         kx         {
     5         kx           info->compressed_size = (size_t)sb.st_size;
     5         kx         }
     5         kx       }
     5         kx       free( buf );
     5         kx     }
     5         kx     package->procedure = INSTALL;
     5         kx     package->priority  = priority;
     5         kx 
     5         kx     if( package->pkginfo->group && group  && strcmp( package->pkginfo->group, group ) != 0 )
     5         kx     {
     5         kx       char *tgz;
     5         kx 
     5         kx       if( package->tarball ) { tgz = package->tarball; }
     5         kx       else                   { tgz = basename( (char *)fname ); }
     5         kx 
     5         kx       WARNING( "%s: Should be moved into '%s' subdir", tgz, package->pkginfo->group );
     5         kx     }
     5         kx 
     5         kx     /******************
     5         kx       read references:
     5         kx      */
     5         kx     rc = get_references_section( &start, &stop, &counter, log );
     5         kx     if( rc != 0 )
     5         kx     {
     5         kx       ERROR( "%s: PKGLOG doesn't contains REFERENCE COUNTER section", bname );
     5         kx       package_free( package );
     5         kx       fclose( log );
     5         kx       return;
     5         kx     }
     5         kx     if( counter > 0 )
     5         kx     {
     5         kx       unsigned int pkgs = counter;
     5         kx 
     5         kx       if( read_references( log, start, &counter, package ) != pkgs )
     5         kx       {
     5         kx         ERROR( "%s: Invalid REFERENCE COUNTER section", bname );
     5         kx         package_free( package );
     5         kx         fclose( log );
     5         kx         return;
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     /******************
     5         kx       read requires:
     5         kx      */
     5         kx     rc = get_requires_section( &start, &stop, log );
     5         kx     if( rc != 0 )
     5         kx     {
     5         kx       ERROR( "%s: PKGLOG doesn't contains REQUIRES section", bname );
     5         kx       package_free( package );
     5         kx       fclose( log );
     5         kx       return;
     5         kx     }
     5         kx     if( (stop - start) > 1 )
     5         kx     {
     5         kx       unsigned int pkgs = (unsigned int)(stop - start - 1); /* -1 skips section header */
     5         kx 
     5         kx       if( read_requires( log, start, stop, package ) != pkgs )
     5         kx       {
     5         kx         ERROR( "%s: Invalid REQUIRES section", bname );
     5         kx         package_free( package );
     5         kx         fclose( log );
     5         kx         return;
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     /*******************
     5         kx       read description:
     5         kx      */
     5         kx     rc = get_description_section( &start, &stop, log );
     5         kx     if( rc != 0 )
     5         kx     {
     5         kx       ERROR( "%s: PKGLOG doesn't contains PACKAGE DESCRIPTION section", bname );
     5         kx       package_free( package );
     5         kx       fclose( log );
     5         kx       return;
     5         kx     }
     5         kx     if( (stop - start) > 1 )
     5         kx     {
     5         kx       if( read_description( log, start, stop, package ) != (unsigned int)DESCRIPTION_NUMBER_OF_LINES )
     5         kx       {
     5         kx         ERROR( "%s: Invalid DESCRIPTION section", bname );
     5         kx         package_free( package );
     5         kx         fclose( log );
     5         kx         return;
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     /*********************
     5         kx       read restore links:
     5         kx      */
     5         kx     rc = get_restore_links_section( &start, &stop, log );
     5         kx     if( rc != 0 )
     5         kx     {
     5         kx       ERROR( "%s: PKGLOG doesn't contains RESTORE LINKS section", bname );
     5         kx       package_free( package );
     5         kx       fclose( log );
     5         kx       return;
     5         kx     }
     5         kx     if( (stop - start) > 1 )
     5         kx     {
     5         kx       (void)read_restore_links( log, start, stop, package );
     5         kx     }
     5         kx 
     5         kx     /*********************
     5         kx       read install script:
     5         kx      */
     5         kx     rc = get_install_script_section( &start, &stop, log );
     5         kx     if( rc != 0 )
     5         kx     {
     5         kx       ERROR( "%s: PKGLOG doesn't contains INSTALL SCRIPT section", bname );
     5         kx       package_free( package );
     5         kx       fclose( log );
     5         kx       return;
     5         kx     }
     5         kx     if( (stop - start) > 1 )
     5         kx     {
     5         kx       (void)read_install_script( log, start, stop, package );
     5         kx     }
     5         kx 
     5         kx     /*****************
     5         kx       read file_list:
     5         kx      */
     5         kx     rc = get_file_list_section( &start, &stop, log );
     5         kx     if( rc != 0 )
     5         kx     {
     5         kx       ERROR( "%s: PKGLOG doesn't contains FILE LIST section", bname );
     5         kx       package_free( package );
     5         kx       fclose( log );
     5         kx       return;
     5         kx     }
     5         kx     if( start )
     5         kx     {
     5         kx       unsigned int files = read_file_list( log, start, package );
     5         kx       if( files == (unsigned int)0 )
     5         kx       {
     5         kx         /*
     5         kx           Packages that do not contain regular files are ignored.
     5         kx           For example, service package base/init-devices-1.2.3-s9xx-glibc-radix-1.1.txz
     5         kx          */
     5         kx         if( ! DO_NOT_PRINTOUT_INFO )
     5         kx         {
     5         kx           INFO( "%s: PKGLOG contains empty FILE LIST section", bname );
     5         kx         }
     5         kx         package_free( package );
     5         kx         fclose( log );
     5         kx         return;
     5         kx       }
     5         kx       package->pkginfo->total_files = (int)files;
     5         kx     }
     5         kx 
     5         kx     /* Skip excluded package: */
     5         kx     {
     5         kx       const char *name = find_exclude( (const char *)package->pkginfo->name );
     5         kx 
     5         kx       if( name && !strcmp( name, package->pkginfo->name ) )
     5         kx       {
     5         kx         package_free( package );
     5         kx         fclose( log );
     5         kx         return;
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     add_package( package );
     5         kx 
     5         kx     ++__child;
     5         kx     fclose( log );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void _read_pkglogs( const char *dirpath, const char *grp )
     5         kx {
     5         kx   DIR    *dir;
     5         kx   char   *path;
     5         kx   size_t  len;
     5         kx 
     5         kx   struct stat    path_sb, entry_sb;
     5         kx   struct dirent *entry;
     5         kx 
     5         kx   if( stat( dirpath, &path_sb ) == -1 )
     5         kx   {
     5         kx     FATAL_ERROR( "%s: Cannot stat Setup Database or destination directory", dirpath );
     5         kx   }
     5         kx 
     5         kx   if( S_ISDIR(path_sb.st_mode) == 0 )
     5         kx   {
     5         kx     FATAL_ERROR( "%s: Setup Database or destination is not a directory", dirpath );
     5         kx   }
     5         kx 
     5         kx   if( (dir = opendir(dirpath) ) == NULL )
     5         kx   {
     5         kx     FATAL_ERROR( "Canot access %s directory: %s", dirpath, strerror( errno ) );
     5         kx   }
     5         kx 
     5         kx   len = strlen( dirpath );
     5         kx 
     5         kx   while( (entry = readdir( dir )) != NULL)
     5         kx   {
     5         kx     /* skip entries '.' and '..' */
     5         kx     if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
     5         kx 
     5         kx     /* determinate a full name of an entry */
     5         kx     path = alloca( len + strlen( entry->d_name ) + 2 );
     5         kx 
     5         kx     strcpy( path, dirpath );
     5         kx     strcat( path, "/" );
     5         kx     strcat( path, entry->d_name );
     5         kx 
     5         kx     if( stat( path, &entry_sb ) == 0 )
     5         kx     {
     5         kx       if( S_ISREG(entry_sb.st_mode) )
     5         kx       {
     5         kx         if( check_input_file( NULL, (const char *)path ) == IFMT_LOG )
     5         kx         {
     5         kx           _read_pkglog( grp, (const char *)path );
     5         kx         }
     5         kx       }
     5         kx       if( S_ISDIR(entry_sb.st_mode) && grp == NULL )
     5         kx       {
     5         kx         _read_pkglogs( (const char *)path, (const char *)entry->d_name );
     5         kx       }
     5         kx     }
     5         kx     /* else { stat() returns error code; errno is set; and we have to continue the loop } */
     5         kx   }
     5         kx 
     5         kx   closedir( dir );
     5         kx }
     5         kx 
     5         kx int read_pkglogs( void )
     5         kx {
     5         kx   int ret = 0;
     5         kx 
     5         kx   __child = 0;
     5         kx 
     5         kx   _read_pkglogs( (const char *)tmpdir, NULL );
     5         kx 
     5         kx   ret = __child;
     5         kx 
     5         kx   __child = 0;
     5         kx 
     5         kx   return ret;
     5         kx }
     5         kx 
     5         kx 
     5         kx 
     5         kx /*****************************
     5         kx   Count slashes in file name:
     5         kx  */
     5         kx static int count_slashes( char *s )
     5         kx {
     5         kx   int   cnt = 0;
     5         kx   char *p   = (char *)0;
     5         kx 
     5         kx   if( !s || *s == '\0' ) return cnt;
     5         kx 
     5         kx   p = s;
     5         kx   while( *p )
     5         kx   {
     5         kx     if( *p == '/' ) {
     5         kx       ++cnt;
     5         kx     }
     5         kx     ++p;
     5         kx   }
     5         kx 
     5         kx   return cnt;
     5         kx }
     5         kx 
     5         kx static void read_srcpkg_fnames( const char *flist )
     5         kx {
     5         kx   struct stat st;
     5         kx   FILE  *fp = NULL;
     5         kx 
     5         kx   if( !flist ) return;
     5         kx 
     5         kx   bzero( (void *)&st, sizeof( struct stat ) );
     5         kx 
     5         kx   if( stat( flist, &st ) == -1 )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot access input '%s' file or directory: %s", flist, strerror( errno ) );
     5         kx   }
     5         kx 
     5         kx   if( S_ISREG(st.st_mode) )
     5         kx   {
     5         kx     char *ln   = NULL;
     5         kx     char *line = NULL;
     5         kx     int   lnum = 0;
     5         kx 
     5         kx     fp = fopen( flist, "r" );
     5         kx     if( !fp )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot open %s file", flist );
     5         kx     }
     5         kx 
     5         kx     line = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !line )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot allocate memory" );
     5         kx     }
     5         kx 
     5         kx     while( (ln = fgets( line, PATH_MAX, fp )) )
     5         kx     {
     5         kx       struct srcpkg_fname *fname = NULL;
     5         kx 
     5         kx       ++lnum;
     5         kx       if( strlen( ln ) == 0 ) continue;
     5         kx       ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol      */
     5         kx       skip_eol_spaces( ln );     /* remove spaces at end-of-line */
     5         kx       /* remove leading spaces: */
     5         kx       while( (*ln == ' ' || *ln == '\t') && *ln != '\0' ) { ++ln; }
     5         kx       /* skip comments and empty lines: */
     5         kx       if( *ln == '\0' || *ln == '#' ) continue;
     5         kx 
     5         kx       if( count_slashes( ln ) > 1 )
     5         kx       {
     5         kx         FATAL_ERROR( "%s:%d: file name contains more than one slash symbols", flist, lnum );
     5         kx       }
     5         kx 
     5         kx       if( ! isalpha( *ln ) )
     5         kx       {
     5         kx         FATAL_ERROR( "%s:%d: file path must be relative and start with a letter (as a group name)", flist, lnum );
     5         kx       }
     5         kx 
     5         kx       fname = srcpkg_fname_alloc( (const char *)ln, lnum );
     5         kx       add_srcpkg_fname( fname );
     5         kx     }
     5         kx 
     5         kx     free( line );
     5         kx     fclose( fp );
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     FATAL_ERROR( "Source file names list '%s' is not a regular file" );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void check_srcfile( void *data, void *user_data )
     5         kx {
     5         kx   struct srcpkg_fname *srcfile = (struct srcpkg_fname *)data;
     5         kx 
     5         kx   if( srcfile )
     5         kx   {
     5         kx     struct stat st;
     5         kx     char *fname = NULL;
     5         kx     struct pkg *srcpkg = NULL;
     5         kx 
     5         kx     bzero( (void *)&st, sizeof( struct stat ) );
     5         kx 
     5         kx     fname = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !fname ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)fname, PATH_MAX );
     5         kx 
     5         kx     (void)sprintf( &fname[0], "%s/%s", srcdir, srcfile->name );
     5         kx 
     5         kx     if( stat( (const char *)fname, &st ) == -1 )
     5         kx     {
     5         kx       FATAL_ERROR( "%s:%d: Cannot access input '%s' file or directory: %s",
     5         kx                     srcfile->name, srcfile->line, fname, strerror( errno ) );
     5         kx     }
     5         kx 
     5         kx     if( S_ISREG(st.st_mode) )
     5         kx     {
     5         kx       enum _input_type format = IFMT_UNKNOWN;
     5         kx 
     5         kx       pid_t p = (pid_t) -1;
     5         kx       int   rc;
     5         kx 
     5         kx       int   len = 0;
     5         kx       char *tmp= NULL, *cmd = NULL;
     5         kx 
     5         kx       tmp = (char *)malloc( (size_t)PATH_MAX );
     5         kx       if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)tmp, PATH_MAX );
     5         kx 
     5         kx       (void)sprintf( &tmp[0], "%s", tmpdir );
     5         kx       if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
     5         kx       {
     5         kx         FATAL_ERROR( "%s:%d: Cannot get PKGINFO from '%s' file",
     5         kx                       srcfile->name, srcfile->line, basename( (char *)fname ) );
     5         kx       }
     5         kx 
     5         kx       cmd = (char *)malloc( (size_t)PATH_MAX );
     5         kx       if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)cmd, PATH_MAX );
     5         kx 
     5         kx       len = snprintf( &cmd[0], PATH_MAX, "%s/pkginfo -d %s -o pkginfo %s > /dev/null 2>&1", selfdir, tmp, fname );
     5         kx       if( len == 0 || len == PATH_MAX - 1 )
     5         kx       {
     5         kx         FATAL_ERROR( "%s:%d: Cannot get PKGINFO from %s file",
     5         kx                       srcfile->name, srcfile->line, basename( (char *)fname ) );
     5         kx       }
     5         kx       p = sys_exec_command( cmd );
     5         kx       rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
     5         kx       if( rc != 0 )
     5         kx       {
     5         kx         FATAL_ERROR( "%s:%d: Cannot get PKGINFO from '%s' file",
     5         kx                       srcfile->name, srcfile->line, basename( (char *)fname ) );
     5         kx       }
     5         kx 
     5         kx       (void)strcat( tmp, "/.PKGINFO" );
     5         kx 
     5         kx       bzero( (void *)&st, sizeof( struct stat ) );
     5         kx       if( stat( (const char *)tmp, &st ) == -1 )
     5         kx       {
     5         kx         FATAL_ERROR( "%s:%d: Cannot get PKGINFO from %s file: %s",
     5         kx                       srcfile->name, srcfile->line, basename( (char *)fname ), strerror( errno ) );
     5         kx       }
     5         kx 
     5         kx       srcpkg = input_package( (const char *)&tmp[0] );
     5         kx       bzero( (void *)tmp, PATH_MAX );
     5         kx       if( srcpkg )
     5         kx       {
     5         kx         char *e = NULL;
     5         kx 
     5         kx         if( srcpkg->group )
     5         kx         {
     5         kx           len = snprintf( &tmp[0], PATH_MAX, "%s/%s", srcpkg->group, basename( (char *)fname ) );
     5         kx           if( len == 0 || len == PATH_MAX - 1 )
     5         kx           {
     5         kx             FATAL_ERROR( "%s:%d: Cannot get PKGINFO from %s file",
     5         kx                           srcfile->name, srcfile->line, basename( (char *)fname ) );
     5         kx           }
     5         kx         }
     5         kx         else
     5         kx         {
     5         kx           len = snprintf( &tmp[0], PATH_MAX, "%s", basename( (char *)fname ) );
     5         kx           if( len == 0 || len == PATH_MAX - 1 )
     5         kx           {
     5         kx             FATAL_ERROR( "%s:%d: Cannot get PKGINFO from %s file",
     5         kx                           srcfile->name, srcfile->line, basename( (char *)fname ) );
     5         kx           }
     5         kx         }
     5         kx 
     5         kx         add_srcpkg( srcpkg );
     5         kx 
     5         kx         remove_trailing_slash( srcdir );
     5         kx       }
     5         kx 
     5         kx       free( tmp );
     5         kx       free( cmd );
     5         kx     }
     5         kx 
     5         kx     free( fname );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void check_srcdir( void )
     5         kx {
     5         kx   struct stat st;
     5         kx   char *fname = srcdir;
     5         kx   struct pkg *srcpkg = NULL;
     5         kx 
     5         kx   bzero( (void *)&st, sizeof( struct stat ) );
     5         kx 
     5         kx   if( stat( (const char *)srcdir, &st ) == -1 )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot access input '%s' file or directory: %s", srcdir, strerror( errno ) );
     5         kx   }
     5         kx 
     5         kx   if( S_ISREG(st.st_mode) )
     5         kx   {
     5         kx     enum _input_type format = IFMT_UNKNOWN;
     5         kx 
     5         kx     pid_t p = (pid_t) -1;
     5         kx     int   rc;
     5         kx 
     5         kx     int   len = 0;
     5         kx     char *tmp= NULL, *cmd = NULL;
     5         kx 
     5         kx     tmp = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)tmp, PATH_MAX );
     5         kx 
     5         kx     (void)sprintf( &tmp[0], "%s", tmpdir );
     5         kx     if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot get PKGINFO from '%s' file", basename( (char *)fname ) );
     5         kx     }
     5         kx 
     5         kx     cmd = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)cmd, PATH_MAX );
     5         kx 
     5         kx     len = snprintf( &cmd[0], PATH_MAX, "%s/pkginfo -d %s -o pkginfo %s > /dev/null 2>&1", selfdir, tmp, fname );
     5         kx     if( len == 0 || len == PATH_MAX - 1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot get PKGINFO from %s file", basename( (char *)fname ) );
     5         kx     }
     5         kx     p = sys_exec_command( cmd );
     5         kx     rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
     5         kx     if( rc != 0 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot get PKGINFO from '%s' file", basename( (char *)fname ) );
     5         kx     }
     5         kx 
     5         kx     (void)strcat( tmp, "/.PKGINFO" );
     5         kx 
     5         kx     bzero( (void *)&st, sizeof( struct stat ) );
     5         kx     if( stat( (const char *)tmp, &st ) == -1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot get PKGINFO from %s file: %s", basename( (char *)fname ), strerror( errno ) );
     5         kx     }
     5         kx 
     5         kx     /* keep or set input file format: */
     5         kx     format = check_input_file( NULL, fname );
     5         kx     if( input_format == IFMT_UNKNOWN ) input_format = format;
     5         kx 
     5         kx     srcpkg = input_package( (const char *)&tmp[0] );
     5         kx     bzero( (void *)tmp, PATH_MAX );
     5         kx     if( srcpkg )
     5         kx     {
     5         kx       char *e = NULL;
     5         kx 
     5         kx       if( srcpkg->group )
     5         kx       {
     5         kx         len = snprintf( &tmp[0], PATH_MAX, "%s/%s", srcpkg->group, basename( (char *)fname ) );
     5         kx         if( len == 0 || len == PATH_MAX - 1 )
     5         kx         {
     5         kx           FATAL_ERROR( "Cannot get PKGINFO from %s file", basename( (char *)fname ) );
     5         kx         }
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         len = snprintf( &tmp[0], PATH_MAX, "%s", basename( (char *)fname ) );
     5         kx         if( len == 0 || len == PATH_MAX - 1 )
     5         kx         {
     5         kx           FATAL_ERROR( "Cannot get PKGINFO from %s file", basename( (char *)fname ) );
     5         kx         }
     5         kx       }
     5         kx 
     5         kx       add_srcpkg( srcpkg );
     5         kx 
     5         kx       /* remove source file name (with group directory if defined) from srcdir path */
     5         kx       e = strstr( (const char *)srcdir, (const char *)&tmp[0] );
     5         kx       if( !e ) { e = strstr( (const char *)srcdir, (const char *)basename( (char *)fname ) ); }
     5         kx       *e = '\0';
     5         kx 
     5         kx       remove_trailing_slash( srcdir );
     5         kx     }
     5         kx 
     5         kx     free( tmp );
     5         kx     free( cmd );
     5         kx   }
     5         kx 
     5         kx   if( S_ISDIR(st.st_mode) )
     5         kx   {
     5         kx     if( srclist_fname )
     5         kx     {
     5         kx       read_srcpkg_fnames( srclist_fname );
     5         kx       dlist_foreach( srcpkg_fnames, check_srcfile, NULL );
     5         kx     }
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static void _print_extern_requires( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx 
     5         kx   if( pkg )
     5         kx   {
     5         kx     if( pkg->group )
     5         kx       fprintf( stderr, "%s/%s:%s:%s\n", pkg->group, pkg->name, pkg->version, strproc( pkg->procedure ) );
     5         kx     else
     5         kx       fprintf( stderr, "%s:%s:%s\n", pkg->name, pkg->version, strproc( pkg->procedure ) );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void print_extern_requires( void )
     5         kx {
     5         kx   dlist_foreach( extern_requires, _print_extern_requires, NULL );
     5         kx }
     5         kx 
     5         kx 
     5         kx /*********************************************
     5         kx   Get directory where this program is placed:
     5         kx  */
     5         kx char *get_selfdir( void )
     5         kx {
     5         kx   char    *buf = NULL;
     5         kx   ssize_t  len;
     5         kx 
     5         kx   buf = (char *)malloc( PATH_MAX );
     5         kx   if( !buf )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot allocate memory" );
     5         kx   }
     5         kx 
     5         kx   bzero( (void *)buf, PATH_MAX );
     5         kx   len = readlink( "/proc/self/exe", buf, (size_t)PATH_MAX );
     5         kx   if( len > 0 && len < PATH_MAX )
     5         kx   {
     5         kx     char *p = xstrdup( (const char *)dirname( buf ) );
     5         kx     free( buf );
     5         kx     return p;
     5         kx   }
     5         kx   FATAL_ERROR( "Cannot determine self directory. Please mount /proc filesystem" );
     5         kx }
     5         kx 
     5         kx void set_stack_size( void )
     5         kx {
     5         kx   const rlim_t   stack_size = 16 * 1024 * 1024; /* min stack size = 16 MB */
     5         kx   struct rlimit  rl;
     5         kx   int ret;
     5         kx 
     5         kx   ret = getrlimit( RLIMIT_STACK, &rl );
     5         kx   if( ret == 0 )
     5         kx   {
     5         kx     if( rl.rlim_cur < stack_size )
     5         kx     {
     5         kx       rl.rlim_cur = stack_size;
     5         kx       ret = setrlimit( RLIMIT_STACK, &rl );
     5         kx       if( ret != 0 )
     5         kx       {
     5         kx         fprintf(stderr, "setrlimit returned result = %d\n", ret);
     5         kx         FATAL_ERROR( "Cannot set stack size" );
     5         kx       }
     5         kx     }
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx int main( int argc, char *argv[] )
     5         kx {
     5         kx   gid_t  gid;
     5         kx 
     5         kx   set_signal_handlers();
     5         kx 
     5         kx   gid = getgid();
     5         kx   setgroups( 1, &gid );
     5         kx 
     5         kx   fatal_error_hook = fatal_error_actions;
     5         kx 
     5         kx   selfdir = get_selfdir();
     5         kx 
     5         kx   errlog = stderr;
     5         kx 
     5         kx   program = basename( argv[0] );
     5         kx   get_args( argc, argv );
     5         kx 
     5         kx   /* set_stack_size(); */
     5         kx 
     5         kx   tmpdir = _mk_tmpdir();
     5         kx   if( !tmpdir )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot create temporary directory" );
     5         kx   }
     5         kx 
     5         kx   /********************************************************
     5         kx     Check if the --source argument is a file or directory:
     5         kx    */
     5         kx   check_srcdir();
     5         kx 
     5         kx   /* Extract or Copy PKGLOGs into TMPDIR: */
     5         kx   if( input_format == IFMT_PKG )
     5         kx   {
     5         kx     int pkgs = extract_pkglogs();
     5         kx     if( pkgs == 0 )       { FATAL_ERROR( "There are no packages in the '%s' directory", srcdir ); }
     5         kx     if( exit_status > 0 ) { FATAL_ERROR( "Cannot extract PKGLOG from some package" ); }
     5         kx     if( ! DO_NOT_PRINTOUT_INFO )
     5         kx     {
     5         kx       INFO( "Found %d packages in the '%s' directory", pkgs, srcdir );
     5         kx     }
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     int pkgs = copy_pkglogs();
     5         kx     if( pkgs == 0 )       { FATAL_ERROR( "There are no PKGLOG files in the '%s' directory", srcdir ); }
     5         kx     if( exit_status > 0 ) { FATAL_ERROR( "Cannot copy some PKGLOG file" ); }
     5         kx     if( ! DO_NOT_PRINTOUT_INFO )
     5         kx     {
     5         kx       INFO( "Found %d PKGLOG files in the '%s' directory", pkgs, srcdir );
     5         kx     }
     5         kx   }
     5         kx 
     5         kx   /* Read PKGLOGs from TMPDIR and create Double Linked List of PACKAGES: */
     5         kx   {
     5         kx     int pkgs = read_pkglogs();
     5         kx     if( pkgs == 0 )       { FATAL_ERROR( "There are no PKGLOG files in the '%s' directory", tmpdir ); }
     5         kx     if( exit_status > 0 ) { FATAL_ERROR( "Cannot read some PKGLOG file" ); }
     5         kx     if( ! DO_NOT_PRINTOUT_INFO )
     5         kx     {
     5         kx       /* INFO( "Found %d PKGLOG files in the '%s' directory", pkgs, tmpdir ); */
     5         kx     }
     5         kx   }
     5         kx 
     5         kx   {
     5         kx     int extern_pkgs = create_provides_list( srcpkgs );
     5         kx     if( output_format == OFMT_LIST )
     5         kx     {
     5         kx       print_provides_list( (const char *)pkglist_fname );
     5         kx       if( extern_pkgs )
     5         kx       {
     5         kx         /* Output machine readable list of requires to stderr: */
     5         kx         print_extern_requires();
     5         kx         exit_status += 1;
     5         kx       }
     5         kx     }
     5         kx     if( output_format == OFMT_JSON ) print_provides_tree( (const char *)pkglist_fname, tree_format );
     5         kx     free_provides_list();
     5         kx   }
     5         kx 
     5         kx   if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
     5         kx   free_resources();
     5         kx 
     5         kx   exit( exit_status );
     5         kx }