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/sysinfo.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 <pthread.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 #include <msglog.h>
     5         kx #include <wrapper.h>
     5         kx #include <system.h>
     5         kx #include <dlist.h>
     5         kx 
     5         kx #if defined( HAVE_DIALOG )
     5         kx #include <dialog-ui.h>
     5         kx #endif
     5         kx 
     5         kx #define PROGRAM_NAME "install-pkglist"
     5         kx 
     5         kx #include <defs.h>
     5         kx 
     5         kx #define WAIT_USEC_FOR_CHILD 10000
     5         kx 
     5         kx char *program = PROGRAM_NAME;
     5         kx char *root = NULL, *srcdir = NULL, *pkglist_fname = NULL,
     5         kx      *tmpdir = NULL, *curdir = NULL;
     5         kx 
     5         kx int   rqck = 0, gpgck = 0, progress = 0, parallel = 0, error_pkgs_list = 0, ncpus = 0;
     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, __terminated = 0, __successful = 0, __all = 0;
     5         kx 
     5         kx enum _install_mode {
     5         kx   CONSOLE = 0,
     5         kx   INFODIALOG,
     5         kx   MENUDIALOG
     5         kx } install_mode = CONSOLE;
     5         kx 
     5         kx enum _input_type {
     5         kx   IFMT_PKG = 0,
     5         kx   IFMT_LOG,
     5         kx 
     5         kx   IFMT_UNKNOWN
     5         kx };
     5         kx 
     5         kx /*********************************************
     5         kx   Package structures and declarations:
     5         kx  */
     5         kx enum _procedure
     5         kx {
     5         kx   INSTALL = 0, /* 'install' */
     5         kx   UPDATE       /* 'update'  */
     5         kx };
     5         kx 
     5         kx enum _priority
     5         kx {
     5         kx   REQUIRED = 0, /* synonims: REQUIRED    | required    | REQ | req */
     5         kx   RECOMMENDED,  /* synonims: RECOMMENDED | recommended | REC | rec */
     5         kx   OPTIONAL,     /* synonims: OPTIONAL    | optional    | OPT | opt */
     5         kx   SKIP          /* synonims: SKIP        | skip        | SKP | skp */
     5         kx };
     5         kx 
     5         kx struct pkg
     5         kx {
     5         kx   char *group;
     5         kx   char *name;
     5         kx   char *version;
     5         kx };
     5         kx 
     5         kx struct package
     5         kx {
     5         kx   char  *name;
     5         kx   char  *version;
     5         kx   char  *group;
     5         kx   char  *description;
     5         kx 
     5         kx   char  *tarball;
     5         kx 
     5         kx   enum  _procedure procedure; /* install procedure     */
     5         kx   enum  _priority  priority;  /* install user priority */
     5         kx };
     5         kx 
     5         kx enum _priority install_priority = OPTIONAL; /* by default allow all packages exept 'SKIP' */
     5         kx 
     5         kx struct dlist *requires = NULL; /* list of pkg structs     */
     5         kx struct dlist *packages = NULL; /* list of package structs */
     5         kx 
     5         kx static void free_requires( void );
     5         kx static void free_packages( void );
     5         kx 
     5         kx /*
     5         kx   End of package structures and declarations.
     5         kx  *********************************************/
     5         kx 
     5         kx /*********************************************
     5         kx   Return status declarations:
     5         kx  */
     5         kx struct pkgrc
     5         kx {
     5         kx   pid_t  pid;
     5         kx   int    status;
     5         kx   char  *name;
     5         kx   char  *version;
     5         kx   char  *group;
     5         kx };
     5         kx 
     5         kx struct dlist *pkgrcl = NULL; /* list of pkgrc structs */
     5         kx 
     5         kx static void          free_pkgrcl( void );
     5         kx static struct pkgrc *find_pkgrc( struct dlist *list, pid_t pid );
     5         kx /*
     5         kx   End of return status declarations.
     5         kx  *********************************************/
     5         kx 
     5         kx 
     5         kx void free_resources()
     5         kx {
     5         kx   if( root )           { free( root );           root           = NULL; }
     5         kx   if( srcdir )         { free( srcdir );         srcdir         = NULL; }
     5         kx   if( pkglist_fname )  { free( pkglist_fname );  pkglist_fname  = NULL; }
     5         kx 
     5         kx   if( requires ) free_requires();
     5         kx   if( packages ) free_packages();
     5         kx   if( pkgrcl )   free_pkgrcl();
     5         kx 
     5         kx   if( curdir )         { free( curdir );         curdir         = NULL; }
     5         kx   if( selfdir )        { free( selfdir );        selfdir        = NULL; }
     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 
     5         kx   fprintf( stdout, "  -c,--check-requires           Check the list of requires before install.\n" );
     5         kx   fprintf( stdout, "  -g,--gpg-verify               Verify GPG2 signature. The signature must be\n" );
     5         kx   fprintf( stdout, "                                saved in a file whose name is the same as the\n" );
     5         kx   fprintf( stdout, "                                package file name, but with the extension '.asc'\n" );
     5         kx   fprintf( stdout, "                                and located in the same directory as the package.\n" );
     5         kx #if defined( HAVE_DIALOG )
     5         kx   fprintf( stdout, "  -i,--info-dialog              Show package description during install\n" );
     5         kx   fprintf( stdout, "                                process using ncurses dialog.\n" );
     5         kx   fprintf( stdout, "  -m,--menu-dialog              Ask for confirmation the inatallation.\n" );
     5         kx #endif
     5         kx   fprintf( stdout, "  --parallel                    Parallel installation (dangerous; required the\n" );
     5         kx   fprintf( stdout, "                                checking of DB integrity after installation).\n" );
     5         kx   fprintf( stdout, "  --errlist                     Print the list of not installed packages to the\n" );
     5         kx   fprintf( stdout, "                                stderr in following format:\n" );
     5         kx   fprintf( stdout, "                                    group/name:version:status\n" );
     5         kx   fprintf( stdout, "                                This option is applicable only for parallel\n" );
     5         kx   fprintf( stdout, "                                installations.\n" );
     5         kx   fprintf( stdout, "  --progress                    Show progress bar instead of packages information.\n" );
     5         kx 
     5         kx   fprintf( stdout, "  -p,--priority=<required|recommended|optional|all>\n" );
     5         kx   fprintf( stdout, "                                Рackage priorities allowed for installation:\n" );
     5         kx   fprintf( stdout, "                                - optional | all ) install all packages;\n" );
     5         kx   fprintf( stdout, "                                - recommended )    install required and recommended;\n" );
     5         kx   fprintf( stdout, "                                - required )       install only required packages.\n" );
     5         kx 
     5         kx   fprintf( stdout, "  -r,--root=<DIR>               Target rootfs path.\n" );
     5         kx 
     5         kx   fprintf( stdout, "  -s,--source=<DIR>             Packages source directory.\n" );
     5         kx 
     5         kx   fprintf( stdout, "\n" );
     5         kx   fprintf( stdout, "Parameter:\n" );
     5         kx   fprintf( stdout, "  <DIR|pkglist>                 Input PKGLIST file name or a source\n"  );
     5         kx   fprintf( stdout, "                                directory to find default PKGLIST.\n"  );
     5         kx   fprintf( stdout, "\n" );
     5         kx   fprintf( stdout, "If sourse packages directory is defined by option -s,--source then\n" );
     5         kx   fprintf( stdout, "specified <DIR|pkglist> argumet will be considered relative to the\n" );
     5         kx   fprintf( stdout, "source directory.\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     struct pkgrc *pkgrc = find_pkgrc( pkgrcl, pid );
     5         kx 
     5         kx     ++__terminated; /* 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         if( pkgrc ) pkgrc->status = (int)WEXITSTATUS (status);
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         ++__successful; /* printf( "Child %d terminated with status: %d\n", pid, (int)WEXITSTATUS (status) ); */
     5         kx         if( pkgrc ) pkgrc->status = (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       if( pkgrc ) pkgrc->status = 253;
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       ++exit_status; /* printf( "Child %d terminated on unknown reason\n", pid ); */
     5         kx       if( pkgrc ) pkgrc->status = 254;
     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_package_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 #if defined( HAVE_DIALOG )
     5         kx   const char* short_options = "hvcgimp:r:s:";
     5         kx #else
     5         kx   const char* short_options = "hvcgp:r:s:";
     5         kx #endif
     5         kx 
     5         kx #define PROGRESS 812
     5         kx #define PARALLEL 872
     5         kx #define _ERRLIST 873
     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     { "check-requires", no_argument,       NULL, 'c' },
     5         kx     { "gpg-verify",     no_argument,       NULL, 'g' },
     5         kx #if defined( HAVE_DIALOG )
     5         kx     { "info-dialog",    no_argument,       NULL, 'i' },
     5         kx     { "menu-dialog",    no_argument,       NULL, 'm' },
     5         kx #endif
     5         kx     { "parallel",       no_argument,       NULL, PARALLEL },
     5         kx     { "errlist",        no_argument,       NULL, _ERRLIST },
     5         kx     { "progress",       no_argument,       NULL, PROGRESS },
     5         kx     { "priority",       required_argument, NULL, 'p' },
     5         kx     { "root",           required_argument, NULL, 'r' },
     5         kx     { "source",         required_argument, NULL, 's' },
     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 'c':
     5         kx       {
     5         kx         rqck = 1;
     5         kx         break;
     5         kx       }
     5         kx       case 'g':
     5         kx       {
     5         kx         gpgck = 1;
     5         kx         break;
     5         kx       }
     5         kx 
     5         kx #if defined( HAVE_DIALOG )
     5         kx       case 'i':
     5         kx       {
     5         kx         install_mode = INFODIALOG;
     5         kx         break;
     5         kx       }
     5         kx       case 'm':
     5         kx       {
     5         kx         install_mode = MENUDIALOG;
     5         kx         break;
     5         kx       }
     5         kx #endif
     5         kx 
     5         kx       case PARALLEL:
     5         kx       {
     5         kx         parallel = 1;
     5         kx         break;
     5         kx       }
     5         kx       case _ERRLIST:
     5         kx       {
     5         kx         error_pkgs_list = 1;
     5         kx         break;
     5         kx       }
     5         kx       case PROGRESS:
     5         kx       {
     5         kx         progress = 1;
     5         kx         break;
     5         kx       }
     5         kx 
     5         kx       case 'p':
     5         kx       {
     5         kx         if( optarg != NULL )
     5         kx         {
     5         kx           char *match = NULL;
     5         kx 
     5         kx           if( strlen( (const char *)optarg ) > 2 )
     5         kx           {
     5         kx             to_lowercase( optarg );
     5         kx             if( (match = strstr( optarg, "req" )) && match == optarg ) {
     5         kx               install_priority = REQUIRED;
     5         kx             }
     5         kx             else if( (match = strstr( optarg, "rec" )) && match == optarg ) {
     5         kx               install_priority = RECOMMENDED;
     5         kx             }
     5         kx             else if( (match = strstr( optarg, "opt" )) && match == optarg ) {
     5         kx               install_priority = OPTIONAL;
     5         kx             }
     5         kx             else if( (match = strstr( optarg, "all" )) && match == optarg ) {
     5         kx               install_priority = OPTIONAL;
     5         kx             }
     5         kx             else {
     5         kx               FATAL_ERROR( "Unknown --priority '%s' value", optarg );
     5         kx             }
     5         kx           }
     5         kx           else
     5         kx           {
     5         kx             FATAL_ERROR( "Unknown --priority '%s' value", optarg );
     5         kx           }
     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 'r':
     5         kx       {
     5         kx         if( optarg != NULL )
     5         kx         {
     5         kx           char cwd[PATH_MAX];
     5         kx 
     5         kx           bzero( (void *)cwd, PATH_MAX );
     5         kx           if( optarg[0] != '/' && curdir )
     5         kx           {
     5         kx             /* skip current directory definition './' at start of argument: */
     5         kx             if( !strncmp( optarg, "./", 2 ) && strncmp( optarg, "..", 2 ) )
     5         kx               (void)sprintf( cwd, "%s/%s", curdir, optarg + 2 );
     5         kx             else if( (strlen( optarg ) == 1) && !strncmp( optarg, ".", 1 ) )
     5         kx               (void)sprintf( cwd, "%s", curdir );
     5         kx             else
     5         kx               (void)sprintf( cwd, "%s/%s", curdir, optarg );
     5         kx             root = xstrdup( (const char *)cwd );
     5         kx           }
     5         kx           else
     5         kx           {
     5         kx             root = xstrdup( (const char *)optarg );
     5         kx           }
     5         kx           remove_trailing_slash( root );
     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           char cwd[PATH_MAX];
     5         kx 
     5         kx           bzero( (void *)cwd, PATH_MAX );
     5         kx           if( optarg[0] != '/' && curdir )
     5         kx           {
     5         kx             (void)sprintf( cwd, "%s/%s", curdir, optarg );
     5         kx             srcdir = xstrdup( (const char *)cwd );
     5         kx           }
     5         kx           else
     5         kx           {
     5         kx             srcdir = xstrdup( (const char *)optarg );
     5         kx           }
     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 
     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 intput PKGLIST file */
     5         kx   if( optind < argc )
     5         kx   {
     5         kx     struct stat st;
     5         kx     char  *buf = NULL;
     5         kx 
     5         kx     bzero( (void *)&st, sizeof( struct stat ) );
     5         kx 
     5         kx     buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx     (void)strcpy( buf, (const char *)argv[optind++] );
     5         kx     remove_trailing_slash( (char *)&buf[0] );
     5         kx 
     5         kx     if( srcdir)
     5         kx     {
     5         kx       char *tmp = xstrdup( (const char *)&buf[0] );
     5         kx 
     5         kx       /* Ignore already defined srcdir if absolute path is specified: */
     5         kx       if( buf[0] != '/' )
     5         kx       {
     5         kx         if( !strncmp( tmp, "./", 2 ) && strncmp( tmp, "..", 2 ) )
     5         kx           (void)sprintf( buf, "%s/%s", srcdir, tmp + 2 );
     5         kx         else if( (strlen( tmp ) == 1) && !strncmp( tmp, ".", 1 ) )
     5         kx           (void)sprintf( buf, "%s", srcdir );
     5         kx         else
     5         kx           (void)sprintf( buf, "%s/%s", srcdir, tmp );
     5         kx       }
     5         kx       free( tmp );
     5         kx 
     5         kx       free( srcdir ); srcdir = xstrdup( (const char *)buf );
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       char *tmp = xstrdup( (const char *)&buf[0] );
     5         kx 
     5         kx       if( buf[0] != '/' && curdir )
     5         kx       {
     5         kx         if( !strncmp( tmp, "./", 2 ) && strncmp( tmp, "..", 2 ) )
     5         kx           (void)sprintf( buf, "%s/%s", curdir, tmp + 2 );
     5         kx         else if( (strlen( tmp ) == 1) && !strncmp( tmp, ".", 1 ) )
     5         kx           (void)sprintf( buf, "%s", curdir );
     5         kx         else
     5         kx           (void)sprintf( buf, "%s/%s", curdir, tmp );
     5         kx       }
     5         kx       free( tmp );
     5         kx 
     5         kx       srcdir = xstrdup( (const char *)buf );
     5         kx     }
     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       /**********************************************************
     5         kx         Add default '.pkglist' file name to the source dir name:
     5         kx        */
     5         kx       (void)sprintf( buf, "%s/.pkglist", srcdir );
     5         kx       pkglist_fname = xstrdup( (const char *)buf );
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       if( S_ISREG(st.st_mode) )
     5         kx       {
     5         kx         pkglist_fname = xstrdup( (const char *)buf );
     5         kx         free( srcdir ); srcdir = xstrdup( (const char *)dirname( (char *)&buf[0] ) );
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         FATAL_ERROR( "Specified '%s' PKGLIST is not a regular file", basename( (char *)&buf[0] ) );
     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     root is always have the trailing slash '/':
     5         kx    */
     5         kx   {
     5         kx     struct stat st;
     5         kx     char  *buf = NULL;
     5         kx     int    len;
     5         kx 
     5         kx     bzero( (void *)&st, sizeof( struct stat ) );
     5         kx 
     5         kx     buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx     if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx     bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx     if( !root )
     5         kx     {
     5         kx       buf[0] = '/'; buf[1] = '\0';
     5         kx       root = xstrdup( (const char *)buf );
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       len = strlen( root );
     5         kx 
     5         kx       (void)strcpy( buf, (const char *)root );
     5         kx       if( buf[ len - 1 ] != '/' )
     5         kx       {
     5         kx         buf[len] = '/'; buf[len+1] = '\0';
     5         kx         free( root ); root = xstrdup( (const char *)buf );
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     if( stat( (const char *)&buf[0], &st ) == -1 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot access '%s' file or directory: %s", buf, strerror( errno ) );
     5         kx     }
     5         kx     if( !S_ISDIR(st.st_mode) )
     5         kx     {
     5         kx       FATAL_ERROR( "Defined --root '%s' is not a directory", buf );
     5         kx     }
     5         kx 
     5         kx     free( buf );
     5         kx   }
     5         kx   /*
     5         kx     End of set root path routine.
     5         kx    *********************************************/
     5         kx }
     5         kx 
     5         kx 
     5         kx 
     5         kx 
     5         kx /*********************************************
     5         kx   Package functions:
     5         kx  */
     5         kx static char *strprio( enum _priority priority, int short_name )
     5         kx {
     5         kx   char *p = NULL;
     5         kx 
     5         kx   switch( priority )
     5         kx   {
     5         kx     case REQUIRED:
     5         kx       p = ( short_name ) ? "REQ" : "REQUIRED";
     5         kx       break;
     5         kx     case RECOMMENDED:
     5         kx       p = ( short_name ) ? "REC" : "RECOMMENDED";
     5         kx       break;
     5         kx     case OPTIONAL:
     5         kx       p = ( short_name ) ? "OPT" : "OPTIONAL";
     5         kx       break;
     5         kx     case SKIP:
     5         kx       p = ( short_name ) ? "SKP" : "SKIP";
     5         kx       break;
     5         kx   }
     5         kx   return p;
     5         kx }
     5         kx 
     5         kx static char *strproc( enum _procedure procedure )
     5         kx {
     5         kx   char *p = NULL;
     5         kx 
     5         kx   switch( procedure )
     5         kx   {
     5         kx     case INSTALL:
     5         kx       p = "install";
     5         kx       break;
     5         kx     case UPDATE:
     5         kx       p = "update";
     5         kx       break;
     5         kx   }
     5         kx   return p;
     5         kx }
     5         kx 
     5         kx 
     5         kx static struct pkg *pkg_alloc( void )
     5         kx {
     5         kx   struct pkg *pkg = NULL;
     5         kx 
     5         kx   pkg = (struct pkg *)malloc( sizeof( struct pkg ) );
     5         kx   if( !pkg ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)pkg, sizeof( struct pkg ) );
     5         kx 
     5         kx   return pkg;
     5         kx }
     5         kx 
     5         kx static void pkg_free( struct pkg *pkg )
     5         kx {
     5         kx   if( pkg )
     5         kx   {
     5         kx     if( pkg->name )    { free( pkg->name );    pkg->name    = NULL; }
     5         kx     if( pkg->version ) { free( pkg->version ); pkg->version = NULL; }
     5         kx     if( pkg->group )   { free( pkg->group );   pkg->group   = NULL; }
     5         kx 
     5         kx     free( pkg );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __pkg_free_func( void *data, void *user_data )
     5         kx {
     5         kx   struct pkg *pkg = (struct pkg *)data;
     5         kx   if( pkg ) { pkg_free( pkg ); }
     5         kx }
     5         kx 
     5         kx static void free_requires( void )
     5         kx {
     5         kx   if( requires ) { dlist_free( requires, __pkg_free_func ); requires = NULL; }
     5         kx }
     5         kx 
     5         kx static void add_required( struct pkg *pkg )
     5         kx {
     5         kx   requires = dlist_append( requires, (void *)pkg );
     5         kx }
     5         kx 
     5         kx ///////////////////// only if we deside to print requires list
     5         kx //static void _print_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\n", pkg->group, pkg->name, pkg->version );
     5         kx //    else
     5         kx //      fprintf( stderr, "%s:%s\n", pkg->name, pkg->version );
     5         kx //  }
     5         kx //}
     5         kx //
     5         kx //static void print_requires( void )
     5         kx //{
     5         kx //  dlist_foreach( requires, _print_requires, NULL );
     5         kx //}
     5         kx /////////////////////
     5         kx 
     5         kx static struct package *package_alloc( void )
     5         kx {
     5         kx   struct package *package = NULL;
     5         kx 
     5         kx   package = (struct package *)malloc( sizeof( struct package ) );
     5         kx   if( !package ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)package, sizeof( struct package ) );
     5         kx 
     5         kx   return package;
     5         kx }
     5         kx 
     5         kx static void package_free( struct package *package )
     5         kx {
     5         kx   if( package )
     5         kx   {
     5         kx     if( package->name )    { free( package->name );    package->name    = NULL; }
     5         kx     if( package->version ) { free( package->version ); package->version = NULL; }
     5         kx     if( package->group )   { free( package->group );   package->group   = NULL; }
     5         kx 
     5         kx     if( package->description ) { free( package->description ); package->description   = NULL; }
     5         kx     if( package->tarball )     { free( package->tarball );     package->tarball   = NULL; }
     5         kx 
     5         kx     free( package );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __package_free_func( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx   if( package ) { package_free( package ); }
     5         kx }
     5         kx 
     5         kx static void free_packages( void )
     5         kx {
     5         kx   if( packages ) { dlist_free( packages, __package_free_func ); packages = NULL; }
     5         kx }
     5         kx 
     5         kx static void add_package( struct package *package )
     5         kx {
     5         kx   packages = dlist_append( packages, (void *)package );
     5         kx }
     5         kx 
     5         kx ////////////////////////////// just for testing
     5         kx //static void _print_packages( void *data, void *user_data )
     5         kx //{
     5         kx //  struct package *package = (struct package *)data;
     5         kx //
     5         kx //  if( package )
     5         kx //  {
     5         kx //    if( package->group )
     5         kx //      fprintf( stderr, "%s/%s:%s:%s:%s:%s:%s\n", package->group, package->name, package->version, strproc( package->procedure ), strprio( package->priority, 0 ),
     5         kx //                                                 package->description, package->tarball );
     5         kx //    else
     5         kx //      fprintf( stderr, "%s:%s:%s:%s:%s:%s\n", package->name, package->version, strproc( package->procedure ), strprio( package->priority, 0 ),
     5         kx //                                              package->description, package->tarball );
     5         kx //  }
     5         kx //}
     5         kx //
     5         kx //static void print_packages( void )
     5         kx //{
     5         kx //  dlist_foreach( packages, _print_packages, NULL );
     5         kx //}
     5         kx //////////////////////////////
     5         kx 
     5         kx /*
     5         kx   End of package functions.
     5         kx  *********************************************/
     5         kx 
     5         kx 
     5         kx /*********************************************
     5         kx   Return status functions:
     5         kx  */
     5         kx static struct pkgrc *pkgrc_alloc( void )
     5         kx {
     5         kx   struct pkgrc *pkgrc = NULL;
     5         kx 
     5         kx   pkgrc = (struct pkgrc *)malloc( sizeof( struct pkgrc ) );
     5         kx   if( !pkgrc ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)pkgrc, sizeof( struct pkgrc ) );
     5         kx 
     5         kx   return pkgrc;
     5         kx }
     5         kx 
     5         kx static void pkgrc_free( struct pkgrc *pkgrc )
     5         kx {
     5         kx   if( pkgrc )
     5         kx   {
     5         kx     if( pkgrc->name )    { free( pkgrc->name );    pkgrc->name    = NULL; }
     5         kx     if( pkgrc->version ) { free( pkgrc->version ); pkgrc->version = NULL; }
     5         kx     if( pkgrc->group )   { free( pkgrc->group );   pkgrc->group   = NULL; }
     5         kx 
     5         kx     free( pkgrc );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void __pkgrc_free_func( void *data, void *user_data )
     5         kx {
     5         kx   struct pkgrc *pkgrc = (struct pkgrc *)data;
     5         kx   if( pkgrc ) { pkgrc_free( pkgrc ); }
     5         kx }
     5         kx 
     5         kx static void free_pkgrcl( void )
     5         kx {
     5         kx   if( pkgrcl ) { dlist_free( pkgrcl, __pkgrc_free_func ); pkgrcl = NULL; }
     5         kx }
     5         kx 
     5         kx static void add_pkgrc( struct pkgrc *pkgrc )
     5         kx {
     5         kx   pkgrcl = dlist_append( pkgrcl, (void *)pkgrc );
     5         kx }
     5         kx 
     5         kx static struct pkgrc *find_pkgrc( struct dlist *list, pid_t pid )
     5         kx {
     5         kx   if( !list ) return NULL;
     5         kx 
     5         kx   while( list && list->data )
     5         kx   {
     5         kx     if( ((struct pkgrc *)list->data)->pid == pid ) { return (struct pkgrc *)list->data; }
     5         kx     list = dlist_next( list );
     5         kx   }
     5         kx 
     5         kx   return NULL;
     5         kx }
     5         kx 
     5         kx static void __remove_success_pkgrc( void *data, void *user_data )
     5         kx {
     5         kx   struct pkgrc *pkgrc = (struct pkgrc *)data;
     5         kx 
     5         kx   if( pkgrc && pkgrc->status == 0 )
     5         kx   {
     5         kx     pkgrcl = dlist_remove( pkgrcl, (const void *)data );
     5         kx     pkgrc_free( pkgrc );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void cleanup_pkgrcl( void )
     5         kx {
     5         kx   dlist_foreach( pkgrcl, __remove_success_pkgrc, NULL );
     5         kx }
     5         kx 
     5         kx static void _print_pkgrcl( void *data, void *user_data )
     5         kx {
     5         kx   struct pkgrc *pkgrc = (struct pkgrc *)data;
     5         kx 
     5         kx   if( pkgrc )
     5         kx   {
     5         kx     if( pkgrc->group )
     5         kx       fprintf( stderr, "%s/%s:%s:%d\n", pkgrc->group, pkgrc->name, pkgrc->version, pkgrc->status );
     5         kx     else
     5         kx       fprintf( stderr, "%s:%s:%d\n", pkgrc->name, pkgrc->version, pkgrc->status );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void return_codes_list( void )
     5         kx {
     5         kx   if( pkgrcl )
     5         kx   {
     5         kx     dlist_foreach( pkgrcl, _print_pkgrcl, NULL );
     5         kx   }
     5         kx }
     5         kx /*
     5         kx   End of return status functions.
     5         kx  *********************************************/
     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 char *skip_lead_spaces( char *s )
     5         kx //{
     5         kx //  char *p = (char *)0;
     5         kx //
     5         kx //  if( !s || *s == '\0' ) return p;
     5         kx //
     5         kx //  p = s; while( isspace( *p ) ) { ++p; }
     5         kx //
     5         kx //  return( p );
     5         kx //}
     5         kx 
     5         kx static char *trim( char *s )
     5         kx {
     5         kx   char *p = (char *)0;
     5         kx 
     5         kx   if( !s || *s == '\0' ) return p;
     5         kx 
     5         kx   p = s + strlen( s ) - 1;
     5         kx   while( isspace( *p ) ) { *p-- = '\0'; }
     5         kx   p = s; while( isspace( *p ) ) { ++p; }
     5         kx 
     5         kx   return( p );
     5         kx }
     5         kx 
     5         kx 
     5         kx static void read_pkglist_file( const char *fname )
     5         kx {
     5         kx   char *ln   = NULL;
     5         kx   char *line = NULL;
     5         kx   int   lnum = 0;
     5         kx 
     5         kx   FILE *fp   = NULL;
     5         kx 
     5         kx   if( !fname || (*fname == '\0') ) return;
     5         kx 
     5         kx   fp = fopen( fname, "r" );
     5         kx   if( !fp )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot open '%s' PKGLIST file", basename( (char *)fname ) );
     5         kx   }
     5         kx 
     5         kx   line = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)line, PATH_MAX );
     5         kx 
     5         kx   while( (ln = fgets( line, PATH_MAX, fp )) )
     5         kx   {
     5         kx     char *p = NULL;
     5         kx     char *name = NULL, *vers = NULL, *desc = NULL, *ball = NULL, *proc = NULL, *prio = NULL;
     5         kx 
     5         kx     ++lnum;
     5         kx 
     5         kx     ln[strlen(ln) - 1] = '\0';  /* replace new-line symbol */
     5         kx     ln = trim( ln ); /* remove leading and trailing spaces */
     5         kx 
     5         kx     if( *ln == '#' )
     5         kx     {
     5         kx       if( !strncmp( ln, "# required:", 11 ) )
     5         kx       {
     5         kx         char *n = NULL, *v = NULL, *g = NULL, *q = NULL;
     5         kx         char *rq = ln + 11;
     5         kx         rq = trim( rq );
     5         kx 
     5         kx         n = rq;
     5         kx         if( (q = index( (const char *)n, '/' )) ) { *q = '\0'; g = n; n = ++q; g = trim( g ); }
     5         kx         if( (q = index( (const char *)n, '=' )) ) { *q = '\0'; v = ++q; n = trim( n ); }
     5         kx         v = trim( v );
     5         kx 
     5         kx         if( n && v  )
     5         kx         {
     5         kx           struct pkg *pkg = pkg_alloc();
     5         kx 
     5         kx           pkg->name    = xstrdup( (const char *)n );
     5         kx           pkg->version = xstrdup( (const char *)v );
     5         kx           if( g )
     5         kx             pkg->group = xstrdup( (const char *)g );
     5         kx 
     5         kx           add_required( pkg );
     5         kx         }
     5         kx       }
     5         kx       continue; /* skip commented lines */
     5         kx     }
     5         kx 
     5         kx     name = ln;
     5         kx     if( (p = index( (const char *)name, ':' )) ) { *p = '\0'; vers = ++p; name = trim( name ); } else continue;
     5         kx     if( (p = index( (const char *)vers, ':' )) ) { *p = '\0'; desc = ++p; vers = trim( vers ); } else continue;
     5         kx     if( (p = index( (const char *)desc, ':' )) ) { *p = '\0'; ball = ++p; desc = trim( desc ); } else continue;
     5         kx     if( (p = index( (const char *)ball, ':' )) ) { *p = '\0'; proc = ++p; ball = trim( ball ); } else continue;
     5         kx     if( (p = index( (const char *)proc, ':' )) ) { *p = '\0'; prio = ++p; proc = trim( proc ); } else continue;
     5         kx     prio = trim( prio );
     5         kx 
     5         kx     if( name && vers && desc && ball && proc && prio )
     5         kx     {
     5         kx       char  *buf = NULL;
     5         kx       struct package *package = NULL;
     5         kx       char  *group = index( (const char *)ball, '/' );
     5         kx       enum _priority priority = OPTIONAL;
     5         kx 
     5         kx       /*******************
     5         kx         Package priority:
     5         kx        */
     5         kx       if( strlen( (const char*)prio ) > 2 )
     5         kx       {
     5         kx         char *match = NULL;
     5         kx 
     5         kx         to_lowercase( prio );
     5         kx         if( (match = strstr( prio, "req" )) && match == prio ) {
     5         kx           priority = REQUIRED;
     5         kx         }
     5         kx         else if( (match = strstr( prio, "rec" )) && match == prio ) {
     5         kx           priority = RECOMMENDED;
     5         kx         }
     5         kx         else if( (match = strstr( prio, "opt" )) && match == prio ) {
     5         kx           priority = OPTIONAL;
     5         kx         }
     5         kx         else if( (match = strstr( prio, "sk" )) && match == prio ) {
     5         kx           priority = SKIP;
     5         kx         }
     5         kx         else {
     5         kx           FATAL_ERROR( "%s: %d: Unknown '%s' priority value", basename( pkglist_fname ), lnum, prio );
     5         kx         }
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         FATAL_ERROR( "%s: %d: Unknown '%s' priority value", basename( pkglist_fname ), lnum, prio );
     5         kx       }
     5         kx 
     5         kx       if( priority > install_priority ) continue;
     5         kx 
     5         kx       buf = (char *)malloc( (size_t)PATH_MAX );
     5         kx       if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)buf, PATH_MAX );
     5         kx 
     5         kx       package = package_alloc();
     5         kx 
     5         kx       package->name        = xstrdup( (const char *)name );
     5         kx       package->version     = xstrdup( (const char *)vers );
     5         kx       package->description = xstrdup( (const char *)desc );
     5         kx 
     5         kx       (void)sprintf( buf, "%s/%s", (const char *)srcdir, (const char *)ball );
     5         kx       {
     5         kx         enum _input_type type = IFMT_UNKNOWN;
     5         kx         char             uncompress = '\0';
     5         kx 
     5         kx         type = check_package_file( &uncompress, (const char *)&buf[0] );
     5         kx         if( type != IFMT_PKG )
     5         kx         {
     5         kx           FATAL_ERROR( "Unknown format of '%s' package file", (const char *)&buf[0] );
     5         kx         }
     5         kx       }
     5         kx       package->tarball     = xstrdup( (const char *)&buf[0] );
     5         kx 
     5         kx       free( buf );
     5         kx 
     5         kx       package->priority = priority;
     5         kx 
     5         kx       /********************
     5         kx         Install procedure:
     5         kx        */
     5         kx       if( strlen( (const char*)proc ) > 5 )
     5         kx       {
     5         kx         char *match = NULL;
     5         kx 
     5         kx         to_lowercase( proc );
     5         kx         if( (match = strstr( proc, "install" )) && match == proc ) {
     5         kx           package->procedure = INSTALL;
     5         kx         }
     5         kx         else if( (match = strstr( proc, "update" )) && match == proc ) {
     5         kx           package->procedure = UPDATE;
     5         kx         }
     5         kx         else {
     5         kx           FATAL_ERROR( "%s: %d: Unknown '%s' procedure value", basename( pkglist_fname ), lnum, proc );
     5         kx         }
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         FATAL_ERROR( "%s: %d: Unknown '%s' procedure value", basename( pkglist_fname ), lnum, proc );
     5         kx       }
     5         kx 
     5         kx       if( group )
     5         kx       {
     5         kx         *group = '\0';
     5         kx         group = ball;
     5         kx         package->group = xstrdup( (const char *)group );
     5         kx       }
     5         kx 
     5         kx       add_package( package );
     5         kx     }
     5         kx 
     5         kx   } /* End of while( ln = fgets( line ) ) */
     5         kx 
     5         kx   free( line );
     5         kx   fclose( fp );
     5         kx }
     5         kx 
     5         kx 
     5         kx static void check_requires( void )
     5         kx {
     5         kx   if( requires )
     5         kx   {
     5         kx     exit_status = 1;
     5         kx 
     5         kx     fprintf( stdout, "\nThe input '%s' has the list of %d required packages.\n\n", basename( pkglist_fname ), dlist_length( requires ) );
     5         kx 
     5         kx     if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
     5         kx     free_resources();
     5         kx     exit( exit_status );
     5         kx   }
     5         kx }
     5         kx 
     5         kx #if defined( HAVE_DIALOG )
     5         kx static DIALOG_LISTITEM *alloc_select_items( void )
     5         kx {
     5         kx   DIALOG_LISTITEM *items   = NULL;
     5         kx   int i = 0, num = dlist_length( packages );
     5         kx   struct dlist *list = packages, *next = NULL;
     5         kx 
     5         kx   items = (DIALOG_LISTITEM *)malloc( (num + 1) * sizeof(DIALOG_LISTITEM) );
     5         kx   if( !items )  { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)items, (num + 1) * sizeof(DIALOG_LISTITEM) );
     5         kx 
     5         kx   while( list )
     5         kx   {
     5         kx     struct package *package = NULL;
     5         kx 
     5         kx     next = dlist_next( list );
     5         kx     package = (struct package *)list->data;
     5         kx     if( package )
     5         kx     {
     5         kx #define COLUMN_LENGHT  23         /* 22 symbols for name + " [UP] " */
     5         kx #define NAME_LENGHT    (COLUMN_LENGHT - 7) /* strlen(" [UP] ") + 1; */
     5         kx #define UPDATE_SUFFIX  " [UP] "
     5         kx #define INSTALL_SUFFIX " [in] "
     5         kx 
     5         kx       char *name = (char *)malloc( (size_t)COLUMN_LENGHT );
     5         kx       if( !name ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)name, (size_t)COLUMN_LENGHT );
     5         kx 
     5         kx       if( strlen( package->name ) > (size_t)NAME_LENGHT )
     5         kx       {
     5         kx         (void)strncpy( name, (const char *)package->name, NAME_LENGHT - 2 );
     5         kx         (void)strcat( name, ".." );
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         (void)strcpy( name, (const char *)package->name );
     5         kx       }
     5         kx 
     5         kx       if( package->procedure == UPDATE )
     5         kx       {
     5         kx         int p = strlen( name );
     5         kx         while( p < NAME_LENGHT ) { name[p] = ' '; ++p; }
     5         kx         name[p] = '\0';
     5         kx         (void)strcat( name, UPDATE_SUFFIX );
     5         kx       }
     5         kx       else
     5         kx       {
     5         kx         int p = strlen( name );
     5         kx         /* while( p < (COLUMN_LENGHT - 1) ) { name[p] = ' '; ++p; } */
     5         kx         while( p < NAME_LENGHT ) { name[p] = ' '; ++p; }
     5         kx         name[p] = '\0';
     5         kx         (void)strcat( name, INSTALL_SUFFIX );
     5         kx       }
     5         kx 
     5         kx       items[i].name = name;
     5         kx       items[i].text = xstrdup( (const char *)package->description );
     5         kx       if( package->group )
     5         kx         items[i].help = xstrdup( (const char *)package->group );
     5         kx       items[i].state = 1;
     5         kx     }
     5         kx     ++i;
     5         kx     list = next;
     5         kx   }
     5         kx   return items;
     5         kx }
     5         kx 
     5         kx static void free_select_items( DIALOG_LISTITEM *items )
     5         kx {
     5         kx   DIALOG_LISTITEM *p = items;
     5         kx 
     5         kx   if( !p ) return;
     5         kx 
     5         kx   while( p->name ) { free( p->name ); free( p->text ); if( p->help ) free( p->help ); ++p; }
     5         kx 
     5         kx   free( items );
     5         kx }
     5         kx 
     5         kx static void remove_unselected_packages( DIALOG_LISTITEM *items )
     5         kx {
     5         kx   DIALOG_LISTITEM *p   = items;
     5         kx   struct dlist    *rem = NULL, *list = NULL, *next = NULL;
     5         kx   int              n   = 0;
     5         kx 
     5         kx   if( !p ) return;
     5         kx 
     5         kx   while( p->name )
     5         kx   {
     5         kx     /* copy packages list item to the local list: */
     5         kx     if( !p->state ) { list = dlist_append( list, dlist_nth_data( packages, n ) ); }
     5         kx     ++p; ++n;
     5         kx   }
     5         kx 
     5         kx   /****************************************************
     5         kx     remove items of the local list from packages list:
     5         kx    */
     5         kx   rem = list;
     5         kx   while( rem )
     5         kx   {
     5         kx     next = dlist_next( rem );
     5         kx     packages = dlist_remove( packages, rem->data );
     5         kx     rem = next;
     5         kx   }
     5         kx 
     5         kx   /***************************
     5         kx     free unselected packages:
     5         kx    */
     5         kx   dlist_free( list, __package_free_func );
     5         kx }
     5         kx #endif
     5         kx 
     5         kx 
     5         kx /*********************************************
     5         kx   Progress functions:
     5         kx  */
     5         kx static void show_install_con_progress( const char *title, int percent )
     5         kx {
     5         kx #define GAUGE_LENGTH  68
     5         kx   size_t  prefix = strlen( title ) + 2; /* title + ' [' */
     5         kx   size_t  suffix = 6;                   /* '] 100%' */
     5         kx   size_t  length = prefix  + GAUGE_LENGTH + suffix;
     5         kx   int     i, ctx = GAUGE_LENGTH * percent / 100;
     5         kx 
     5         kx   if( percent <   0 ) percent = 0;
     5         kx   if( percent > 100 ) percent = 100;
     5         kx 
     5         kx   printf( "\033[1A" );               /* move the cursor up 1 line   */
     5         kx   printf( "\033[%dD", (int)length ); /* move cursor to start of line */
     5         kx   printf( "%s [", title );
     5         kx 
     5         kx   for( i = 0; i < ctx; ++i )     { fprintf( stdout, "\u2588" ); }
     5         kx   for( ; i < GAUGE_LENGTH; ++i ) { fprintf( stdout, " " );      }
     5         kx 
     5         kx   printf( "] %3d%%\n", percent );
     5         kx   fflush( stdout );
     5         kx }
     5         kx 
     5         kx static void show_progress( void )
     5         kx {
     5         kx   const char *title   = "Install:";
     5         kx   const char *message = "\n"
     5         kx                         "Please wait for install all specified packages:\n"
     5         kx                         "\n\n";
     5         kx 
     5         kx   if( install_mode != CONSOLE )
     5         kx   {
     5         kx #if defined( HAVE_DIALOG )
     5         kx     show_install_dlg_progress( 0 );
     5         kx #else
     5         kx     fprintf( stdout, "%s", message );
     5         kx     show_install_con_progress( title, 0 );
     5         kx #endif
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     fprintf( stdout, "%s", message );
     5         kx     show_install_con_progress( title, 0 );
     5         kx   }
     5         kx 
     5         kx }
     5         kx 
     5         kx static void update_progress( int percent )
     5         kx {
     5         kx   const char *title   = "Install:";
     5         kx 
     5         kx   if( install_mode != CONSOLE )
     5         kx   {
     5         kx #if defined( HAVE_DIALOG )
     5         kx     show_install_dlg_progress( percent );
     5         kx #else
     5         kx     show_install_con_progress( title, percent );
     5         kx #endif
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     show_install_con_progress( title, percent );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void stop_progress( void )
     5         kx {
     5         kx   const char *title   = "Install:";
     5         kx 
     5         kx   if( install_mode != CONSOLE )
     5         kx   {
     5         kx #if defined( HAVE_DIALOG )
     5         kx     show_install_dlg_progress( 100 );
     5         kx #else
     5         kx     show_install_con_progress( title, 100 );
     5         kx     fprintf( stdout, "\n" );
     5         kx #endif
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     show_install_con_progress( title, 100 );
     5         kx     fprintf( stdout, "\n" );
     5         kx   }
     5         kx }
     5         kx /*
     5         kx   End of progress functions.
     5         kx  *********************************************/
     5         kx 
     5         kx 
     5         kx 
     5         kx /*********************************************
     5         kx   Install functions.
     5         kx  */
     5         kx static void install_package( struct package *package )
     5         kx {
     5         kx   int   len = 0;
     5         kx   char *cmd = NULL, *opt = NULL, *out = "> /dev/null 2>&1";
     5         kx 
     5         kx   if( !package ) return;
     5         kx 
     5         kx   opt = (char *)malloc( (size_t)PATH_MAX );
     5         kx   if( !opt ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)opt, PATH_MAX );
     5         kx   opt[0] = ' ';
     5         kx 
     5         kx   if( gpgck ) (void)sprintf( opt, "--gpg-verify " );
     5         kx   if( (install_mode != CONSOLE) && !parallel && !progress ) (void)strcat( opt, "--info-dialog " );
     5         kx   if( parallel ) (void)strcat( opt, "--ignore-chrefs-errors " );
     5         kx   if( (install_mode == CONSOLE) && !parallel && !progress ) out = " ";
     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,
     5         kx                   "%s/%s-package %s --priority=%s --root=%s %s %s",
     5         kx                   selfdir, strproc( package->procedure ), opt,
     5         kx                   strprio( package->priority, 1 ),
     5         kx                   root, package->tarball, out );
     5         kx   if( len == 0 || len == PATH_MAX - 1 )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot install %s-%s package", package->name, package->version );
     5         kx   }
     5         kx   if( parallel )
     5         kx   {
     5         kx     struct pkgrc *pkgrc = pkgrc_alloc();
     5         kx 
     5         kx     pkgrc->name    = xstrdup( (const char *)package->name );
     5         kx     pkgrc->version = xstrdup( (const char *)package->version );
     5         kx     if( package->group )
     5         kx       pkgrc->group = xstrdup( (const char *)package->group );
     5         kx     pkgrc->pid     = sys_exec_command( cmd );
     5         kx 
     5         kx     add_pkgrc( pkgrc );
     5         kx     ++__child;
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     pid_t p = (pid_t) -1;
     5         kx     int  rc = 0;
     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 && rc != 31 )
     5         kx     {
     5         kx       FATAL_ERROR( "Cannot install '%s-%s' package", package->name, package->version );
     5         kx     }
     5         kx     ++__successful;
     5         kx   }
     5         kx 
     5         kx   free( cmd );
     5         kx   free( opt );
     5         kx }
     5         kx 
     5         kx static void _serial_install_package( void *data, void *user_data )
     5         kx {
     5         kx   struct package *package = (struct package *)data;
     5         kx   int    percent;
     5         kx 
     5         kx   if( package ) { install_package( package ); }
     5         kx 
     5         kx   if( progress )
     5         kx   {
     5         kx     percent = ( __successful < __all ) ? __successful * 100 / __all : 100;
     5         kx     update_progress( percent );
     5         kx   }
     5         kx }
     5         kx 
     5         kx static void serial_install_packages( void )
     5         kx {
     5         kx   if( progress )
     5         kx   {
     5         kx     show_progress();
     5         kx   }
     5         kx 
     5         kx   dlist_foreach( packages, _serial_install_package, NULL );
     5         kx 
     5         kx   if( progress )
     5         kx   {
     5         kx     stop_progress();
     5         kx   }
     5         kx }
     5         kx 
     5         kx 
     5         kx static void *install_process( void *args )
     5         kx {
     5         kx   struct dlist *list = packages, *next = NULL;
     5         kx 
     5         kx   int nstreams = ncpus * 2; /* two concurents for CPU */
     5         kx 
     5         kx   while( list )
     5         kx   {
     5         kx     struct package *package = NULL;
     5         kx 
     5         kx     next = dlist_next( list );
     5         kx     package = (struct package *)list->data;
     5         kx     if( package )
     5         kx     {
     5         kx       install_package( package );
     5         kx     }
     5         kx     list = next;
     5         kx 
     5         kx     /* wait for available CPU: */
     5         kx     while( (__child - __terminated) > nstreams ) usleep( WAIT_USEC_FOR_CHILD );
     5         kx   }
     5         kx 
     5         kx   return NULL;
     5         kx }
     5         kx 
     5         kx static void parallel_install_packages( void )
     5         kx {
     5         kx   pthread_t install_process_id;
     5         kx   int       status;
     5         kx 
     5         kx   /* Start the parallel installation process: */
     5         kx   status = pthread_create( &install_process_id, NULL, install_process, NULL );
     5         kx   if( status != 0 )
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot start parallel installation process" );
     5         kx   }
     5         kx   (void)pthread_detach( install_process_id );
     5         kx }
     5         kx 
     5         kx /*
     5         kx   End of install functions.
     5         kx  *********************************************/
     5         kx 
     5         kx 
     5         kx 
     5         kx 
     5         kx static void dialogrc( void )
     5         kx {
     5         kx   struct stat st;
     5         kx   char  *tmp = 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   /* imagine that the utility is in /sbin directory: */
     5         kx   (void)sprintf( &tmp[0], "%s/../usr/share/%s/.dialogrc", selfdir, PACKAGE_NAME );
     5         kx   if( stat( (const char *)&tmp[0], &st ) == -1 )
     5         kx   {
     5         kx     /* finaly assume that /usr/sbin is a sbindir: */
     5         kx     (void)sprintf( &tmp[0], "%s/../../usr/share/%s/.dialogrc", selfdir, PACKAGE_NAME );
     5         kx   }
     5         kx 
     5         kx   setenv( "DIALOGRC", (const char *)&tmp[0], 1 );
     5         kx 
     5         kx   free( tmp );
     5         kx }
     5         kx 
     5         kx static char *get_curdir( void )
     5         kx {
     5         kx   char *cwd = NULL;
     5         kx 
     5         kx   cwd = (char *)malloc( PATH_MAX );
     5         kx   if( !cwd ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx   bzero( (void *)cwd, PATH_MAX );
     5         kx 
     5         kx   if( getcwd( cwd, (size_t)PATH_MAX ) != NULL )
     5         kx   {
     5         kx     char *p = NULL;
     5         kx     remove_trailing_slash( cwd );
     5         kx     p = xstrdup( (const char *)cwd );
     5         kx     free( cwd );
     5         kx     return p;
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     FATAL_ERROR( "Cannot get absolute path to current directory" );
     5         kx   }
     5         kx 
     5         kx   return (char *)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   ncpus = get_nprocs();
     5         kx 
     5         kx   fatal_error_hook = fatal_error_actions;
     5         kx 
     5         kx   selfdir = get_selfdir();
     5         kx   curdir  = get_curdir();
     5         kx   dialogrc();
     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     Fill requires and packages lists, check package tarballs,
     5         kx     skip unnesessary packages according to --priority option:
     5         kx    */
     5         kx   read_pkglist_file( (const char *)pkglist_fname );
     5         kx 
     5         kx   /* check only the list of requires in the input PKGLIST: */
     5         kx   if( rqck ) check_requires();
     5         kx 
     5         kx #if defined( HAVE_DIALOG )
     5         kx   if( install_mode == MENUDIALOG )
     5         kx   {
     5         kx     int  status = 0, num   = dlist_length( packages );
     5         kx     DIALOG_LISTITEM *items = alloc_select_items();
     5         kx 
     5         kx     status = select_packages_box( items, num, 0, 0 );
     5         kx     if( !status )
     5         kx     {
     5         kx       remove_unselected_packages( items );
     5         kx       free_select_items( items );
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       /* Abort installation: */
     5         kx       if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
     5         kx       free_resources();
     5         kx 
     5         kx       exit( exit_status );
     5         kx     }
     5         kx   }
     5         kx #endif
     5         kx 
     5         kx 
     5         kx   if( parallel )
     5         kx   {
     5         kx     /************************
     5         kx       parallel installation:
     5         kx      */
     5         kx     int percent = 0;
     5         kx 
     5         kx     __all  = dlist_length( packages );
     5         kx     __done = 0; __child = 0;
     5         kx 
     5         kx     __terminated = 0; __successful = 0;
     5         kx 
     5         kx     show_progress();
     5         kx 
     5         kx     parallel_install_packages();
     5         kx 
     5         kx     if( __terminated < __all )
     5         kx     {
     5         kx       while( !__done )
     5         kx       {
     5         kx         percent = ( __terminated < __all ) ? __terminated * 100 / __all : 100;
     5         kx 
     5         kx         update_progress( percent );
     5         kx         usleep( WAIT_USEC_FOR_CHILD );
     5         kx       }
     5         kx     }
     5         kx 
     5         kx     __done = 0; __child = 0;
     5         kx 
     5         kx     stop_progress();
     5         kx 
     5         kx     if( __successful < __terminated ) { percent = __successful * 100 / __terminated; }
     5         kx     else                              { percent = 100; }
     5         kx 
     5         kx     __terminated = 0; __successful = 0;
     5         kx 
     5         kx     if( install_mode != CONSOLE )
     5         kx     {
     5         kx #if defined( HAVE_DIALOG )
     5         kx       char *msg = NULL;
     5         kx 
     5         kx       msg = (char *)malloc( (size_t)80 );
     5         kx       if( !msg ) { FATAL_ERROR( "Cannot allocate memory" ); }
     5         kx       bzero( (void *)msg, 80 );
     5         kx 
     5         kx       (void)sprintf( msg, "\nSuccessfully installed %d%% of %d specified packages.\n", percent, __all );
     5         kx 
     5         kx       (void)info_box( " \\Z0INSTALL PACKAGES\\Zn ", msg, 5, 0, 0 );
     5         kx 
     5         kx       free( msg );
     5         kx #else
     5         kx       fprintf( stdout, "\nSuccessfully installed %d%% of %d specified packages.\n\n", percent, __all );
     5         kx #endif
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       fprintf( stdout, "\nSuccessfully installed %d%% of %d specified packages.\n\n", percent, __all );
     5         kx     }
     5         kx 
     5         kx     cleanup_pkgrcl();  /* remove successfully installed packages from return codes list */
     5         kx     if( pkgrcl && error_pkgs_list )
     5         kx     {
     5         kx       return_codes_list();
     5         kx     }
     5         kx   }
     5         kx   else
     5         kx   {
     5         kx     /**********************
     5         kx       serial installation:
     5         kx      */
     5         kx 
     5         kx     __successful = 0;
     5         kx     __all        = dlist_length( packages );
     5         kx 
     5         kx     serial_install_packages();
     5         kx 
     5         kx     if( install_mode != CONSOLE )
     5         kx     {
     5         kx #if defined( HAVE_DIALOG )
     5         kx       info_box( " \\Z4INSTALL PACKAGES\\Zn ",
     5         kx                 "\nAll of specified packages have been installed.\n", 5, 0, 0 );
     5         kx #else
     5         kx       fprintf( stdout, "\nAll of specified packages have been installed.\n\n" );
     5         kx #endif
     5         kx     }
     5         kx     else
     5         kx     {
     5         kx       fprintf( stdout, "\nAll of specified packages have been installed.\n\n" );
     5         kx     }
     5         kx 
     5         kx   }
     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 }