summaryrefslogtreecommitdiff
path: root/src/chrefs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/chrefs.c')
-rw-r--r--src/chrefs.c1933
1 files changed, 1933 insertions, 0 deletions
diff --git a/src/chrefs.c b/src/chrefs.c
new file mode 100644
index 0000000..8820aea
--- /dev/null
+++ b/src/chrefs.c
@@ -0,0 +1,1933 @@
+
+/**********************************************************************
+
+ Copyright 2019 Andrey V.Kosteltsev
+
+ Licensed under the Radix.pro License, Version 1.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://radix.pro/licenses/LICENSE-1.0-en_US.txt
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied.
+
+ **********************************************************************/
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <dirent.h>
+#include <sys/stat.h> /* chmod(2) */
+#include <sys/file.h> /* flock(2) */
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <alloca.h> /* alloca(3) */
+#include <string.h> /* strdup(3) */
+#include <strings.h> /* index(3) */
+#include <libgen.h> /* basename(3) */
+#include <ctype.h> /* tolower(3) */
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include <sys/resource.h>
+
+#include <signal.h>
+#if !defined SIGCHLD && defined SIGCLD
+# define SIGCHLD SIGCLD
+#endif
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <msglog.h>
+#include <wrapper.h>
+#include <system.h>
+
+#define PROGRAM_NAME "chrefs"
+
+#include <defs.h>
+
+
+char *program = PROGRAM_NAME;
+char *destination = NULL, *operation = NULL, *pkglog_fname = NULL,
+ *tmpdir = NULL, *requires_fname = NULL;
+
+int exit_status = EXIT_SUCCESS; /* errors counter */
+char *selfdir = NULL;
+
+char *pkgname = NULL,
+ *pkgver = NULL,
+ *arch = NULL,
+ *distroname = NULL,
+ *distrover = NULL,
+ *group = NULL;
+
+
+/********************************************
+ *requires[] declarations:
+ */
+struct package {
+ char *name;
+ char *version;
+ char *arch;
+ char *distro_name;
+ char *distro_version;
+};
+
+static struct package *create_package( char *name, char *version,
+ char *arch, char *distro_name,
+ char *distro_version );
+static void free_package( struct package *pkg );
+static struct package **create_requires( size_t size );
+static void free_requires( struct package **requires );
+/*
+ End of *requires[] declarations.
+ ********************************************/
+
+struct package **requires = NULL;
+
+
+/********************************************
+ LOCK FILE declarations:
+ */
+static int __lock_file( FILE *fp );
+static void __unlock_file( int fd );
+/*
+ End of LOCK FILE declarations.
+ ********************************************/
+
+
+#define FREE_PKGINFO_VARIABLES() \
+ if( pkgname ) { free( pkgname ); } pkgname = NULL; \
+ if( pkgver ) { free( pkgver ); } pkgver = NULL; \
+ if( arch ) { free( arch ); } arch = NULL; \
+ if( distroname ) { free( distroname ); } distroname = NULL; \
+ if( distrover ) { free( distrover ); } distrover = NULL; \
+ if( group ) { free( group ); } group = NULL; \
+ if( requires ) { free_requires( requires ); } requires = NULL
+
+void free_resources()
+{
+ if( selfdir ) { free( selfdir ); selfdir = NULL; }
+ if( destination ) { free( destination ); destination = NULL; }
+ if( operation ) { free( operation ); operation = NULL; }
+ if( pkglog_fname ) { free( pkglog_fname ); pkglog_fname = NULL; }
+ if( requires_fname ) { free( requires_fname ); requires_fname = NULL; }
+
+ FREE_PKGINFO_VARIABLES();
+}
+
+void usage()
+{
+ free_resources();
+
+ fprintf( stdout, "\n" );
+ fprintf( stdout, "Usage: %s [options] <pkglog>\n", program );
+ fprintf( stdout, "\n" );
+ fprintf( stdout, "Increment or Decrement reference counters in required PKGLOG files\n" );
+ fprintf( stdout, "in the Setup Database packages directory, which is determined by\n" );
+ fprintf( stdout, "option --destination OR by the directory where the input <pkglog>\n" );
+ fprintf( stdout, "file is located. If destination is defined then <pkglog> file name\n" );
+ fprintf( stdout, "should be defined relative to destination.\n" );
+ fprintf( stdout, "\n" );
+ fprintf( stdout, "Options:\n" );
+ fprintf( stdout, " -h,--help Display this information.\n" );
+ fprintf( stdout, " -v,--version Display the version of %s utility.\n", program );
+ fprintf( stdout, " -d,--destination=<DIR> Setup Database packages directory.\n" );
+ fprintf( stdout, " -o,--operation=<inc|dec> Operation: Increment or Decrement.\n" );
+ fprintf( stdout, "\n" );
+ fprintf( stdout, "Parameter:\n" );
+ fprintf( stdout, " <pkglog> Input PKGLOG file (TEXT format).\n" );
+ fprintf( stdout, "\n" );
+
+ exit( EXIT_FAILURE );
+}
+
+void to_lowercase( char *s )
+{
+ char *p = s;
+ while( p && *p ) { int c = *p; *p = tolower( c ); ++p; }
+}
+
+void to_uppercase( char *s )
+{
+ char *p = s;
+ while( p && *p ) { int c = *p; *p = toupper( c ); ++p; }
+}
+
+void version()
+{
+ char *upper = NULL;
+
+ upper = (char *)alloca( strlen( program ) + 1 );
+
+ strcpy( (char *)upper, (const char *)program );
+ to_uppercase( upper );
+
+ fprintf( stdout, "%s (%s) %s\n", program, upper, PROGRAM_VERSION );
+
+ fprintf( stdout, "Copyright (C) 2019 Andrey V.Kosteltsev.\n" );
+ fprintf( stdout, "This is free software. There is NO warranty; not even\n" );
+ fprintf( stdout, "for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" );
+ fprintf( stdout, "\n" );
+
+ free_resources();
+ exit( EXIT_SUCCESS );
+}
+
+
+static void remove_trailing_slash( char *dir )
+{
+ char *s;
+
+ if( !dir || dir[0] == '\0' ) return;
+
+ s = dir + strlen( dir ) - 1;
+ while( *s == '/' )
+ {
+ *s = '\0'; --s;
+ }
+}
+
+
+static int _mkdir_p( const char *dir, const mode_t mode )
+{
+ char *buf;
+ char *p = NULL;
+ struct stat sb;
+
+ if( !dir ) return -1;
+
+ buf = (char *)alloca( strlen( dir ) + 1 );
+ strcpy( buf, dir );
+
+ remove_trailing_slash( buf );
+
+ /* check if path exists and is a directory */
+ if( stat( buf, &sb ) == 0 )
+ {
+ if( S_ISDIR(sb.st_mode) )
+ {
+ return 0;
+ }
+ }
+
+ /* mkdir -p */
+ for( p = buf + 1; *p; ++p )
+ {
+ if( *p == '/' )
+ {
+ *p = 0;
+ /* test path */
+ if( stat( buf, &sb ) != 0 )
+ {
+ /* path does not exist - create directory */
+ if( mkdir( buf, mode ) < 0 )
+ {
+ return -1;
+ }
+ } else if( !S_ISDIR(sb.st_mode) )
+ {
+ /* not a directory */
+ return -1;
+ }
+ *p = '/';
+ }
+ }
+
+ /* test path */
+ if( stat( buf, &sb ) != 0 )
+ {
+ /* path does not exist - create directory */
+ if( mkdir( buf, mode ) < 0 )
+ {
+ return -1;
+ }
+ } else if( !S_ISDIR(sb.st_mode) )
+ {
+ /* not a directory */
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void _rm_tmpdir( const char *dirpath )
+{
+ DIR *dir;
+ char *path;
+ size_t len;
+
+ struct stat path_sb, entry_sb;
+ struct dirent *entry;
+
+ if( stat( dirpath, &path_sb ) == -1 )
+ {
+ return; /* stat returns error code; errno is set */
+ }
+
+ if( S_ISDIR(path_sb.st_mode) == 0 )
+ {
+ return; /* dirpath is not a directory */
+ }
+
+ if( (dir = opendir(dirpath) ) == NULL )
+ {
+ return; /* Cannot open direcroty; errno is set */
+ }
+
+ len = strlen( dirpath );
+
+ while( (entry = readdir( dir )) != NULL)
+ {
+
+ /* skip entries '.' and '..' */
+ if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
+
+ /* determinate a full name of an entry */
+ path = alloca( len + strlen( entry->d_name ) + 2 );
+ strcpy( path, dirpath );
+ strcat( path, "/" );
+ strcat( path, entry->d_name );
+
+ if( stat( path, &entry_sb ) == 0 )
+ {
+ if( S_ISDIR(entry_sb.st_mode) )
+ {
+ /* recursively remove a nested directory */
+ _rm_tmpdir( path );
+ }
+ else
+ {
+ /* remove a file object */
+ (void)unlink( path );
+ }
+ }
+ /* else { stat() returns error code; errno is set; and we have to continue the loop } */
+
+ }
+
+ /* remove the devastated directory and close the object of this directory */
+ (void)rmdir( dirpath );
+
+ closedir( dir );
+}
+
+
+static char *_mk_tmpdir( void )
+{
+ char *buf = NULL, *p, *tmp = "/tmp";
+ size_t len = 0, size = 0;
+
+ (void)umask( S_IWGRP | S_IWOTH ); /* octal 022 */
+
+ /* Get preferred directory for tmp files */
+ if( (p = getenv( "TMP" )) != NULL ) {
+ tmp = p;
+ }
+ else if( (p = getenv( "TEMP" )) != NULL ) {
+ tmp = p;
+ }
+
+ size = strlen( tmp ) + strlen( DISTRO_NAME ) + strlen( program ) + 12;
+
+ buf = (char *)malloc( size );
+ if( !buf ) return NULL;
+
+ len = snprintf( buf, size, (const char *)"%s/%s/%s-%.7u", tmp, DISTRO_NAME, program, getpid() );
+ if( len == 0 || len == size - 1 )
+ {
+ free( buf ); return NULL;
+ }
+
+ _rm_tmpdir( (const char *)&buf[0] );
+
+ if( _mkdir_p( buf, S_IRWXU | S_IRWXG | S_IRWXO ) == 0 )
+ {
+ return buf;
+ }
+
+ free( buf ); return NULL;
+}
+
+
+/********************************************
+ *requires[] functions:
+ */
+static struct package *create_package( char *name, char *version,
+ char *arch, char *distro_name,
+ char *distro_version )
+{
+ struct package *pkg = (struct package *)0;
+
+ if( !name || *name == '\0' ) return pkg;
+ if( !version || *version == '\0' ) return pkg;
+ if( !arch || *arch == '\0' ) return pkg;
+ if( !distro_name || *distro_name == '\0' ) return pkg;
+ if( !distro_version || *distro_version == '\0' ) return pkg;
+
+ pkg = (struct package *)malloc( sizeof(struct package) );
+ if( pkg )
+ {
+ pkg->name = xstrdup( (const char *)name );
+ pkg->version = xstrdup( (const char *)version );
+ pkg->arch = xstrdup( (const char *)arch );
+ pkg->distro_name = xstrdup( (const char *)distro_name );
+ pkg->distro_version = xstrdup( (const char *)distro_version );
+ }
+
+ return pkg;
+}
+
+static void free_package( struct package *pkg )
+{
+ if( pkg )
+ {
+ if( pkg->name ) free( pkg->name );
+ if( pkg->version ) free( pkg->version );
+ if( pkg->arch ) free( pkg->arch );
+ if( pkg->distro_name ) free( pkg->distro_name );
+ if( pkg->distro_version ) free( pkg->distro_version );
+
+ free( pkg );
+ }
+}
+
+static struct package **create_requires( size_t size )
+{
+ struct package **requires = (struct package **)0;
+
+ if( size > 0 )
+ {
+ requires = (struct package **)malloc( size * sizeof(struct package *) );
+ bzero( (void *)requires, size * sizeof(struct package *) );
+ }
+
+ return( requires );
+}
+
+static void free_requires( struct package **requires )
+{
+ if( requires )
+ {
+ struct package **ptr = requires;
+
+ while( *ptr )
+ {
+ if( *ptr ) free_package( *ptr );
+ ptr++;
+ }
+ free( requires );
+ }
+}
+/*
+ End of *requires[] functions.
+ ********************************************/
+
+
+/********************************************
+ LOCK FILE functions:
+ */
+static int __lock_file( FILE *fp )
+{
+ int fd = fileno( fp );
+
+ if( flock( fd, LOCK_EX ) == -1 )
+ {
+ return -1;
+ /*
+ Мы не проверяем errno == EWOULDBLOCK, так какданная ошибка
+ говорит о том что файл заблокирован другим процессом с флагом
+ LOCK_NB, а мы не собираемся циклически проверять блокировку.
+ У нас все просто: процесс просто ждет освобождения дескриптора
+ и не пытается во время ожидания выполнять другие задачи.
+ */
+ }
+ return fd;
+}
+
+static void __unlock_file( int fd )
+{
+ if( fd != -1 ) flock( fd, LOCK_UN );
+ /*
+ Здесь, в случае ошибки, мы не будем выводить
+ никаких сообщений. Наш процесс выполняет простую
+ атомарную задачу и, наверное, завершится в скором
+ времени, освободив все дескрипторы.
+ */
+}
+/*
+ End of LOCK FILE functions.
+ ********************************************/
+
+
+void fatal_error_actions( void )
+{
+ logmsg( errlog, MSG_NOTICE, "Free resources on FATAL error..." );
+ if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
+ free_resources();
+}
+
+void sigint( int signum )
+{
+ (void)signum;
+
+ if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
+ free_resources();
+}
+
+static void set_signal_handlers()
+{
+ struct sigaction sa;
+ sigset_t set;
+
+ memset( &sa, 0, sizeof( sa ) );
+ sa.sa_handler = sigint; /* TERM, INT */
+ sa.sa_flags = SA_RESTART;
+ sigemptyset( &set );
+ sigaddset( &set, SIGTERM );
+ sigaddset( &set, SIGINT );
+ sa.sa_mask = set;
+ sigaction( SIGTERM, &sa, NULL );
+ sigaction( SIGINT, &sa, NULL );
+
+ memset( &sa, 0, sizeof( sa ) ); /* ignore SIGPIPE */
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigaction( SIGPIPE, &sa, NULL );
+
+ /* System V fork+wait does not work if SIGCHLD is ignored */
+ signal( SIGCHLD, SIG_DFL );
+}
+
+enum _pkglog_type
+{
+ PKGLOG_TEXT = 0,
+ PKGLOG_GZ,
+ PKGLOG_BZ2,
+ PKGLOG_XZ,
+ PKGLOG_TAR,
+
+ PKGLOG_UNKNOWN
+};
+
+static enum _pkglog_type pkglog_type = PKGLOG_UNKNOWN;
+static char uncompress[2] = { 0, 0 };
+
+
+static enum _pkglog_type check_pkglog_file( const char *fname )
+{
+ struct stat st;
+ size_t pkglog_size = 0;
+ unsigned char buf[8];
+ int rc, fd;
+
+ /* SIGNATURES: https://www.garykessler.net/library/file_sigs.html */
+
+ uncompress[0] = '\0';
+
+ if( stat( fname, &st ) == -1 )
+ {
+ FATAL_ERROR( "Cannot access %s file: %s", basename( (char *)fname ), strerror( errno ) );
+ }
+
+ pkglog_size = st.st_size;
+
+ if( (fd = open( fname, O_RDONLY )) == -1 )
+ {
+ FATAL_ERROR( "Cannot open %s file: %s", basename( (char *)fname ), strerror( errno ) );
+ }
+
+ rc = (int)read( fd, (void *)&buf[0], 7 );
+ if( rc != 7 )
+ {
+ FATAL_ERROR( "Unknown type of input file %s", basename( (char *)fname ) );
+ }
+ buf[7] = '\0';
+
+ /* TEXT */
+ if( !strncmp( (const char *)&buf[0], "PACKAGE", 7 ) )
+ {
+ close( fd ); return PKGLOG_TEXT;
+ }
+
+ /* GZ */
+ if( buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x08 )
+ {
+ uncompress[0] = 'x';
+ close( fd ); return PKGLOG_GZ;
+ }
+
+ /* BZ2 */
+ if( buf[0] == 0x42 && buf[1] == 0x5A && buf[2] == 0x68 )
+ {
+ uncompress[0] = 'j';
+ close( fd ); return PKGLOG_BZ2;
+ }
+
+ /* XZ */
+ if( buf[0] == 0xFD && buf[1] == 0x37 && buf[2] == 0x7A &&
+ buf[3] == 0x58 && buf[4] == 0x5A && buf[5] == 0x00 )
+ {
+ uncompress[0] = 'J';
+ close( fd ); return PKGLOG_XZ;
+ }
+
+ if( pkglog_size > 262 )
+ {
+ if( lseek( fd, 257, SEEK_SET ) == -1 )
+ {
+ FATAL_ERROR( "Cannot check signature of %s file: %s", basename( (char *)fname ), strerror( errno ) );
+ }
+ rc = (int)read( fd, &buf[0], 5 );
+ if( rc != 5 )
+ {
+ FATAL_ERROR( "Cannot read signature of %s file", basename( (char *)fname ) );
+ }
+ /* TAR */
+ if( buf[0] == 0x75 && buf[1] == 0x73 && buf[2] == 0x74 && buf[3] == 0x61 && buf[4] == 0x72 )
+ {
+ close( fd ); return PKGLOG_TAR;
+ }
+ }
+
+ close( fd ); return PKGLOG_UNKNOWN;
+}
+
+
+void get_args( int argc, char *argv[] )
+{
+ const char* short_options = "hvd:o:";
+
+ const struct option long_options[] =
+ {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "destination", required_argument, NULL, 'd' },
+ { "operation", required_argument, NULL, 'o' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int ret;
+ int option_index = 0;
+
+ while( (ret = getopt_long( argc, argv, short_options, long_options, &option_index )) != -1 )
+ {
+ switch( ret )
+ {
+ case 'h':
+ {
+ usage();
+ break;
+ }
+ case 'v':
+ {
+ version();
+ break;
+ }
+
+ case 'd':
+ {
+ if( optarg != NULL )
+ {
+ destination = xstrdup( (const char *)optarg );
+ remove_trailing_slash( destination );
+ }
+ else
+ /* option is present but without value */
+ usage();
+ break;
+ }
+ case 'o':
+ {
+ operation = xstrdup( (const char *)optarg );
+ to_lowercase( operation );
+ if( strcmp( operation, "inc" ) != 0 && strcmp( operation, "dec" ) != 0 )
+ {
+ ERROR( "Invalid '%s' operation requested", operation );
+ usage();
+ }
+ break;
+ }
+
+ case '?': default:
+ {
+ usage();
+ break;
+ }
+ }
+ }
+
+
+ if( operation == NULL )
+ {
+ usage();
+ }
+
+ /* last command line argument is the LOGFILE */
+ if( optind < argc )
+ {
+ char *buf = NULL;
+
+ buf = (char *)malloc( (size_t)PATH_MAX );
+ if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
+
+ if( destination == NULL )
+ {
+ pkglog_fname = xstrdup( (const char *)argv[optind++] );
+ if( pkglog_fname == NULL )
+ {
+ FATAL_ERROR( "Unable to set input PKGLOG file name" );
+ }
+
+ bzero( (void *)buf, PATH_MAX );
+ (void)sprintf( buf, "%s", pkglog_fname );
+ destination = xstrdup( (const char *)dirname( buf ) );
+ if( destination == NULL )
+ {
+ FATAL_ERROR( "Unable to set destination directory" );
+ }
+
+ }
+ else
+ {
+ bzero( (void *)buf, PATH_MAX );
+ (void)sprintf( buf, "%s/%s", destination, argv[optind++] );
+ pkglog_fname = xstrdup( (const char *)buf );
+ if( pkglog_fname == NULL )
+ {
+ FATAL_ERROR( "Unable to set inpit PKGLOG file name" );
+ }
+ }
+
+ free( buf );
+
+ pkglog_type = check_pkglog_file( (const char *)pkglog_fname );
+ if( pkglog_type != PKGLOG_TEXT )
+ {
+ ERROR( "%s: Unknown input file format", basename( pkglog_fname ) );
+ usage();
+ }
+
+ }
+ else
+ {
+ usage();
+ }
+}
+
+
+/*
+ Especialy for pkginfo lines.
+ Remove leading spaces and take non-space characters only:
+ */
+static char *skip_spaces( char *s )
+{
+ char *q, *p = (char *)0;
+
+ if( !s || *s == '\0' ) return p;
+
+ p = s;
+
+ while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p;
+ while( *q != ' ' && *q != '\t' && *q != '\0' ) { ++q; } *q = '\0';
+
+ if( *p == '\0' ) return (char *)0;
+
+ return( xstrdup( (const char *)p ) );
+}
+
+
+/*
+ remove spaces at end of line:
+ */
+static void skip_eol_spaces( char *s )
+{
+ char *p = (char *)0;
+
+ if( !s || *s == '\0' ) return;
+
+ p = s + strlen( s ) - 1;
+ while( isspace( *p ) ) { *p-- = '\0'; }
+}
+
+
+
+int get_pkginfo()
+{
+ int ret = -1;
+ FILE *log = NULL;
+
+ if( pkglog_fname != NULL )
+ {
+ log = fopen( (const char *)pkglog_fname, "r" );
+ if( !log )
+ {
+ FATAL_ERROR( "Cannot open %s file", pkglog_fname );
+ }
+ }
+
+ if( log != NULL )
+ {
+ char *ln = NULL;
+ char *line = NULL;
+
+ char *pkgname_pattern = "PACKAGE NAME:",
+ *pkgver_pattern = "PACKAGE VERSION:",
+ *group_pattern = "GROUP:",
+ *arch_pattern = "ARCH:",
+ *distroname_pattern = "DISTRO:",
+ *distrover_pattern = "DISTRO VERSION:";
+
+ int last = 10; /* read first 10 lines only */
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ if( last )
+ {
+ int n = 1;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ char *match = NULL;
+
+ ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
+ skip_eol_spaces( ln ); /* remove spaces at end-of-line */
+
+ if( (match = strstr( ln, pkgname_pattern )) && match == ln ) /* at start of line only */
+ {
+ pkgname = skip_spaces( ln + strlen( pkgname_pattern ) );
+ }
+ if( (match = strstr( ln, pkgver_pattern )) && match == ln )
+ {
+ pkgver = skip_spaces( ln + strlen( pkgver_pattern ) );
+ }
+ if( (match = strstr( ln, arch_pattern )) && match == ln )
+ {
+ arch = skip_spaces( ln + strlen( arch_pattern ) );
+ }
+ if( (match = strstr( ln, distroname_pattern )) && match == ln )
+ {
+ distroname = skip_spaces( ln + strlen( distroname_pattern ) );
+ }
+ if( (match = strstr( ln, distrover_pattern )) && match == ln )
+ {
+ distrover = skip_spaces( ln + strlen( distrover_pattern ) );
+ }
+ if( (match = strstr( ln, group_pattern )) && match == ln )
+ {
+ group = skip_spaces( ln + strlen( group_pattern ) );
+ }
+
+ if( n < last ) ++n;
+ else break;
+
+ } /* End of while() */
+
+ }
+
+ free( line );
+
+ if( pkgname == NULL ) ++ret;
+ if( pkgver == NULL ) ++ret;
+ if( arch == NULL ) ++ret;
+ if( distroname == NULL ) ++ret;
+ if( distrover == NULL ) ++ret;
+ /* group can be equal to NULL */
+
+ fclose( log );
+ }
+
+ return( ret );
+}
+
+
+
+int get_references_section( int *start, int *stop, unsigned int *cnt, FILE *log )
+{
+ int ret = -1, found = 0;
+
+ if( !start || !stop || !cnt ) return ret;
+
+ if( log != NULL )
+ {
+ char *ln = NULL;
+ char *line = NULL;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ char *match = NULL;
+
+ if( (match = strstr( ln, "REFERENCE COUNTER:" )) && match == ln ) /* at start of line only */
+ {
+ *start = ret + 1;
+ ++found;
+
+ /* Get reference counter */
+ {
+ unsigned int count;
+ int rc;
+
+ ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
+ skip_eol_spaces( ln ); /* remove spaces at end-of-line */
+
+ rc = sscanf( ln, "REFERENCE COUNTER: %u", &count );
+ if( rc == 1 && cnt != NULL )
+ {
+ *cnt = count;
+ }
+ }
+ }
+ if( (match = strstr( ln, "REQUIRES:" )) && match == ln )
+ {
+ *stop = ret + 1;
+ ++found;
+ }
+
+ ++ret;
+ }
+
+ free( line );
+
+ ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
+
+ fseek( log, 0, SEEK_SET );
+ }
+
+ return( ret );
+}
+
+
+
+int get_requires_section( int *start, int *stop, const char *log_fname )
+{
+ int ret = -1, found = 0;
+
+ FILE *log = NULL;
+
+ if( !start || !stop ) return ret;
+
+ if( log_fname != NULL )
+ {
+ log = fopen( (const char *)log_fname, "r" );
+ if( !log )
+ {
+ return ret;
+ }
+ }
+
+ if( log != NULL )
+ {
+ char *ln = NULL;
+ char *line = NULL;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ char *match = NULL;
+
+ if( (match = strstr( ln, "REQUIRES:" )) && match == ln ) /* at start of line only */
+ {
+ *start = ret + 1;
+ ++found;
+ }
+ if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln )
+ {
+ *stop = ret + 1;
+ ++found;
+ }
+
+ ++ret;
+ }
+
+ free( line );
+
+ ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
+
+ fclose( log );
+ }
+
+ return( ret );
+}
+
+
+int get_description_section( int *start, int *stop, const char *log_fname )
+{
+ int ret = -1, found = 0;
+
+ FILE *log = NULL;
+
+ if( !start || !stop ) return ret;
+
+ if( log_fname != NULL )
+ {
+ log = fopen( (const char *)log_fname, "r" );
+ if( !log )
+ {
+ return ret;
+ }
+ }
+
+ if( log != NULL )
+ {
+ char *ln = NULL;
+ char *line = NULL;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ char *match = NULL;
+
+ if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln ) /* at start of line only */
+ {
+ *start = ret + 1;
+ ++found;
+ }
+ if( (match = strstr( ln, "RESTORE LINKS:" )) && match == ln )
+ {
+ *stop = ret + 1;
+ ++found;
+ }
+
+ ++ret;
+ }
+
+ free( line );
+
+ ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
+
+ fclose( log );
+ }
+
+ return( ret );
+}
+
+
+int get_restore_links_section( int *start, int *stop, const char *log_fname )
+{
+ int ret = -1, found = 0;
+
+ FILE *log = NULL;
+
+ if( !start || !stop ) return ret;
+
+ if( log_fname != NULL )
+ {
+ log = fopen( (const char *)log_fname, "r" );
+ if( !log )
+ {
+ return ret;
+ }
+ }
+
+ if( log != NULL )
+ {
+ char *ln = NULL;
+ char *line = NULL;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ char *match = NULL;
+
+ if( (match = strstr( ln, "RESTORE LINKS:" )) && match == ln ) /* at start of line only */
+ {
+ *start = ret + 1;
+ ++found;
+ }
+ if( (match = strstr( ln, "INSTALL SCRIPT:" )) && match == ln )
+ {
+ *stop = ret + 1;
+ ++found;
+ }
+
+ ++ret;
+ }
+
+ free( line );
+
+ ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
+
+ fclose( log );
+ }
+
+ return( ret );
+}
+
+
+int get_install_script_section( int *start, int *stop, const char *log_fname )
+{
+ int ret = -1, found = 0;
+
+ FILE *log = NULL;
+
+ if( !start || !stop ) return ret;
+
+ if( log_fname != NULL )
+ {
+ log = fopen( (const char *)log_fname, "r" );
+ if( !log )
+ {
+ return ret;
+ }
+ }
+
+ if( log != NULL )
+ {
+ char *ln = NULL;
+ char *line = NULL;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ char *match = NULL;
+
+ if( (match = strstr( ln, "INSTALL SCRIPT:" )) && match == ln ) /* at start of line only */
+ {
+ *start = ret + 1;
+ ++found;
+ }
+ if( (match = strstr( ln, "FILE LIST:" )) && match == ln )
+ {
+ *stop = ret + 1;
+ ++found;
+ }
+
+ ++ret;
+ }
+
+ free( line );
+
+ ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
+
+ fclose( log );
+ }
+
+ return( ret );
+}
+
+
+int get_file_list_section( int *start, int *stop, const char *log_fname )
+{
+ int ret = -1, found = 0;
+
+ FILE *log = NULL;
+
+ if( !start || !stop ) return ret;
+
+ if( log_fname != NULL )
+ {
+ log = fopen( (const char *)log_fname, "r" );
+ if( !log )
+ {
+ return ret;
+ }
+ }
+
+ if( log != NULL )
+ {
+ char *ln = NULL;
+ char *line = NULL;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+ *stop = 0;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ char *match = NULL;
+
+ if( (match = strstr( ln, "FILE LIST:" )) && match == ln ) /* at start of line only */
+ {
+ *start = ret + 1;
+ ++found;
+ }
+
+ ++ret;
+ }
+
+ free( line );
+
+ ret = ( found == 1 ) ? 0 : 1; /* 0 - success; 1 - not found. */
+
+ fclose( log );
+ }
+
+ return( ret );
+}
+
+
+
+
+/***********************************************************
+ get_requires():
+ --------------
+ if( success ) - returns number of requires
+ if( error ) - returns -1
+ */
+int get_requires( const char *requires, const char *log_fname )
+{
+ int ret = -1;
+ FILE *req = NULL, *log = NULL;
+
+ int start = 0, stop = 0;
+
+ if( get_requires_section( &start, &stop, log_fname ) != 0 )
+ {
+ return ret;
+ }
+
+ if( log_fname != NULL )
+ {
+ log = fopen( (const char *)log_fname, "r" );
+ if( ! log )
+ {
+ return ret;
+ }
+ }
+
+ if( requires != NULL )
+ {
+ req = fopen( (const char *)requires, "w" );
+ if( ! req )
+ {
+ return ret;
+ }
+ }
+
+ /* get PKGLOG sections */
+ {
+ char *ln = NULL;
+ char *line = NULL;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ if( start && start < stop )
+ {
+ int n = 1, lines = 0;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
+ skip_eol_spaces( ln ); /* remove spaces at end-of-line */
+
+ if( (n > start) && (n < stop) )
+ {
+ fprintf( req, "%s\n", ln );
+ ++lines;
+ }
+ ++n;
+ }
+
+ ret = lines; /* number of lines in the LIST */
+ }
+
+ free( line );
+
+ fclose( log );
+ fflush( req ); fclose( req );
+ }
+
+ return( ret );
+}
+
+
+struct package **read_requires( const char *fname, int n )
+{
+ struct package **requires = (struct package **)0;
+ struct package **ptr = (struct package **)0;
+
+ FILE *file;
+
+ if( ! fname ) return NULL;
+
+ requires = create_requires( n + 1 );
+ if( requires )
+ {
+ int i;
+ char *ln = NULL;
+ char *line = NULL;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ struct package *package;
+
+ file = fopen( fname, "r" );
+ if( !file )
+ {
+ free( line );
+ free_requires( requires );
+ return NULL;
+ }
+
+ ptr = requires;
+ for( i = 0; i < n; ++i )
+ {
+ if( (ln = fgets( line, PATH_MAX, file )) )
+ {
+ char *d, *name, *version;
+
+ ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
+ skip_eol_spaces( ln ); /* remove spaces at end-of-line */
+
+ /* сut 'name=version' by delimiter '=': */
+ d = index( ln, '=' ); *d = '\0';
+ version = ++d; name = ln;
+
+ package = create_package( name, version, arch, DISTRO_NAME, DISTRO_VERSION );
+ if( package )
+ {
+ *ptr = package;
+ ptr++;
+ }
+ }
+ }
+ *ptr = (struct package *)0;
+
+ free( line );
+ }
+
+ return requires;
+}
+
+int find_requires( char *pname, const char *grp )
+{
+ char *name = NULL;
+ char *buf = NULL;
+
+ struct package **ptr = requires;
+
+ buf = (char *)malloc( (size_t)PATH_MAX );
+
+ if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
+
+ while( *ptr )
+ {
+ if( grp && *grp != '\0' )
+ {
+ char *p = NULL;
+ size_t len = strlen( (*ptr)->name );
+
+ if( (p = strstr( (*ptr)->name, grp )) && (p == (*ptr)->name) )
+ {
+ /* if group is equal to required package's group then remove group from the name */
+ name = alloca( len + 1 );
+ strcpy( name, (const char *)(*ptr)->name );
+
+ name = index( name, '/' ) + 1;
+ }
+ else
+ {
+ /* if group is not equal to required package's group then add group to the name */
+ name = alloca( len + strlen( grp ) + 2 );
+ (void)sprintf( name, "%s/%s", grp, (const char *)(*ptr)->name );
+ }
+ }
+ else
+ {
+ name = (*ptr)->name;
+ }
+
+ (void)sprintf( buf, "%s-%s-%s-%s-%s",
+ name, (*ptr)->version, (*ptr)->arch,
+ (*ptr)->distro_name, (*ptr)->distro_version );
+
+ if( ! strcmp( buf, pname ) )
+ {
+ free( buf ); return 1;
+ }
+ ptr++;
+ }
+
+ free( buf );
+
+ return 0;
+}
+
+
+int save_tmp_head( FILE *log, int stop, const char *fname )
+{
+ FILE *fp;
+ int ret = -1;
+
+ char *ln = NULL;
+ char *line = NULL;
+ int n = 1, lines = 0;
+
+ if( !stop || !log || !fname || *fname == '\0' ) return ret;
+
+ fp = fopen( fname, "w" );
+ if( !fp )
+ {
+ return ret;
+ }
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
+ skip_eol_spaces( ln ); /* remove spaces at end-of-line */
+
+ if( n < stop )
+ {
+ fprintf( fp, "%s\n", ln );
+ ++n; ++lines;
+ }
+ else
+ break;
+ }
+
+ ret = lines; /* number of lines in the HEAD */
+
+ free( line );
+
+ fseek( log, 0, SEEK_SET );
+ fclose( fp );
+
+ return ret;
+}
+
+int save_tmp_tail( FILE *log, int start, const char *fname )
+{
+ FILE *fp;
+ int ret = -1;
+
+ char *ln = NULL;
+ char *line = NULL;
+ int n = 1, lines = 0;
+
+ if( !start || !log || !fname || *fname == '\0' ) return ret;
+
+ fp = fopen( fname, "w" );
+ if( !fp )
+ {
+ return ret;
+ }
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
+
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
+ skip_eol_spaces( ln ); /* remove spaces at end-of-line */
+
+ fprintf( fp, "%s\n", ln );
+ ++lines;
+ }
+
+ ret = lines; /* number of lines in the TAIL */
+
+ free( line );
+
+ fseek( log, 0, SEEK_SET );
+ fclose( fp );
+
+ return ret;
+}
+
+int write_tmp_part( FILE *log, const char *fname )
+{
+ FILE *fp;
+ int ret = -1;
+
+ char *ln = NULL;
+ char *line = NULL;
+ int lines = 0;
+
+ if( !log || !fname || *fname == '\0' ) return ret;
+
+ fp = fopen( fname, "r" );
+ if( !fp )
+ {
+ return ret;
+ }
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ ++ret;
+
+ while( (ln = fgets( line, PATH_MAX, fp )) )
+ {
+ ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
+ skip_eol_spaces( ln ); /* remove spaces at end-of-line */
+
+ fprintf( log, "%s\n", ln );
+ ++lines;
+ }
+
+ ret = lines; /* number of written lines */
+
+ free( line );
+
+ fclose( fp );
+
+ return ret;
+}
+
+
+
+static char **create_references( size_t size )
+{
+ char **references = (char **)0;
+
+ if( size > 0 )
+ {
+ references = (char **)malloc( size * sizeof(char *) );
+ bzero( (void *)references, size * sizeof(char *) );
+ }
+
+ return( references );
+}
+
+static void free_references( char **references )
+{
+ if( references )
+ {
+ char **ptr = references;
+
+ while( *ptr )
+ {
+ if( *ptr ) free( *ptr );
+ ptr++;
+ }
+ free( references );
+ }
+}
+
+
+static char **get_references( FILE *log, int start, unsigned int *cnt, char *grp, char *name, char *version )
+{
+ char **refs = (char **)0;
+ char **ptr;
+
+ char *ln = NULL;
+ char *line = NULL;
+ int n = 1;
+
+ size_t len = 0;
+
+ unsigned int counter, pkgs;
+
+ char *pkg = NULL;
+
+ if( !log || !cnt || *cnt == 0 || !name || !version ) return refs;
+
+ line = (char *)malloc( (size_t)PATH_MAX );
+ if( !line )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ pkg = (char *)malloc( (size_t)PATH_MAX );
+ if( !pkg )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ counter = *cnt;
+
+ if( grp && *grp != '\0' ) { (void)sprintf( pkg, "%s/%s=", grp, name ); }
+ else { (void)sprintf( pkg, "%s=", name ); }
+
+ len = strlen( pkg );
+
+ refs = ptr = create_references( counter + 1 ); /* null terminated char *references[] */
+
+ while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
+
+ n = 0; pkgs = 0;
+ while( (ln = fgets( line, PATH_MAX, log )) )
+ {
+ ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
+ skip_eol_spaces( ln ); /* remove spaces at end-of-line */
+
+ if( strstr( ln, "REQUIRES:" ) ) break; /* if cnt greater than real number of references */
+
+ if( n < counter )
+ {
+ if( strncmp( ln, pkg, len ) ) /* always remove 'name=version' from list */
+ {
+ if( refs )
+ {
+ *ptr = xstrdup( (const char *)ln ); ++ptr;
+ *ptr = (char *)0;
+ ++pkgs;
+ }
+ }
+ ++n;
+ }
+ else
+ break;
+ }
+
+ free( line ); free( pkg );
+
+ fseek( log, 0, SEEK_SET );
+
+ if( pkgs == 0 )
+ {
+ free_references( refs );
+ refs = (char **)0;
+ }
+
+ *cnt = pkgs;
+
+ return refs;
+}
+
+
+static void _change_references( char *grp, char *name, char *version, const char *log_fname )
+{
+ int fd;
+ FILE *log;
+
+ char *head_fname = NULL, *tail_fname = NULL;
+ int head_lines, tail_lines;
+
+ int rc, start, stop;
+ unsigned int counter;
+
+ int inc = ( strcmp( operation, "inc" ) == 0 ) ? 1 : 0;
+
+ char **references = NULL;
+
+ if( !name || !version || log_fname == NULL ) return;
+ if( check_pkglog_file( log_fname ) != PKGLOG_TEXT ) return;
+
+ log = fopen( (const char *)log_fname, "r+" );
+ if( !log )
+ {
+ ERROR( "Cannot access %s file: %s", log_fname, strerror( errno ) );
+ return;
+ }
+
+ fd = __lock_file( log );
+
+ rc = get_references_section( &start, &stop, &counter, log );
+ if( rc != 0 )
+ {
+ ERROR( "%s: PKGLOG doesn't contains REFERENCE COUNTER section", log_fname );
+ __unlock_file( fd ); fclose( log );
+ return;
+ }
+
+ head_fname = (char *)alloca( strlen( tmpdir ) + 7 );
+ (void)sprintf( head_fname, "%s/.HEAD", tmpdir );
+
+ tail_fname = (char *)alloca( strlen( tmpdir ) + 7 );
+ (void)sprintf( tail_fname, "%s/.TAIL", tmpdir );
+
+ head_lines = save_tmp_head( log, start, (const char *)head_fname );
+ tail_lines = save_tmp_tail( log, stop - 1, (const char *)tail_fname );
+
+ if( head_lines < 10 && tail_lines < 12 )
+ {
+ ERROR( "%s: Invalid PKGLOG file", log_fname );
+ __unlock_file( fd ); fclose( log );
+ return;
+ }
+
+ references = get_references( log, start, &counter, grp, name, version );
+
+ if( ftruncate( fd, 0 ) != 0 )
+ {
+ ERROR( "Cannot change REFERENCE COUNTER in the %s file: %s", log_fname, strerror( errno ) );
+ free_references( references );
+ __unlock_file( fd ); fclose( log );
+ return;
+ }
+
+ head_lines = write_tmp_part( log, (const char *)head_fname );
+
+ if( inc ) ++counter;
+ fprintf( log, "REFERENCE COUNTER: %u\n", counter );
+ if( inc )
+ {
+ if( grp && *grp != '\0' )
+ {
+ fprintf( log, "%s/%s=%s\n", grp, name, version );
+ }
+ else
+ {
+ fprintf( log, "%s=%s\n", name, version );
+ }
+ }
+
+ if( references )
+ {
+ char **ptr = references;
+
+ while( *ptr )
+ {
+ if( *ptr ) fprintf( log, "%s\n", *ptr );
+ ptr++;
+ }
+
+ free_references( references );
+ }
+
+ tail_lines = write_tmp_part( log, (const char *)tail_fname );
+
+ __unlock_file( fd );
+ fclose( log );
+}
+
+
+static void _search_required_packages( const char *dirpath, const char *grp )
+{
+ DIR *dir;
+ char *path;
+ size_t len;
+
+ struct stat path_sb, entry_sb;
+ struct dirent *entry;
+
+ if( stat( dirpath, &path_sb ) == -1 )
+ {
+ FATAL_ERROR( "%s: Cannot stat Setup Database or destination directory", dirpath );
+ }
+
+ if( S_ISDIR(path_sb.st_mode) == 0 )
+ {
+ FATAL_ERROR( "%s: Setup Database or destination is not a directory", dirpath );
+ }
+
+ if( (dir = opendir(dirpath) ) == NULL )
+ {
+ FATAL_ERROR( "Canot access %s directory: %s", dirpath, strerror( errno ) );
+ }
+
+ len = strlen( dirpath );
+
+ while( (entry = readdir( dir )) != NULL)
+ {
+ /* skip entries '.' and '..' */
+ if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
+
+ /* determinate a full name of an entry */
+ path = alloca( len + strlen( entry->d_name ) + 2 );
+
+ strcpy( path, dirpath );
+ strcat( path, "/" );
+ strcat( path, entry->d_name );
+
+ if( stat( path, &entry_sb ) == 0 )
+ {
+ if( S_ISREG(entry_sb.st_mode) )
+ {
+ if( find_requires( entry->d_name, grp ) )
+ {
+ _change_references( group, pkgname, pkgver, (const char *)path );
+ }
+ }
+ if( S_ISDIR(entry_sb.st_mode) && grp == NULL )
+ {
+ _search_required_packages( (const char *)path, (const char *)entry->d_name );
+ }
+ }
+ /* else { stat() returns error code; errno is set; and we have to continue the loop } */
+
+ }
+
+ closedir( dir );
+}
+
+
+
+
+/*********************************************
+ Get directory where this program is placed:
+ */
+char *get_selfdir( void )
+{
+ char *buf = NULL;
+ ssize_t len;
+
+ buf = (char *)malloc( PATH_MAX );
+ if( !buf )
+ {
+ FATAL_ERROR( "Cannot allocate memory" );
+ }
+
+ bzero( (void *)buf, PATH_MAX );
+ len = readlink( "/proc/self/exe", buf, (size_t)PATH_MAX );
+ if( len > 0 && len < PATH_MAX )
+ {
+ char *p = xstrdup( (const char *)dirname( buf ) );
+ free( buf );
+ return p;
+ }
+ FATAL_ERROR( "Cannot determine self directory. Please mount /proc filesystem" );
+}
+
+void set_stack_size( void )
+{
+ const rlim_t stack_size = 16 * 1024 * 1024; /* min stack size = 16 MB */
+ struct rlimit rl;
+ int ret;
+
+ ret = getrlimit( RLIMIT_STACK, &rl );
+ if( ret == 0 )
+ {
+ if( rl.rlim_cur < stack_size )
+ {
+ rl.rlim_cur = stack_size;
+ ret = setrlimit( RLIMIT_STACK, &rl );
+ if( ret != 0 )
+ {
+ fprintf(stderr, "setrlimit returned result = %d\n", ret);
+ FATAL_ERROR( "Cannot set stack size" );
+ }
+ }
+ }
+}
+
+
+int main( int argc, char *argv[] )
+{
+ gid_t gid;
+
+ int ret;
+
+ set_signal_handlers();
+
+ gid = getgid();
+ setgroups( 1, &gid );
+
+ fatal_error_hook = fatal_error_actions;
+
+ selfdir = get_selfdir();
+
+ errlog = stderr;
+
+ program = basename( argv[0] );
+ get_args( argc, argv );
+
+ /* set_stack_size(); */
+
+ exit_status = get_pkginfo();
+ if( exit_status != 0 )
+ {
+ FATAL_ERROR( "%s: Invalid input PKGLOG file", basename( pkglog_fname ) );
+ }
+
+ tmpdir = _mk_tmpdir();
+ if( !tmpdir )
+ {
+ FATAL_ERROR( "Cannot create temporary directory" );
+ }
+ else
+ {
+ char *buf = NULL;
+
+ buf = (char *)malloc( (size_t)strlen( tmpdir ) + 11 );
+ if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
+
+ (void)sprintf( (char *)&buf[0], "%s/.REQUIRES", tmpdir );
+ requires_fname = xstrdup( (const char *)&buf[0] );
+ free( buf );
+ }
+
+ /*******************
+ Getting REQUIRES:
+ */
+ if( (ret = get_requires( (const char *)requires_fname, (const char *)pkglog_fname )) > 0 )
+ {
+ /* We have non-empty list of REQUIRES in the 'requires_fname' file */
+ requires = read_requires( (const char *)requires_fname, ret );
+ _search_required_packages( (const char *)destination, NULL );
+ }
+
+ if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
+ free_resources();
+
+ exit( exit_status );
+}