5 kx
5 kx /**********************************************************************
5 kx
5 kx Copyright 2019 Andrey V.Kosteltsev
5 kx
9 kx Licensed under the Radix cross Linux License, Version 1.0 .
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
9 kx https://radix-linux.su/licenses/LICENSE-1.0-en_US.txt
5 kx
5 kx Unless required by applicable law or agreed to in writing, software
5 kx distributed under the License is distributed on an "AS IS" BASIS,
5 kx WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
5 kx implied.
5 kx
5 kx **********************************************************************/
5 kx
5 kx #include <config.h>
5 kx
5 kx #include <stdlib.h>
5 kx #include <stdio.h>
5 kx #include <sys/types.h>
5 kx #include <stdint.h>
5 kx #include <dirent.h>
5 kx #include <sys/stat.h> /* chmod(2) */
5 kx #include <sys/file.h> /* flock(2) */
5 kx #include <fcntl.h>
5 kx #include <linux/limits.h>
5 kx #include <alloca.h> /* alloca(3) */
5 kx #include <string.h> /* strdup(3) */
5 kx #include <strings.h> /* index(3) */
5 kx #include <libgen.h> /* basename(3) */
5 kx #include <ctype.h> /* tolower(3) */
5 kx #include <errno.h>
5 kx #include <time.h>
5 kx #include <sys/time.h>
5 kx #include <pwd.h>
5 kx #include <grp.h>
5 kx #include <stdarg.h>
5 kx #include <unistd.h>
5 kx
5 kx #include <math.h>
5 kx
5 kx #include <sys/wait.h>
5 kx
5 kx #include <sys/resource.h>
5 kx
5 kx #include <signal.h>
5 kx #if !defined SIGCHLD && defined SIGCLD
5 kx # define SIGCHLD SIGCLD
5 kx #endif
5 kx
5 kx #define _GNU_SOURCE
5 kx #include <getopt.h>
5 kx
5 kx #include <msglog.h>
5 kx #include <wrapper.h>
5 kx #include <system.h>
5 kx #include <dlist.h>
5 kx #include <pkglist.h>
5 kx
5 kx #define PROGRAM_NAME "check-requires"
5 kx
5 kx #include <defs.h>
5 kx
5 kx
5 kx char *program = PROGRAM_NAME;
5 kx char *root = NULL, *pkgs_path = NULL, *pkg_fname = NULL,
5 kx *tmpdir = NULL;
5 kx
5 kx int exit_status = EXIT_SUCCESS; /* errors counter */
5 kx char *selfdir = NULL;
5 kx
5 kx int __done = 0, __child = 0;
5 kx
5 kx enum _input_type {
5 kx IFMT_PKG = 0,
5 kx IFMT_LOG,
5 kx
5 kx IFMT_UNKNOWN
5 kx } input_format = IFMT_PKG;
5 kx
5 kx enum _priority priority = REQUIRED;
5 kx
5 kx
5 kx void free_resources()
5 kx {
5 kx if( root ) { free( root ); root = NULL; }
5 kx if( pkgs_path ) { free( pkgs_path ); pkgs_path = NULL; }
5 kx if( pkg_fname ) { free( pkg_fname ); pkg_fname = NULL; }
5 kx
5 kx if( selfdir ) { free( selfdir ); selfdir = NULL; }
5 kx
5 kx free_tarballs();
5 kx free_packages();
5 kx free_srcpkgs();
5 kx }
5 kx
5 kx void usage()
5 kx {
5 kx free_resources();
5 kx
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Usage: %s [options] <package|pkglog>\n", program );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "This utility checks if packages required by requested package are\n" );
5 kx fprintf( stdout, "instaled. If there are non-installed packages or packages have to\n" );
5 kx fprintf( stdout, "updated then the list of non-installed packages is output to the\n" );
5 kx fprintf( stdout, "standard error stream.\n" );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Options:\n" );
5 kx fprintf( stdout, " -h,--help Display this information.\n" );
5 kx fprintf( stdout, " -v,--version Display the version of %s utility.\n", program );
5 kx fprintf( stdout, " -r,--root=<DIR> Target rootfs path.\n" );
5 kx
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Parameter:\n" );
5 kx fprintf( stdout, " <package|pkglog> The PACKAGE tarball or PKGLOG.\n" );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "The list of required packages prints out in following format:\n" );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "app/attr:2.4.47:PROCEDURE\n" );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "where PROCEDURE is:\n" );
5 kx fprintf( stdout, " install - package should be installed; or\n" );
5 kx fprintf( stdout, " update - the old version of required package already instaled\n" );
5 kx fprintf( stdout, " but should be updated to the new version presented\n" );
5 kx fprintf( stdout, " between colon characters.\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 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 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 void fatal_error_actions( void )
5 kx {
5 kx logmsg( errlog, MSG_NOTICE, "Free resources on FATAL error..." );
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx }
5 kx
5 kx void sigint( int signum )
5 kx {
5 kx (void)signum;
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx }
5 kx
5 kx void sigchld( int signum )
5 kx {
5 kx pid_t pid = 0;
5 kx int status;
5 kx
5 kx (void)signum;
5 kx
5 kx while( (pid = waitpid( -1, &status, WNOHANG )) > 0 )
5 kx {
5 kx ; /* One of children with 'pid' is terminated */
5 kx
5 kx if( WIFEXITED( status ) )
5 kx {
5 kx if( (int) WEXITSTATUS (status) > 0 )
5 kx {
5 kx ++exit_status; /* printf( "Child %d returned non zero status: %d\n", pid, (int)WEXITSTATUS (status) ); */
5 kx }
5 kx else
5 kx {
5 kx ; /* printf( "Child %d terminated with status: %d\n", pid, (int)WEXITSTATUS (status) ); */
5 kx }
5 kx }
5 kx else if( WIFSIGNALED( status ) )
5 kx {
5 kx ++exit_status; /* printf( "Child %d terminated on signal: %d\n", pid, WTERMSIG( status ) ); */
5 kx }
5 kx else
5 kx {
5 kx ++exit_status; /* printf( "Child %d terminated on unknown reason\n", pid ); */
5 kx }
5 kx
5 kx }
5 kx
5 kx if( pid == -1 && errno == ECHILD )
5 kx {
5 kx /* No child processes: */
5 kx __done = 1;
5 kx }
5 kx return;
5 kx }
5 kx
5 kx
5 kx static void set_signal_handlers()
5 kx {
5 kx struct sigaction sa;
5 kx sigset_t set;
5 kx
5 kx memset( &sa, 0, sizeof( sa ) );
5 kx sa.sa_handler = sigint; /* TERM, INT */
5 kx sa.sa_flags = SA_RESTART;
5 kx sigemptyset( &set );
5 kx sigaddset( &set, SIGTERM );
5 kx sigaddset( &set, SIGINT );
5 kx sa.sa_mask = set;
5 kx sigaction( SIGTERM, &sa, NULL );
5 kx sigaction( SIGINT, &sa, NULL );
5 kx
5 kx /* System V fork+wait does not work if SIGCHLD is ignored */
5 kx memset( &sa, 0, sizeof( sa ) );
5 kx sa.sa_handler = sigchld; /* CHLD */
5 kx sa.sa_flags = SA_RESTART;
5 kx sigemptyset( &set );
5 kx sigaddset( &set, SIGCHLD );
5 kx sa.sa_mask = set;
5 kx sigaction( SIGCHLD, &sa, NULL );
5 kx
5 kx memset( &sa, 0, sizeof( sa ) ); /* ignore SIGPIPE */
5 kx sa.sa_handler = SIG_IGN;
5 kx sa.sa_flags = 0;
5 kx sigaction( SIGPIPE, &sa, NULL );
5 kx }
5 kx
5 kx
5 kx static enum _input_type check_input_file( char *uncompress, const char *fname )
5 kx {
5 kx struct stat st;
5 kx size_t pkglog_size = 0;
5 kx unsigned char buf[8];
5 kx int rc, fd;
5 kx
5 kx /* SIGNATURES: https://www.garykessler.net/library/file_sigs.html */
5 kx
5 kx if( uncompress )
5 kx {
5 kx *uncompress = '\0';
5 kx }
5 kx
5 kx if( stat( fname, &st ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot access %s file: %s", basename( (char *)fname ), strerror( errno ) );
5 kx }
5 kx
5 kx pkglog_size = st.st_size;
5 kx
5 kx if( (fd = open( fname, O_RDONLY )) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot open %s file: %s", basename( (char *)fname ), strerror( errno ) );
5 kx }
5 kx
5 kx rc = (int)read( fd, (void *)&buf[0], 7 );
5 kx if( rc != 7 )
5 kx {
5 kx close( fd ); return IFMT_UNKNOWN;
5 kx }
5 kx buf[7] = '\0';
5 kx
5 kx /* TEXT */
5 kx if( !strncmp( (const char *)&buf[0], "PACKAGE", 7 ) )
5 kx {
5 kx close( fd ); return IFMT_LOG;
5 kx }
5 kx
5 kx /* GZ */
5 kx if( buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x08 )
5 kx {
5 kx if( uncompress ) { *uncompress = 'x'; }
5 kx close( fd ); return IFMT_PKG;
5 kx }
5 kx
5 kx /* BZ2 */
5 kx if( buf[0] == 0x42 && buf[1] == 0x5A && buf[2] == 0x68 )
5 kx {
5 kx if( uncompress ) { *uncompress = 'j'; }
5 kx close( fd ); return IFMT_PKG;
5 kx }
5 kx
5 kx /* XZ */
5 kx if( buf[0] == 0xFD && buf[1] == 0x37 && buf[2] == 0x7A &&
5 kx buf[3] == 0x58 && buf[4] == 0x5A && buf[5] == 0x00 )
5 kx {
5 kx if( uncompress ) { *uncompress = 'J'; }
5 kx close( fd ); return IFMT_PKG;
5 kx }
5 kx
5 kx if( pkglog_size > 262 )
5 kx {
5 kx if( lseek( fd, 257, SEEK_SET ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot check signature of %s file: %s", basename( (char *)fname ), strerror( errno ) );
5 kx }
5 kx rc = (int)read( fd, &buf[0], 5 );
5 kx if( rc != 5 )
5 kx {
5 kx FATAL_ERROR( "Cannot read signature of %s file", basename( (char *)fname ) );
5 kx }
5 kx /* TAR */
5 kx if( buf[0] == 0x75 && buf[1] == 0x73 && buf[2] == 0x74 && buf[3] == 0x61 && buf[4] == 0x72 )
5 kx {
5 kx close( fd ); return IFMT_PKG;
5 kx }
5 kx }
5 kx
5 kx close( fd ); return IFMT_UNKNOWN;
5 kx }
5 kx
5 kx
5 kx void get_args( int argc, char *argv[] )
5 kx {
5 kx const char* short_options = "hvr:";
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 { "root", required_argument, NULL, 'r' },
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
5 kx case 'r':
5 kx {
5 kx if( optarg != NULL )
5 kx {
5 kx root = xstrdup( (const char *)optarg );
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 '?': default:
5 kx {
5 kx usage();
5 kx break;
5 kx }
5 kx }
5 kx }
5 kx
5 kx
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 if( stat( (const char *)&buf[0], &st ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot access '%s' file: %s", buf, strerror( errno ) );
5 kx }
5 kx
5 kx if( S_ISREG(st.st_mode) )
5 kx {
5 kx pkg_fname = xstrdup( (const char *)&buf[0] );
5 kx free( buf );
5 kx }
5 kx else
5 kx {
5 kx FATAL_ERROR( "Input package '%s' is not a regular file", buf );
5 kx }
5 kx }
5 kx else
5 kx {
5 kx usage();
5 kx }
5 kx
5 kx
5 kx if( !pkgs_path )
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 if( !root )
5 kx {
5 kx buf[0] = '/'; buf[1] = '\0';
5 kx }
5 kx else
5 kx {
5 kx int 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 }
5 kx }
5 kx
5 kx (void)strcat( buf, PACKAGES_PATH );
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
5 kx if( S_ISDIR(st.st_mode) )
5 kx {
5 kx pkgs_path = xstrdup( (const char *)&buf[0] );
5 kx free( buf );
5 kx }
5 kx else
5 kx {
5 kx FATAL_ERROR( "Defined --root '%s' is not a directory", buf );
5 kx }
5 kx
5 kx } /* End if( !pkgs_path ) */
5 kx }
5 kx
5 kx
5 kx /***************************************************************
5 kx Copy functions:
5 kx */
5 kx static void _copy_pkglog( const char *group, const char *fname )
5 kx {
5 kx enum _input_type type = IFMT_UNKNOWN;
5 kx char uncompress = '\0';
5 kx
5 kx type = check_input_file( &uncompress, fname );
5 kx
5 kx if( type == IFMT_LOG )
5 kx {
5 kx int len = 0;
5 kx char *tmp= NULL, *cmd = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx if( group ) { (void)sprintf( &tmp[0], "%s/%s", tmpdir, group ); }
5 kx else { (void)sprintf( &tmp[0], "%s", tmpdir ); }
5 kx
5 kx if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
5 kx {
5 kx ERROR( "Cannot copy '%s' PKGLOG file", basename( (char *)fname ) );
5 kx free( tmp );
5 kx return;
5 kx }
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX, "cp %s %s/ > /dev/null 2>&1", fname, tmp );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot copy %s PKGLOG file", basename( (char *)fname ) );
5 kx }
5 kx (void)sys_exec_command( cmd );
5 kx ++__child;
5 kx
5 kx free( tmp );
5 kx free( cmd );
5 kx }
5 kx }
5 kx
5 kx static void _search_pkglogs( const char *dirpath, const char *grp )
5 kx {
5 kx DIR *dir;
5 kx char *path;
5 kx size_t len;
5 kx
5 kx struct stat path_sb, entry_sb;
5 kx struct dirent *entry;
5 kx
5 kx if( stat( dirpath, &path_sb ) == -1 )
5 kx {
5 kx FATAL_ERROR( "%s: Cannot stat Setup Database or destination directory", dirpath );
5 kx }
5 kx
5 kx if( S_ISDIR(path_sb.st_mode) == 0 )
5 kx {
5 kx FATAL_ERROR( "%s: Setup Database or destination is not a directory", dirpath );
5 kx }
5 kx
5 kx if( (dir = opendir(dirpath) ) == NULL )
5 kx {
5 kx FATAL_ERROR( "Canot access %s directory: %s", dirpath, strerror( errno ) );
5 kx }
5 kx
5 kx len = strlen( dirpath );
5 kx
5 kx while( (entry = readdir( dir )) != NULL)
5 kx {
5 kx /* skip entries '.' and '..' */
5 kx if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
5 kx
5 kx /* determinate a full name of an entry */
5 kx path = alloca( len + strlen( entry->d_name ) + 2 );
5 kx
5 kx strcpy( path, dirpath );
5 kx strcat( path, "/" );
5 kx strcat( path, entry->d_name );
5 kx
5 kx if( stat( path, &entry_sb ) == 0 )
5 kx {
5 kx if( S_ISREG(entry_sb.st_mode) )
5 kx {
5 kx _copy_pkglog( grp, (const char *)path );
5 kx }
5 kx if( S_ISDIR(entry_sb.st_mode) && grp == NULL )
5 kx {
5 kx _search_pkglogs( (const char *)path, (const char *)entry->d_name );
5 kx }
5 kx }
5 kx /* else { stat() returns error code; errno is set; and we have to continue the loop } */
5 kx }
5 kx
5 kx closedir( dir );
5 kx }
5 kx
5 kx /***********************************************************
5 kx copy_pkglogs() - returns number of copied PKGLOGS or 0 if
5 kx no PKGLOGS found in the destination
5 kx directory (SETUP_DB_PATH).
5 kx The exit_status has been set.
5 kx */
5 kx int copy_pkglogs( void )
5 kx {
5 kx int ret = 0;
5 kx
5 kx __done = 0; __child = 0;
5 kx
5 kx _search_pkglogs( (const char *)pkgs_path, NULL );
5 kx
5 kx if( __child > 0 )
5 kx {
5 kx while( !__done ) usleep( 1 );
5 kx ret = __child;
5 kx }
5 kx
5 kx __done = 0; __child = 0;
5 kx
5 kx return ret;
5 kx }
5 kx /*
5 kx Enf of Copy functions.
5 kx ***********************************************************/
5 kx
5 kx
5 kx /***********************************************************
5 kx Remove leading spaces and take non-space characters only:
5 kx (Especialy for pkginfo lines)
5 kx */
5 kx static char *skip_spaces( char *s )
5 kx {
5 kx char *q, *p = (char *)0;
5 kx
5 kx if( !s || *s == '\0' ) return p;
5 kx
5 kx p = s;
5 kx
5 kx while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p;
5 kx while( *q != ' ' && *q != '\t' && *q != '\0' ) { ++q; } *q = '\0';
5 kx
5 kx if( *p == '\0' ) return (char *)0;
5 kx
5 kx return( xstrdup( (const char *)p ) );
5 kx }
5 kx
5 kx
5 kx /*******************************
5 kx remove spaces at end of line:
5 kx */
5 kx static void skip_eol_spaces( char *s )
5 kx {
5 kx char *p = (char *)0;
5 kx
5 kx if( !s || *s == '\0' ) return;
5 kx
5 kx p = s + strlen( s ) - 1;
5 kx while( isspace( *p ) ) { *p-- = '\0'; }
5 kx }
5 kx
5 kx static size_t read_usize( char *s )
5 kx {
5 kx size_t size = 0;
5 kx size_t mult = 1;
5 kx double sz = 0.0;
5 kx
5 kx char suffix;
5 kx char *q, *p = (char *)0;
5 kx
5 kx if( !s || *s == '\0' ) return size;
5 kx
5 kx p = s;
5 kx
5 kx while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p;
5 kx while( *q != ' ' && *q != '\t' && *q != '\0' ) { ++q; } *q = '\0';
5 kx
5 kx if( *p == '\0' ) return size;
5 kx
5 kx --q;
5 kx suffix = *q;
5 kx switch( suffix )
5 kx {
5 kx /* by default size calculates in KiB - 1024 Bytes (du -s -h .) */
5 kx case 'G':
5 kx case 'g':
5 kx mult = 1024 * 1024;
5 kx *q = '\0';
5 kx break;
5 kx case 'M':
5 kx case 'm':
5 kx mult = 1024;
5 kx *q = '\0';
5 kx break;
5 kx case 'K':
5 kx case 'k':
5 kx *q = '\0';
5 kx break;
5 kx default:
5 kx break;
5 kx }
5 kx
5 kx if( sscanf( p, "%lg", &sz ) != 1 ) return size;
5 kx
5 kx return (size_t)round( sz * (double)mult );
5 kx }
5 kx
5 kx static int read_total_files( char *s )
5 kx {
5 kx int n = 0;
5 kx char *q, *p = (char *)0;
5 kx
5 kx if( !s || *s == '\0' ) return n;
5 kx
5 kx p = s;
5 kx
5 kx while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p;
5 kx while( *q != ' ' && *q != '\t' && *q != '\0' ) { ++q; } *q = '\0';
5 kx
5 kx if( *p == '\0' ) return n;
5 kx
5 kx if( sscanf( p, "%u", &n ) != 1 ) return 0;
5 kx
5 kx return n;
5 kx }
5 kx
5 kx static struct pkg *input_package( const char *pkginfo_fname )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx FILE *pkginfo = NULL;
5 kx
5 kx struct pkg *pkg = NULL;
5 kx char *pkgname = NULL, *pkgver = NULL, *group = NULL;
5 kx
5 kx if( pkginfo_fname != NULL )
5 kx {
5 kx pkginfo = fopen( (const char *)pkginfo_fname, "r" );
5 kx if( !pkginfo )
5 kx {
5 kx FATAL_ERROR( "Cannot open %s file", pkginfo_fname );
5 kx }
5 kx }
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, pkginfo )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( (match = strstr( ln, "pkgname" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) pkgname = skip_spaces( p );
5 kx }
5 kx if( (match = strstr( ln, "pkgver" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) pkgver = skip_spaces( p );
5 kx }
5 kx if( (match = strstr( ln, "group" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) group = skip_spaces( p );
5 kx }
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx if( pkgname && pkgver )
5 kx {
5 kx pkg = pkg_alloc();
5 kx if( pkg )
5 kx {
5 kx if( group )
5 kx {
5 kx pkg->group = group;
5 kx }
5 kx pkg->name = pkgname;
5 kx pkg->version = pkgver;
5 kx }
5 kx
5 kx }
5 kx else
5 kx {
5 kx if( group ) free( group );
5 kx if( pkgname ) free( pkgname );
5 kx if( pkgver ) free( pkgver );
5 kx
5 kx FATAL_ERROR( "Invalid input .PKGINFO file" );
5 kx }
5 kx
5 kx fclose( pkginfo );
5 kx
5 kx return( pkg );
5 kx }
5 kx
5 kx
5 kx static void get_short_description( char *buf, const char *line )
5 kx {
5 kx char *s, *p, *q;
5 kx
5 kx if( buf ) { buf[0] = '\0'; s = buf; }
5 kx if( !line || line[0] == '\0' ) return;
5 kx
5 kx p = index( line, '(' );
5 kx q = index( line, ')' );
5 kx if( p && q && q > p )
5 kx {
5 kx ++p;
5 kx while( *p && p < q )
5 kx {
5 kx *s = *p;
5 kx ++p; ++s;
5 kx }
5 kx *s = '\0';
5 kx }
5 kx else
5 kx {
5 kx /*
5 kx If short description declaration is incorrect at first line
5 kx of description; then we take whole first line of description:
5 kx */
5 kx p = index( line, ':' ); ++p;
5 kx while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; }
5 kx strcpy( buf, p );
5 kx }
5 kx }
5 kx
5 kx
5 kx static int get_references_section( int *start, int *stop, unsigned int *cnt, FILE *log )
5 kx {
5 kx int ret = -1, found = 0;
5 kx
5 kx if( !start || !stop || !cnt ) return ret;
5 kx
5 kx if( log != NULL )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx ++ret;
5 kx *start = 0; *stop = 0;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx if( (match = strstr( ln, "REFERENCE COUNTER:" )) && match == ln ) /* at start of line only */
5 kx {
5 kx *start = ret + 1;
5 kx ++found;
5 kx
5 kx /* Get reference counter */
5 kx {
5 kx unsigned int count;
5 kx int rc;
5 kx
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx rc = sscanf( ln, "REFERENCE COUNTER: %u", &count );
5 kx if( rc == 1 && cnt != NULL )
5 kx {
5 kx *cnt = count;
5 kx }
5 kx }
5 kx }
5 kx if( (match = strstr( ln, "REQUIRES:" )) && match == ln )
5 kx {
5 kx *stop = ret + 1;
5 kx ++found;
5 kx }
5 kx
5 kx ++ret;
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx }
5 kx
5 kx return( ret );
5 kx }
5 kx
5 kx static int get_requires_section( int *start, int *stop, FILE *log )
5 kx {
5 kx int ret = -1, found = 0;
5 kx
5 kx if( !start || !stop ) return ret;
5 kx
5 kx if( log != NULL )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx ++ret;
5 kx *start = 0; *stop = 0;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx if( (match = strstr( ln, "REQUIRES:" )) && match == ln ) /* at start of line only */
5 kx {
5 kx *start = ret + 1;
5 kx ++found;
5 kx }
5 kx if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln )
5 kx {
5 kx *stop = ret + 1;
5 kx ++found;
5 kx }
5 kx
5 kx ++ret;
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx }
5 kx
5 kx return( ret );
5 kx }
5 kx
5 kx static int get_description_section( int *start, int *stop, FILE *log )
5 kx {
5 kx int ret = -1, found = 0;
5 kx
5 kx if( !start || !stop ) return ret;
5 kx
5 kx if( log != NULL )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx ++ret;
5 kx *start = 0; *stop = 0;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln ) /* at start of line only */
5 kx {
5 kx *start = ret + 1;
5 kx ++found;
5 kx }
5 kx if( (match = strstr( ln, "RESTORE LINKS:" )) && match == ln )
5 kx {
5 kx *stop = ret + 1;
5 kx ++found;
5 kx }
5 kx
5 kx ++ret;
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx }
5 kx
5 kx return( ret );
5 kx }
5 kx
5 kx static int get_restore_links_section( int *start, int *stop, FILE *log )
5 kx {
5 kx int ret = -1, found = 0;
5 kx
5 kx if( !start || !stop ) return ret;
5 kx
5 kx if( log != NULL )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx ++ret;
5 kx *start = 0; *stop = 0;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx if( (match = strstr( ln, "RESTORE LINKS:" )) && match == ln ) /* at start of line only */
5 kx {
5 kx *start = ret + 1;
5 kx ++found;
5 kx }
5 kx if( (match = strstr( ln, "INSTALL SCRIPT:" )) && match == ln )
5 kx {
5 kx *stop = ret + 1;
5 kx ++found;
5 kx }
5 kx
5 kx ++ret;
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx }
5 kx
5 kx return( ret );
5 kx }
5 kx
5 kx
5 kx static int get_install_script_section( int *start, int *stop, FILE *log )
5 kx {
5 kx int ret = -1, found = 0;
5 kx
5 kx if( !start || !stop ) return ret;
5 kx
5 kx if( log != NULL )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx ++ret;
5 kx *start = 0; *stop = 0;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx if( (match = strstr( ln, "INSTALL SCRIPT:" )) && match == ln ) /* at start of line only */
5 kx {
5 kx *start = ret + 1;
5 kx ++found;
5 kx }
5 kx if( (match = strstr( ln, "FILE LIST:" )) && match == ln )
5 kx {
5 kx *stop = ret + 1;
5 kx ++found;
5 kx }
5 kx
5 kx ++ret;
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx ret = ( found == 2 ) ? 0 : 1; /* 0 - success; 1 - not found. */
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx }
5 kx
5 kx return( ret );
5 kx }
5 kx
5 kx
5 kx static int get_file_list_section( int *start, int *stop, FILE *log )
5 kx {
5 kx int ret = -1, found = 0;
5 kx
5 kx if( !start || !stop ) return ret;
5 kx
5 kx if( log != NULL )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx ++ret;
5 kx *start = 0; *stop = 0;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx if( (match = strstr( ln, "FILE LIST:" )) && match == ln ) /* at start of line only */
5 kx {
5 kx *start = ret + 1;
5 kx ++found;
5 kx }
5 kx
5 kx ++ret;
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx ret = ( found == 1 ) ? 0 : 1; /* 0 - success; 1 - not found. */
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx }
5 kx
5 kx return( ret );
5 kx }
5 kx
5 kx
5 kx int read_pkginfo( FILE *log, struct package *package )
5 kx {
5 kx int ret = -1;
5 kx
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx char *pkgname_pattern = "PACKAGE NAME:",
5 kx *pkgver_pattern = "PACKAGE VERSION:",
5 kx *arch_pattern = "ARCH:",
5 kx *distroname_pattern = "DISTRO:",
5 kx *distrover_pattern = "DISTRO VERSION:",
5 kx *group_pattern = "GROUP:",
5 kx *url_pattern = "URL:",
5 kx *license_pattern = "LICENSE:",
5 kx *uncompressed_size_pattern = "UNCOMPRESSED SIZE:",
5 kx *total_files_pattern = "TOTAL FILES:";
5 kx
5 kx
5 kx if( !log || !package ) return ret;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx ++ret;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( (match = strstr( ln, pkgname_pattern )) && match == ln ) /* at start of line only */
5 kx {
5 kx package->pkginfo->name = skip_spaces( ln + strlen( pkgname_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, pkgver_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->version = skip_spaces( ln + strlen( pkgver_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, arch_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->arch = skip_spaces( ln + strlen( arch_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, distroname_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->distro_name = skip_spaces( ln + strlen( distroname_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, distrover_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->distro_version = skip_spaces( ln + strlen( distrover_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, group_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->group = skip_spaces( ln + strlen( group_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, url_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->url = skip_spaces( ln + strlen( url_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, license_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->license = skip_spaces( ln + strlen( license_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, uncompressed_size_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->uncompressed_size = read_usize( ln + strlen( uncompressed_size_pattern ) );
5 kx }
5 kx if( (match = strstr( ln, total_files_pattern )) && match == ln )
5 kx {
5 kx package->pkginfo->total_files = read_total_files( ln + strlen( total_files_pattern ) );
5 kx }
5 kx
5 kx if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln )
5 kx {
5 kx char *buf = NULL;
5 kx
5 kx buf = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !buf )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx /* Get short_description from PACKAGE DESCRIPTION */
5 kx ln = fgets( line, PATH_MAX, log );
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx
5 kx bzero( (void *)buf, PATH_MAX );
5 kx get_short_description( buf, (const char *)line );
5 kx if( buf[0] != '\0' )
5 kx {
5 kx package->pkginfo->short_description = xstrdup( (const char *)buf );
5 kx }
5 kx free( buf );
5 kx }
5 kx
5 kx } /* End of while() */
5 kx
5 kx free( line );
5 kx
5 kx if( package->pkginfo->name == NULL ) ++ret;
5 kx if( package->pkginfo->version == NULL ) ++ret;
5 kx if( package->pkginfo->arch == NULL ) ++ret;
5 kx if( package->pkginfo->distro_name == NULL ) ++ret;
5 kx if( package->pkginfo->distro_version == NULL ) ++ret;
5 kx /* group can be equal to NULL */
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx
5 kx return( ret );
5 kx }
5 kx
5 kx
5 kx static unsigned int read_references( FILE *log, int start, unsigned int *cnt, struct package *package )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx char *p = NULL, *group = NULL, *name = NULL, *version = NULL;
5 kx int n = 1;
5 kx
5 kx unsigned int counter, pkgs = 0;
5 kx
5 kx struct pkg *pkg = NULL;
5 kx
5 kx if( !log || !cnt || *cnt == 0 || !package ) return pkgs;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx counter = *cnt;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
5 kx
5 kx n = 0;
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( strstr( ln, "REQUIRES:" ) ) break; /* if cnt greater than real number of references */
5 kx
5 kx if( n < counter )
5 kx {
5 kx if( (p = index( (const char *)ln, '=' )) )
5 kx {
5 kx *p = '\0'; version = ++p;
5 kx if( (p = index( (const char *)ln, '/' )) )
5 kx {
5 kx *p = '\0'; name = ++p; group = (char *)&ln[0];
5 kx }
5 kx else
5 kx {
5 kx name = (char *)&ln[0]; group = NULL;
5 kx }
5 kx
5 kx pkg = pkg_alloc();
5 kx
5 kx if( group ) pkg->group = xstrdup( (const char *)group );
5 kx pkg->name = xstrdup( (const char *)name );
5 kx pkg->version = xstrdup( (const char *)version );
5 kx
5 kx add_reference( package, pkg );
5 kx ++pkgs;
5 kx }
5 kx ++n;
5 kx }
5 kx else
5 kx break;
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx
5 kx *cnt = pkgs;
5 kx
5 kx return pkgs;
5 kx }
5 kx
5 kx
5 kx static unsigned int read_requires( FILE *log, int start, int stop, struct package *package )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx char *p = NULL, *group = NULL, *name = NULL, *version = NULL;
5 kx int n = 1;
5 kx
5 kx unsigned int pkgs = 0;
5 kx
5 kx struct pkg *pkg = NULL;
5 kx
5 kx if( !log || !package ) return pkgs;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
5 kx
5 kx if( start && start < stop )
5 kx {
5 kx ++n; /* skip section header */
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( strstr( ln, "PACKAGE DESCRIPTION:" ) ) break; /* if (stop - start - 1) greater than real number of requiress */
5 kx
5 kx if( (n > start) && (n < stop) )
5 kx {
5 kx if( (p = index( (const char *)ln, '=' )) )
5 kx {
5 kx *p = '\0'; version = ++p;
5 kx if( (p = index( (const char *)ln, '/' )) )
5 kx {
5 kx *p = '\0'; name = ++p; group = (char *)&ln[0];
5 kx }
5 kx else
5 kx {
5 kx name = (char *)&ln[0]; group = NULL;
5 kx }
5 kx
5 kx pkg = pkg_alloc();
5 kx
5 kx if( group ) pkg->group = xstrdup( (const char *)group );
5 kx pkg->name = xstrdup( (const char *)name );
5 kx pkg->version = xstrdup( (const char *)version );
5 kx
5 kx add_required( package, pkg );
5 kx ++pkgs;
5 kx }
5 kx
5 kx }
5 kx ++n;
5 kx }
5 kx
5 kx } /* End if( start && start < stop ) */
5 kx
5 kx free( line );
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx
5 kx return pkgs;
5 kx }
5 kx
5 kx
5 kx static unsigned int read_description( FILE *log, int start, int stop, struct package *package )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx char *pattern = NULL;
5 kx int n = 1;
5 kx
5 kx char *tmp_fname = NULL;
5 kx FILE *tmp = NULL;
5 kx
5 kx unsigned int lines = 0;
5 kx
5 kx if( !log || !package ) return lines;
5 kx
5 kx tmp_fname = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx bzero( (void *)tmp_fname, PATH_MAX );
5 kx (void)sprintf( (char *)&tmp_fname[0], "%s/.DESCRIPTION", tmpdir );
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx pattern = (char *)malloc( (size_t)strlen( package->pkginfo->name ) + 2 );
5 kx if( !pattern ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx (void)sprintf( pattern, "%s:", package->pkginfo->name );
5 kx
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
5 kx
5 kx if( start && start < stop )
5 kx {
5 kx ++n; /* skip section header */
5 kx
5 kx tmp = fopen( (const char *)&tmp_fname[0], "w" );
5 kx if( !tmp )
5 kx {
5 kx FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( strstr( ln, "RESTORE LINKS:" ) ) break; /* if (stop - start - 1) greater than real number of lines */
5 kx
5 kx if( (n > start) && (n < stop) )
5 kx {
5 kx /*
5 kx skip non-significant spaces at beginning of line
5 kx and print lines started with 'pkgname:'
5 kx */
5 kx if( (match = strstr( ln, pattern )) && lines < DESCRIPTION_NUMBER_OF_LINES )
5 kx {
5 kx int mlen = strlen( match ), plen = strlen( pattern );
5 kx int length = ( mlen > plen ) ? (mlen - plen - 1) : 0 ;
5 kx
5 kx if( length > DESCRIPTION_LENGTH_OF_LINE )
5 kx {
5 kx /* WARNING( "Package DESCRIPTION contains lines with length greater than %d characters", DESCRIPTION_LENGTH_OF_LINE ); */
5 kx match[plen + 1 + DESCRIPTION_LENGTH_OF_LINE] = '\0'; /* truncating description line */
5 kx skip_eol_spaces( match ); /* remove spaces at end-of-line */
5 kx }
5 kx fprintf( tmp, "%s\n", match );
5 kx ++lines;
5 kx }
5 kx
5 kx }
5 kx ++n;
5 kx }
5 kx
5 kx if( lines < (unsigned int)DESCRIPTION_NUMBER_OF_LINES )
5 kx {
5 kx /* WARNING( "Package DESCRIPTION contains less than %d lines", DESCRIPTION_NUMBER_OF_LINES ); */
5 kx while( lines < (unsigned int)DESCRIPTION_NUMBER_OF_LINES )
5 kx {
5 kx fprintf( tmp, "%s\n", pattern );
5 kx ++lines;
5 kx }
5 kx }
5 kx
5 kx fflush( tmp );
5 kx fclose( tmp );
5 kx
5 kx } /* End if( start && start < stop ) */
5 kx
5 kx free( pattern );
5 kx free( line );
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx
5 kx /* read temporary saved description */
5 kx {
5 kx struct stat sb;
5 kx size_t size = 0;
5 kx int fd;
5 kx
5 kx char *desc = NULL;
5 kx
5 kx if( stat( tmp_fname, &sb ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx size = (size_t)sb.st_size;
5 kx
5 kx if( size )
5 kx {
5 kx ssize_t rc = 0;
5 kx
5 kx desc = (char *)malloc( size + 1 );
5 kx if( !desc ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)desc, size + 1 );
5 kx
5 kx if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 )
5 kx {
5 kx FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) );
5 kx }
5 kx
5 kx rc = read( fd, (void *)desc, size );
5 kx if( rc != (ssize_t)size )
5 kx {
5 kx ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx
5 kx package->description = desc;
5 kx
5 kx close( fd );
5 kx }
5 kx
5 kx }
5 kx
5 kx (void)unlink( tmp_fname );
5 kx free( tmp_fname );
5 kx
5 kx return lines;
5 kx }
5 kx
5 kx
5 kx static unsigned int read_restore_links( FILE *log, int start, int stop, struct package *package )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx int n = 1;
5 kx
5 kx char *tmp_fname = NULL;
5 kx FILE *tmp = NULL;
5 kx
5 kx unsigned int lines = 0;
5 kx
5 kx if( !log || !package ) return lines;
5 kx
5 kx tmp_fname = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx bzero( (void *)tmp_fname, PATH_MAX );
5 kx (void)sprintf( (char *)&tmp_fname[0], "%s/.RESTORELINKS", tmpdir );
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
5 kx
5 kx if( start && start < stop )
5 kx {
5 kx ++n; /* skip section header */
5 kx
5 kx tmp = fopen( (const char *)&tmp_fname[0], "w" );
5 kx if( !tmp )
5 kx {
5 kx FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( strstr( ln, "INSTALL SCRIPT:" ) ) break; /* if (stop - start - 1) greater than real number of lines */
5 kx
5 kx if( (n > start) && (n < stop) )
5 kx {
5 kx fprintf( tmp, "%s\n", ln );
5 kx ++lines;
5 kx }
5 kx ++n;
5 kx }
5 kx
5 kx fflush( tmp );
5 kx fclose( tmp );
5 kx
5 kx } /* End if( start && start < stop ) */
5 kx
5 kx free( line );
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx
5 kx /* read temporary saved description */
5 kx {
5 kx struct stat sb;
5 kx size_t size = 0;
5 kx int fd;
5 kx
5 kx char *links = NULL;
5 kx
5 kx if( stat( tmp_fname, &sb ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx size = (size_t)sb.st_size;
5 kx
5 kx if( size )
5 kx {
5 kx ssize_t rc = 0;
5 kx
5 kx links = (char *)malloc( size + 1 );
5 kx if( !links ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)links, size + 1 );
5 kx
5 kx if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 )
5 kx {
5 kx FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) );
5 kx }
5 kx
5 kx rc = read( fd, (void *)links, size );
5 kx if( rc != (ssize_t)size )
5 kx {
5 kx ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx
5 kx package->restore_links = links;
5 kx
5 kx close( fd );
5 kx }
5 kx
5 kx }
5 kx
5 kx (void)unlink( tmp_fname );
5 kx free( tmp_fname );
5 kx
5 kx return lines;
5 kx }
5 kx
5 kx
5 kx static unsigned int read_install_script( FILE *log, int start, int stop, struct package *package )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx int n = 1;
5 kx
5 kx char *tmp_fname = NULL;
5 kx FILE *tmp = NULL;
5 kx
5 kx unsigned int lines = 0;
5 kx
5 kx if( !log || !package ) return lines;
5 kx
5 kx tmp_fname = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx bzero( (void *)tmp_fname, PATH_MAX );
5 kx (void)sprintf( (char *)&tmp_fname[0], "%s/.INSTALL", tmpdir );
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
5 kx
5 kx if( start && start < stop )
5 kx {
5 kx ++n; /* skip section header */
5 kx
5 kx tmp = fopen( (const char *)&tmp_fname[0], "w" );
5 kx if( !tmp )
5 kx {
5 kx FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( strstr( ln, "FILE LIST:" ) ) break; /* if (stop - start - 1) greater than real number of lines */
5 kx
5 kx if( (n > start) && (n < stop) )
5 kx {
5 kx fprintf( tmp, "%s\n", ln );
5 kx ++lines;
5 kx }
5 kx ++n;
5 kx }
5 kx
5 kx fflush( tmp );
5 kx fclose( tmp );
5 kx
5 kx } /* End if( start && start < stop ) */
5 kx
5 kx free( line );
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx
5 kx /* read temporary saved description */
5 kx {
5 kx struct stat sb;
5 kx size_t size = 0;
5 kx int fd;
5 kx
5 kx char *install = NULL;
5 kx
5 kx if( stat( tmp_fname, &sb ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx size = (size_t)sb.st_size;
5 kx
5 kx if( size )
5 kx {
5 kx ssize_t rc = 0;
5 kx
5 kx install = (char *)malloc( size + 1 );
5 kx if( !install ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)install, size + 1 );
5 kx
5 kx if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 )
5 kx {
5 kx FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) );
5 kx }
5 kx
5 kx rc = read( fd, (void *)install, size );
5 kx if( rc != (ssize_t)size )
5 kx {
5 kx ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) );
5 kx }
5 kx
5 kx package->install_script = install;
5 kx
5 kx close( fd );
5 kx }
5 kx
5 kx }
5 kx
5 kx (void)unlink( tmp_fname );
5 kx free( tmp_fname );
5 kx
5 kx return lines;
5 kx }
5 kx
5 kx
5 kx static unsigned int read_file_list( FILE *log, int start, struct package *package )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx int n = 1;
5 kx
5 kx unsigned int files = 0;
5 kx
5 kx if( !log || !package ) return files;
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n;
5 kx
5 kx if( start )
5 kx {
5 kx while( (ln = fgets( line, PATH_MAX, log )) )
5 kx {
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx add_file( package, (const char *)ln );
5 kx ++files;
5 kx }
5 kx
5 kx } /* End if( start && start < stop ) */
5 kx
5 kx free( line );
5 kx
5 kx fseek( log, 0, SEEK_SET );
5 kx
5 kx return files;
5 kx }
5 kx
5 kx
5 kx
5 kx static void _read_pkglog( const char *group, const char *fname )
5 kx {
5 kx FILE *log = NULL;
5 kx char *bname = NULL;
5 kx
5 kx if( fname != NULL )
5 kx {
5 kx log = fopen( (const char *)fname, "r" );
5 kx if( !log )
5 kx {
5 kx FATAL_ERROR( "Cannot open %s file", fname );
5 kx }
5 kx bname = (char *)fname + strlen( tmpdir ) + 1;
5 kx }
5 kx
5 kx if( log != NULL )
5 kx {
5 kx struct package *package = NULL;
5 kx int rc, start, stop;
5 kx unsigned int counter;
5 kx
5 kx package = package_alloc();
5 kx
5 kx if( read_pkginfo( log, package ) != 0 )
5 kx {
5 kx ERROR( "%s: Invalid PKGLOG file", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx
5 kx if( hardware ) package->hardware = xstrdup( (const char *)hardware );
5 kx if( tarballs ) /* find tarball and allocate package->tarball */
5 kx {
5 kx struct pkginfo *info = package->pkginfo;
5 kx const char *tgz = NULL;
5 kx char *buf = NULL;
5 kx struct stat sb;
5 kx
5 kx buf = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx
5 kx if( info->group )
5 kx {
5 kx (void)sprintf( buf, "%s/%s-%s-%s-%s-%s",
5 kx info->group, info->name, info->version, info->arch,
5 kx info->distro_name, info->distro_version );
5 kx }
5 kx else
5 kx {
5 kx (void)sprintf( buf, "%s-%s-%s-%s-%s",
5 kx info->name, info->version, info->arch,
5 kx info->distro_name, info->distro_version );
5 kx }
5 kx tgz = find_tarball( (const char *)&buf[0] );
5 kx if( tgz )
5 kx {
5 kx package->tarball = xstrdup( (const char *)tgz );
5 kx
5 kx bzero( (void *)&buf[0], PATH_MAX );
5 kx (void)sprintf( buf, "%s/%s", pkgs_path, tgz );
5 kx if( stat( buf, &sb ) != -1 )
5 kx {
5 kx info->compressed_size = (size_t)sb.st_size;
5 kx }
5 kx }
5 kx free( buf );
5 kx }
5 kx package->procedure = INSTALL;
5 kx package->priority = priority;
5 kx
5 kx if( package->pkginfo->group && group && strcmp( package->pkginfo->group, group ) != 0 )
5 kx {
5 kx char *tgz;
5 kx
5 kx if( package->tarball ) { tgz = package->tarball; }
5 kx else { tgz = basename( (char *)fname ); }
5 kx
5 kx WARNING( "%s: Should be moved into '%s' subdir", tgz, package->pkginfo->group );
5 kx }
5 kx
5 kx /******************
5 kx read references:
5 kx */
5 kx rc = get_references_section( &start, &stop, &counter, log );
5 kx if( rc != 0 )
5 kx {
5 kx ERROR( "%s: PKGLOG doesn't contains REFERENCE COUNTER section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx if( counter > 0 )
5 kx {
5 kx unsigned int pkgs = counter;
5 kx
5 kx if( read_references( log, start, &counter, package ) != pkgs )
5 kx {
5 kx ERROR( "%s: Invalid REFERENCE COUNTER section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx }
5 kx
5 kx /******************
5 kx read requires:
5 kx */
5 kx rc = get_requires_section( &start, &stop, log );
5 kx if( rc != 0 )
5 kx {
5 kx ERROR( "%s: PKGLOG doesn't contains REQUIRES section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx if( (stop - start) > 1 )
5 kx {
5 kx unsigned int pkgs = (unsigned int)(stop - start - 1); /* -1 skips section header */
5 kx
5 kx if( read_requires( log, start, stop, package ) != pkgs )
5 kx {
5 kx ERROR( "%s: Invalid REQUIRES section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx }
5 kx
5 kx /*******************
5 kx read description:
5 kx */
5 kx rc = get_description_section( &start, &stop, log );
5 kx if( rc != 0 )
5 kx {
5 kx ERROR( "%s: PKGLOG doesn't contains PACKAGE DESCRIPTION section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx if( (stop - start) > 1 )
5 kx {
5 kx if( read_description( log, start, stop, package ) != (unsigned int)DESCRIPTION_NUMBER_OF_LINES )
5 kx {
5 kx ERROR( "%s: Invalid DESCRIPTION section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx }
5 kx
5 kx /*********************
5 kx read restore links:
5 kx */
5 kx rc = get_restore_links_section( &start, &stop, log );
5 kx if( rc != 0 )
5 kx {
5 kx ERROR( "%s: PKGLOG doesn't contains RESTORE LINKS section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx if( (stop - start) > 1 )
5 kx {
5 kx (void)read_restore_links( log, start, stop, package );
5 kx }
5 kx
5 kx /*********************
5 kx read install script:
5 kx */
5 kx rc = get_install_script_section( &start, &stop, log );
5 kx if( rc != 0 )
5 kx {
5 kx ERROR( "%s: PKGLOG doesn't contains INSTALL SCRIPT section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx if( (stop - start) > 1 )
5 kx {
5 kx (void)read_install_script( log, start, stop, package );
5 kx }
5 kx
5 kx /*****************
5 kx read file_list:
5 kx */
5 kx rc = get_file_list_section( &start, &stop, log );
5 kx if( rc != 0 )
5 kx {
5 kx ERROR( "%s: PKGLOG doesn't contains FILE LIST section", bname );
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx if( start )
5 kx {
5 kx unsigned int files = read_file_list( log, start, package );
5 kx if( files == (unsigned int)0 )
5 kx {
5 kx /*
5 kx Packages that do not contain regular files are ignored.
5 kx For example, service package base/init-devices-1.2.3-s9xx-glibc-radix-1.1.txz
5 kx */
5 kx if( ! DO_NOT_PRINTOUT_INFO )
5 kx {
5 kx INFO( "%s: PKGLOG contains empty FILE LIST section", bname );
5 kx }
5 kx package_free( package );
5 kx fclose( log );
5 kx return;
5 kx }
5 kx package->pkginfo->total_files = (int)files;
5 kx }
5 kx
5 kx /*
5 kx Здесь можно организовать проверку пакета на предмет его
5 kx целостности и правильности установки (когда будет готова
5 kx утилита check-package).
5 kx */
5 kx add_package( package );
5 kx
5 kx ++__child;
5 kx fclose( log );
5 kx }
5 kx }
5 kx
5 kx static void _read_pkglogs( const char *dirpath, const char *grp )
5 kx {
5 kx DIR *dir;
5 kx char *path;
5 kx size_t len;
5 kx
5 kx struct stat path_sb, entry_sb;
5 kx struct dirent *entry;
5 kx
5 kx if( stat( dirpath, &path_sb ) == -1 )
5 kx {
5 kx FATAL_ERROR( "%s: Cannot stat Setup Database or destination directory", dirpath );
5 kx }
5 kx
5 kx if( S_ISDIR(path_sb.st_mode) == 0 )
5 kx {
5 kx FATAL_ERROR( "%s: Setup Database or destination is not a directory", dirpath );
5 kx }
5 kx
5 kx if( (dir = opendir(dirpath) ) == NULL )
5 kx {
5 kx FATAL_ERROR( "Canot access %s directory: %s", dirpath, strerror( errno ) );
5 kx }
5 kx
5 kx len = strlen( dirpath );
5 kx
5 kx while( (entry = readdir( dir )) != NULL)
5 kx {
5 kx /* skip entries '.' and '..' */
5 kx if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
5 kx
5 kx /* determinate a full name of an entry */
5 kx path = alloca( len + strlen( entry->d_name ) + 2 );
5 kx
5 kx strcpy( path, dirpath );
5 kx strcat( path, "/" );
5 kx strcat( path, entry->d_name );
5 kx
5 kx if( stat( path, &entry_sb ) == 0 )
5 kx {
5 kx if( S_ISREG(entry_sb.st_mode) )
5 kx {
5 kx if( check_input_file( NULL, (const char *)path ) == IFMT_LOG )
5 kx {
5 kx _read_pkglog( grp, (const char *)path );
5 kx }
5 kx }
5 kx if( S_ISDIR(entry_sb.st_mode) && grp == NULL )
5 kx {
5 kx _read_pkglogs( (const char *)path, (const char *)entry->d_name );
5 kx }
5 kx }
5 kx /* else { stat() returns error code; errno is set; and we have to continue the loop } */
5 kx }
5 kx
5 kx closedir( dir );
5 kx }
5 kx
5 kx int read_pkglogs( void )
5 kx {
5 kx int ret = 0;
5 kx
5 kx __child = 0;
5 kx
5 kx _read_pkglogs( (const char *)tmpdir, NULL );
5 kx
5 kx ret = __child;
5 kx
5 kx __child = 0;
5 kx
5 kx return ret;
5 kx }
5 kx
5 kx
5 kx static void check_pkg_fname( void )
5 kx {
5 kx struct stat st;
5 kx char *fname = pkg_fname;
5 kx
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx
5 kx if( stat( (const char *)fname, &st ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot access input '%s' file: %s", fname, strerror( errno ) );
5 kx }
5 kx
5 kx if( S_ISREG(st.st_mode) )
5 kx {
5 kx struct pkg *srcpkg = NULL;
5 kx
5 kx pid_t p = (pid_t) -1;
5 kx int rc;
5 kx
5 kx int len = 0;
5 kx char *tmp= NULL, *cmd = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx (void)sprintf( &tmp[0], "%s", tmpdir );
5 kx if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGINFO from '%s' file", basename( (char *)fname ) );
5 kx }
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX, "%s/pkginfo -d %s -o pkginfo %s > /dev/null 2>&1", selfdir, tmp, fname );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGINFO from %s file", basename( (char *)fname ) );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx if( rc != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGINFO from '%s' file", basename( (char *)fname ) );
5 kx }
5 kx
5 kx (void)strcat( tmp, "/.PKGINFO" );
5 kx srcpkg = input_package( (const char *)&tmp[0] );
5 kx add_srcpkg( srcpkg );
5 kx *(strstr( tmp, "/.PKGINFO" )) = '\0'; /* :restore tmpdir in tmp[] buffer */
5 kx
5 kx if( check_input_file( NULL, (const char *)fname ) == IFMT_PKG )
5 kx {
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx len = snprintf( &cmd[0], PATH_MAX, "%s/pkglog -m -d %s %s > /dev/null 2>&1", selfdir, tmp, fname );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGLOG from %s file", basename( (char *)fname ) );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx if( rc != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGLOG from '%s' file", basename( (char *)fname ) );
5 kx }
5 kx }
5 kx else
5 kx {
5 kx char *buf = NULL;
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( srcpkg->group ) { (void)sprintf( &buf[0], "%s/%s", tmp, srcpkg->group ); }
5 kx else { (void)sprintf( &buf[0], "%s", tmp ); }
5 kx
5 kx if( _mkdir_p( buf, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot copy '%s' PKGLOG file", basename( (char *)fname ) );
5 kx }
5 kx
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx len = snprintf( &cmd[0], PATH_MAX, "cp %s %s/ > /dev/null 2>&1", fname, buf );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot copy %s PKGLOG file", basename( (char *)fname ) );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx if( rc != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot copy %s PKGLOG file", basename( (char *)fname ) );
5 kx }
5 kx
5 kx free( buf );
5 kx }
5 kx
5 kx free( tmp );
5 kx free( cmd );
5 kx }
5 kx else
5 kx {
5 kx FATAL_ERROR( "Input %s file is not a regular file", basename( (char *)fname ) );
5 kx }
5 kx }
5 kx
5 kx /****************************************************************
5 kx Если после апдейта пакет просто сменил группу, то его надо
5 kx удалить из списка внешних зависимостей, ведь он предоставляет
5 kx нужную функциональность.
5 kx
5 kx Например: libs/libspectre требует libs/cairo, а xlibs/cairo
5 kx требует libs/libspectre, однако libs/libspectre может
5 kx использовать как libs/cairo так и xlibs/cairo .
5 kx
5 kx Search installed package with specified name within any group:
5 kx */
5 kx static char *pkglog_fname = NULL;
5 kx
5 kx static void _probe_pkglog( const char *pname, const char *dirpath, const char *grp )
5 kx {
5 kx DIR *dir;
5 kx char *path;
5 kx size_t len;
5 kx
5 kx struct stat path_sb, entry_sb;
5 kx struct dirent *entry;
5 kx
5 kx if( pkglog_fname ) return;
5 kx
5 kx if( stat( dirpath, &path_sb ) == -1 )
5 kx {
5 kx FATAL_ERROR( "%s: Cannot stat Setup Database or destination directory", dirpath );
5 kx }
5 kx
5 kx if( S_ISDIR(path_sb.st_mode) == 0 )
5 kx {
5 kx FATAL_ERROR( "%s: Setup Database or destination is not a directory", dirpath );
5 kx }
5 kx
5 kx if( (dir = opendir(dirpath) ) == NULL )
5 kx {
5 kx FATAL_ERROR( "Canot access %s directory: %s", dirpath, strerror( errno ) );
5 kx }
5 kx
5 kx len = strlen( dirpath );
5 kx
5 kx while( (entry = readdir( dir )) != NULL)
5 kx {
5 kx /* skip entries '.' and '..' */
5 kx if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
5 kx
5 kx /* determinate a full name of an entry */
5 kx path = alloca( len + strlen( entry->d_name ) + 2 );
5 kx
5 kx strcpy( path, dirpath );
5 kx strcat( path, "/" );
5 kx strcat( path, entry->d_name );
5 kx
5 kx if( stat( path, &entry_sb ) == 0 )
5 kx {
5 kx if( S_ISREG(entry_sb.st_mode) )
5 kx {
5 kx char *match = NULL;
5 kx char *pkglog = basename( path );
5 kx
5 kx if( (match = strstr( pkglog, pname )) && match == pkglog )
5 kx {
5 kx char *buf = NULL, *p = NULL, *q = NULL;
5 kx
5 kx p = q = buf = xstrdup( (const char *)pkglog );
5 kx ++p;
5 kx while( *p != '\0' && !isblank(*p) && !(*q == '-' && isdigit(*p)) )
5 kx {
5 kx /* package version starts with a number and separated by '-' */
5 kx ++p; ++q;
5 kx }
5 kx *(--p) = '\0';
5 kx
5 kx /*******************************************************
5 kx We have to make sure that the name we are looking for
5 kx is not shorter than the name of the found package.
5 kx */
5 kx if( strlen(pname) >= strlen(buf) )
5 kx {
5 kx
5 kx pkglog_fname = xstrdup( (const char *)path );
5 kx free( buf );
5 kx closedir( dir );
5 kx return;
5 kx }
5 kx free( buf );
5 kx }
5 kx }
5 kx if( S_ISDIR(entry_sb.st_mode) && grp == NULL )
5 kx {
5 kx _probe_pkglog( pname, (const char *)path, (const char *)entry->d_name );
5 kx }
5 kx }
5 kx /* else { stat() returns error code; errno is set; and we have to continue the loop } */
5 kx }
5 kx
5 kx closedir( dir );
5 kx }
5 kx
5 kx /******************
5 kx probe_package():
5 kx ---------------
5 kx */
5 kx static char *probe_package( const char *name )
5 kx {
5 kx char *ret = NULL;
5 kx
5 kx _probe_pkglog( name, (const char *)pkgs_path, NULL );
5 kx if( pkglog_fname )
5 kx {
5 kx ret = pkglog_fname;
5 kx }
5 kx
5 kx return ret;
5 kx }
5 kx
5 kx static int check_installed_pkgname( const char *name )
5 kx {
5 kx int ret = 0;
5 kx char *fname = NULL;
5 kx
5 kx if( !name ) return ret;
5 kx
5 kx fname = probe_package( name );
5 kx if( fname )
5 kx {
5 kx ret = 1;
5 kx free( pkglog_fname );
5 kx pkglog_fname = NULL;
5 kx }
5 kx
5 kx return ret;
5 kx }
5 kx /*
5 kx End of search installed package.
5 kx ****************************************************************/
5 kx
5 kx static int __extern_requires = 0;
5 kx
5 kx static void _print_extern_requires( void *data, void *user_data )
5 kx {
5 kx struct pkg *pkg = (struct pkg *)data;
5 kx
5 kx if( pkg && !check_installed_pkgname( (const char *)pkg->name ) )
5 kx {
5 kx if( pkg->group )
5 kx fprintf( stderr, "%s/%s:%s:%s\n", pkg->group, pkg->name, pkg->version, strproc( pkg->procedure ) );
5 kx else
5 kx fprintf( stderr, "%s:%s:%s\n", pkg->name, pkg->version, strproc( pkg->procedure ) );
5 kx
5 kx ++__extern_requires;
5 kx }
5 kx }
5 kx
5 kx static void print_extern_requires( void )
5 kx {
5 kx dlist_foreach( extern_requires, _print_extern_requires, NULL );
5 kx }
5 kx
5 kx
5 kx /*********************************************
5 kx Get directory where this program is placed:
5 kx */
5 kx char *get_selfdir( void )
5 kx {
5 kx char *buf = NULL;
5 kx ssize_t len;
5 kx
5 kx buf = (char *)malloc( PATH_MAX );
5 kx if( !buf )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx bzero( (void *)buf, PATH_MAX );
5 kx len = readlink( "/proc/self/exe", buf, (size_t)PATH_MAX );
5 kx if( len > 0 && len < PATH_MAX )
5 kx {
5 kx char *p = xstrdup( (const char *)dirname( buf ) );
5 kx free( buf );
5 kx return p;
5 kx }
5 kx FATAL_ERROR( "Cannot determine self directory. Please mount /proc filesystem" );
5 kx }
5 kx
5 kx void set_stack_size( void )
5 kx {
5 kx const rlim_t stack_size = 16 * 1024 * 1024; /* min stack size = 16 MB */
5 kx struct rlimit rl;
5 kx int ret;
5 kx
5 kx ret = getrlimit( RLIMIT_STACK, &rl );
5 kx if( ret == 0 )
5 kx {
5 kx if( rl.rlim_cur < stack_size )
5 kx {
5 kx rl.rlim_cur = stack_size;
5 kx ret = setrlimit( RLIMIT_STACK, &rl );
5 kx if( ret != 0 )
5 kx {
5 kx fprintf(stderr, "setrlimit returned result = %d\n", ret);
5 kx FATAL_ERROR( "Cannot set stack size" );
5 kx }
5 kx }
5 kx }
5 kx }
5 kx
5 kx
5 kx int main( int argc, char *argv[] )
5 kx {
5 kx gid_t gid;
5 kx
5 kx set_signal_handlers();
5 kx
5 kx gid = getgid();
5 kx setgroups( 1, &gid );
5 kx
5 kx fatal_error_hook = fatal_error_actions;
5 kx
5 kx selfdir = get_selfdir();
5 kx
5 kx errlog = stderr;
5 kx
5 kx program = basename( argv[0] );
5 kx get_args( argc, argv );
5 kx
5 kx /* set_stack_size(); */
5 kx
5 kx tmpdir = _mk_tmpdir();
5 kx if( !tmpdir )
5 kx {
5 kx FATAL_ERROR( "Cannot create temporary directory" );
5 kx }
5 kx
5 kx /* Copy PKGLOGs into TMPDIR: */
5 kx {
5 kx int pkgs = copy_pkglogs();
5 kx if( pkgs == 0 ) { FATAL_ERROR( "There are no PKGLOG files in the '%s' directory", pkgs_path ); }
5 kx if( exit_status > 0 ) { FATAL_ERROR( "Cannot copy some PKGLOG file" ); }
5 kx if( ! DO_NOT_PRINTOUT_INFO )
5 kx {
5 kx INFO( "Found %d PKGLOG files in the '%s' directory", pkgs, pkgs_path );
5 kx }
5 kx }
5 kx
5 kx /***********************************************************
5 kx Fill srcpkg struct and put or replace pkglog into tmpdir:
5 kx */
5 kx check_pkg_fname();
5 kx
5 kx /* Read PKGLOGs from TMPDIR and create Double Linked List of PACKAGES: */
5 kx {
5 kx int pkgs = read_pkglogs();
5 kx if( pkgs == 0 ) { FATAL_ERROR( "There are no PKGLOG files in the '%s' directory", tmpdir ); }
5 kx if( exit_status > 0 ) { FATAL_ERROR( "Cannot read some PKGLOG file" ); }
5 kx if( ! DO_NOT_PRINTOUT_INFO )
5 kx {
5 kx /* INFO( "Found %d PKGLOG files in the '%s' directory", pkgs, tmpdir ); */
5 kx }
5 kx }
5 kx
5 kx {
5 kx int extern_pkgs = create_provides_list( srcpkgs );
5 kx if( extern_pkgs )
5 kx {
5 kx print_extern_requires();
5 kx if( __extern_requires ) exit_status += 1;
5 kx }
5 kx free_provides_list();
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx
5 kx exit( exit_status );
5 kx }