diff options
Diffstat (limited to 'src/make-pkglist.c')
-rw-r--r-- | src/make-pkglist.c | 3155 |
1 files changed, 3155 insertions, 0 deletions
diff --git a/src/make-pkglist.c b/src/make-pkglist.c new file mode 100644 index 0000000..103d540 --- /dev/null +++ b/src/make-pkglist.c @@ -0,0 +1,3155 @@ + +/********************************************************************** + + 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 <math.h> + +#include <sys/wait.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> + +#include <dlist.h> +#include <pkglist.h> + +#define PROGRAM_NAME "make-pkglist" + +#include <defs.h> + + +char *program = PROGRAM_NAME; +char *srcdir = NULL, *pkglist_fname = NULL, + *tmpdir = NULL; + +char *srclist_fname = NULL; + +struct srcpkg_fname +{ + char *name; + int line; +}; + +struct dlist *srcpkg_fnames = NULL; + +int exit_status = EXIT_SUCCESS; /* errors counter */ +char *selfdir = NULL; + +int __done = 0, __child = 0; + +enum _output_format { + OFMT_LIST = 0, + OFMT_JSON, + + OFMT_UNKNOWN +} output_format = OFMT_LIST; + +enum _tree_format tree_format = TFMT_BIN; + +enum _input_type { + IFMT_PKG = 0, + IFMT_LOG, + + IFMT_UNKNOWN +} input_format = IFMT_UNKNOWN; + +enum _priority priority = REQUIRED; + +/*************************************************************** + Exclude declarations: + */ +static struct dlist *exclude = NULL; + +static void add_exclude( const char *name ); +static void free_exclude( void ); + +static void read_exclude_list( const char *optarg ); +/* + End of exclude declarstions. + ***************************************************************/ + +/*************************************************************** + Source file names functions: + */ +static struct srcpkg_fname *srcpkg_fname_alloc( const char *name, int line ) +{ + struct srcpkg_fname *fname = NULL; + + fname = (struct srcpkg_fname *)malloc( sizeof( struct srcpkg_fname ) ); + if( !fname ) { FATAL_ERROR( "Cannot allocate memory" ); } + + fname->name = xstrdup( name ); + fname->line = line; + + return fname; +} + +static void srcpkg_fname_free( struct srcpkg_fname *fname ) +{ + if( fname ) + { + if( fname->name ) { free( fname->name ); fname->name = NULL; } + free( fname ); + } +} + +static void __srcpkg_fname_free_func( void *data, void *user_data ) +{ + struct srcpkg_fname *fname = (struct srcpkg_fname *)data; + if( fname ) { srcpkg_fname_free( fname ); } +} + +static void free_srcpkg_fnames( void ) +{ + if( srcpkg_fnames ) { dlist_free( srcpkg_fnames, __srcpkg_fname_free_func ); srcpkg_fnames = NULL; } +} + +static void add_srcpkg_fname( struct srcpkg_fname *fname ) +{ + if( fname ) + srcpkg_fnames = dlist_append( srcpkg_fnames, (void *)fname ); +} +/* + End of source file names functions. + ***************************************************************/ + + +void free_resources() +{ + if( selfdir ) { free( selfdir ); selfdir = NULL; } + if( srcdir ) { free( srcdir ); srcdir = NULL; } + if( srclist_fname ) { free( srclist_fname ); srclist_fname = NULL; } + if( pkglist_fname ) { free( pkglist_fname ); pkglist_fname = NULL; } + + free_exclude(); + + free_tarballs(); + free_packages(); + free_srcpkg_fnames(); + free_srcpkgs(); +} + +void usage() +{ + free_resources(); + + fprintf( stdout, "\n" ); + fprintf( stdout, "Usage: %s [options] <pkglist>\n", program ); + fprintf( stdout, "\n" ); + fprintf( stdout, "Create Packages List in the installation order from set of PKGLOGs\n" ); + fprintf( stdout, "or set of PACKAGEs placed in the source directory. If the source\n" ); + fprintf( stdout, "directory is not defined then directory of <pkglist> will be used\n" ); + fprintf( stdout, "as source PACKAGE directory.\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, " -s,--source=<DIR|pkg|log> Setup Database packages directory or directory\n" ); + fprintf( stdout, " where set of PACKAGEs is placed.\n" ); + fprintf( stdout, " If the source argument is a PACKAGE or PKGLOG\n" ); + fprintf( stdout, " file, then the source directory will be represented\n" ); + fprintf( stdout, " as the base directory of the source file excluding\n" ); + fprintf( stdout, " the group directory if defined.\n" ); + fprintf( stdout, " -F,--files-from=<FILE> Get file names of PACKAGEs or PKGLOGs from FILE.\n" ); + fprintf( stdout, " Each line of the FILE must contain a path to the\n" ); + fprintf( stdout, " PACKAGE or PKGLOG file relative to the directory\n" ); + fprintf( stdout, " specified by option --source.\n" ); + fprintf( stdout, " -e,--exclude=<pname|plist> Ignore package with <pname> or the comma\n" ); + fprintf( stdout, " separated list of package names.\n" ); + fprintf( stdout, " -i,--iformat=<pkg|log> Input format: PACKAGEs or PKGLOGs.\n" ); + fprintf( stdout, " -o,--oformat=<list|json> Output format: LIST or JSON.\n" ); + + fprintf( stdout, " -t,--tformat=<dag|bin> Tree format: DAG or BIN (default BIN).\n" ); + + fprintf( stdout, " -m,--minimize Create .min.json files. Applicable\n" ); + fprintf( stdout, " for JSON output format.\n" ); + + fprintf( stdout, " -p,--prioriy=<PRIORITY> Default install priority: REQ|REC|OPT|SKP.\n" ); + fprintf( stdout, " -w,--hardware=<HARDWARE> Hardware Name used for JSON output format.\n" ); + fprintf( stdout, " -H,--htmlroot=<HTMLROOT> Optional Requires tree HTMLROOT name used\n" ); + fprintf( stdout, " for JSON output format.\n" ); + + fprintf( stdout, "\n" ); + fprintf( stdout, "Parameter:\n" ); + fprintf( stdout, " <pkglist> Output PKGLIST file name or a target\n" ); + fprintf( stdout, " directory to save output PKGLIST.\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "If HTMLROOT is not defined by option --htmlroot then HTMLROOT will be set\n" ); + fprintf( stdout, "as basename of target <pkglist> file in lower case without extension.\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; +} + + + +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(); +} + +void sigchld( int signum ) +{ + pid_t pid = 0; + int status; + + (void)signum; + + while( (pid = waitpid( -1, &status, WNOHANG )) > 0 ) + { + ; /* One of children with 'pid' is terminated */ + + if( WIFEXITED( status ) ) + { + if( (int) WEXITSTATUS (status) > 0 ) + { + ++exit_status; /* printf( "Child %d returned non zero status: %d\n", pid, (int)WEXITSTATUS (status) ); */ + } + else + { + ; /* printf( "Child %d terminated with status: %d\n", pid, (int)WEXITSTATUS (status) ); */ + } + } + else if( WIFSIGNALED( status ) ) + { + ++exit_status; /* printf( "Child %d terminated on signal: %d\n", pid, WTERMSIG( status ) ); */ + } + else + { + ++exit_status; /* printf( "Child %d terminated on unknown reason\n", pid ); */ + } + + } + + if( pid == -1 && errno == ECHILD ) + { + /* No child processes: */ + __done = 1; + } + return; +} + + +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 ); + + /* System V fork+wait does not work if SIGCHLD is ignored */ + memset( &sa, 0, sizeof( sa ) ); + sa.sa_handler = sigchld; /* CHLD */ + sa.sa_flags = SA_RESTART; + sigemptyset( &set ); + sigaddset( &set, SIGCHLD ); + sa.sa_mask = set; + sigaction( SIGCHLD, &sa, NULL ); + + memset( &sa, 0, sizeof( sa ) ); /* ignore SIGPIPE */ + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigaction( SIGPIPE, &sa, NULL ); +} + + +static enum _input_type check_input_file( char *uncompress, 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 */ + + if( uncompress ) + { + *uncompress = '\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 ) + { + close( fd ); return IFMT_UNKNOWN; + } + buf[7] = '\0'; + + /* TEXT */ + if( !strncmp( (const char *)&buf[0], "PACKAGE", 7 ) ) + { + close( fd ); return IFMT_LOG; + } + + /* GZ */ + if( buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x08 ) + { + if( uncompress ) { *uncompress = 'x'; } + close( fd ); return IFMT_PKG; + } + + /* BZ2 */ + if( buf[0] == 0x42 && buf[1] == 0x5A && buf[2] == 0x68 ) + { + if( uncompress ) { *uncompress = 'j'; } + close( fd ); return IFMT_PKG; + } + + /* XZ */ + if( buf[0] == 0xFD && buf[1] == 0x37 && buf[2] == 0x7A && + buf[3] == 0x58 && buf[4] == 0x5A && buf[5] == 0x00 ) + { + if( uncompress ) { *uncompress = 'J'; } + close( fd ); return IFMT_PKG; + } + + 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 IFMT_PKG; + } + } + + close( fd ); return IFMT_UNKNOWN; +} + + +void get_args( int argc, char *argv[] ) +{ + const char* short_options = "hvme:s:F:o:i:t:p:w:H:"; + + const struct option long_options[] = + { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "minimize", no_argument, NULL, 'm' }, + { "exclude", required_argument, NULL, 'e' }, + { "source", required_argument, NULL, 's' }, + { "files-from", required_argument, NULL, 'F' }, + { "oformat", required_argument, NULL, 'o' }, + { "iformat", required_argument, NULL, 'i' }, + { "tformat", required_argument, NULL, 't' }, + { "priority", required_argument, NULL, 'p' }, + { "hardware", required_argument, NULL, 'w' }, + { "htmlroot", required_argument, NULL, 'H' }, + { 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 'm': + { + minimize = 1; + break; + } + + case 'e': + { + if( optarg != NULL ) + { + read_exclude_list( (const char *)optarg ); + } + else + /* option is present but without value */ + usage(); + break; + } + + case 's': + { + if( optarg != NULL ) + { + srcdir = xstrdup( (const char *)optarg ); + remove_trailing_slash( srcdir ); + } + else + /* option is present but without value */ + usage(); + break; + } + case 'F': + { + if( optarg != NULL ) + { + srclist_fname = xstrdup( (const char *)optarg ); + remove_trailing_slash( srclist_fname ); + } + else + /* option is present but without value */ + usage(); + break; + } + case 'o': + { + char *fmt = (char *)alloca( strlen( optarg ) + 1 ); + + strcpy( (char *)fmt, (const char *)optarg ); + to_lowercase( fmt ); + + if( !strcmp( fmt, "list" ) ) { output_format = OFMT_LIST; } + else if( !strcmp( fmt, "json" ) ) { output_format = OFMT_JSON; } + else + { + ERROR( "Invalid output format: %s", fmt ); + usage(); + } + break; + } + case 'i': + { + char *fmt = (char *)alloca( strlen( optarg ) + 1 ); + + strcpy( (char *)fmt, (const char *)optarg ); + to_lowercase( fmt ); + + if( !strcmp( fmt, "pkg" ) ) { input_format = IFMT_PKG; } + else if( !strcmp( fmt, "log" ) ) { input_format = IFMT_LOG; } + else + { + ERROR( "Invalid input format: %s", fmt ); + usage(); + } + break; + } + case 't': + { + char *fmt = (char *)alloca( strlen( optarg ) + 1 ); + + strcpy( (char *)fmt, (const char *)optarg ); + to_lowercase( fmt ); + + if( !strcmp( fmt, "bin" ) ) { tree_format = TFMT_BIN; } + else if( !strcmp( fmt, "dag" ) ) { tree_format = TFMT_DAG; } + else + { + ERROR( "Invalid tree format: %s", fmt ); + usage(); + } + break; + } + case 'p': + { + char *p = (char *)alloca( strlen( optarg ) + 1 ); + + strcpy( (char *)p, (const char *)optarg ); + to_lowercase( p ); + + if( !strcmp( p, "required" ) || !strcmp( p, "req" ) ) { priority = REQUIRED; } + else if( !strcmp( p, "recommended" ) || !strcmp( p, "rec" ) ) { priority = RECOMMENDED; } + else if( !strcmp( p, "optional" ) || !strcmp( p, "opt" ) ) { priority = OPTIONAL; } + else if( !strcmp( p, "skip" ) || !strcmp( p, "skp" ) ) { priority = SKIP; } + else + { + ERROR( "Invalid default install priority: %s", p ); + usage(); + } + break; + } + case 'w': + { + char *hw = (char *)alloca( strlen( optarg ) + 1 ); + + strcpy( (char *)hw, (const char *)optarg ); + to_lowercase( hw ); + + hardware = xstrdup( (const char *)hw ); + break; + } + case 'H': + { + char *root = (char *)alloca( strlen( optarg ) + 1 ); + + strcpy( (char *)root, (const char *)optarg ); + to_lowercase( root ); + + htmlroot = xstrdup( (const char *)root ); + break; + } + + case '?': default: + { + usage(); + break; + } + } + } + + + /* last command line argument is the output PKGLIST file */ + if( optind < argc ) + { + struct stat st; + char *buf = NULL; + size_t hrl = 0; + + bzero( (void *)&st, sizeof( struct stat ) ); + + if( htmlroot ) { hrl = strlen( htmlroot ); } + + buf = (char *)malloc( strlen( (const char *)argv[optind] ) + hrl + 10 ); + if( !buf ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + (void)strcpy( buf, (const char *)argv[optind++] ); + remove_trailing_slash( (char *)&buf[0] ); + + stat( (const char *)&buf[0], &st ); /* Do not check return status */ + + if( S_ISDIR(st.st_mode) ) + { + if( ! srcdir ) + { + srcdir = xstrdup( (const char *)&buf[0] ); + } + /* Add .pkglist or .json to the output dir name: */ + if( htmlroot ) + { + (void)strcat( buf, "/" ); + (void)strcat( buf, htmlroot ); + + if( output_format == OFMT_LIST ) + (void)strcat( buf, ".pkglist" ); + else + (void)strcat( buf, ".json" ); + } + else + { + if( output_format == OFMT_LIST ) + (void)strcat( buf, "/.pkglist" ); + else + (void)strcat( buf, "/.json" ); + } + } + + if( !hardware ) + hardware = xstrdup( "unknown" ); + + /* Check output directory; set srcdir and htmlroot if needed */ + { + char *d, *f, *fname; + size_t len; + + if( !rindex( (const char *)&buf[0], '/' ) ) + { + d = "."; + f = (char *)&buf[0]; + len = strlen( f ) + 3; + } + else + { + f = basename( (char *)&buf[0] ); + d = dirname( (char *)&buf[0] ); /* dirname() cuts the filename from buf[] */ + len = strlen( d ) + strlen( f ) + 2; + } + + fname = (char *)alloca( len ); + (void)sprintf( fname, "%s/%s", d, f ); + + if( stat( (const char *)d, &st ) == -1 ) + { + FATAL_ERROR( "Cannot access output '%s' directory: %s", d, strerror( errno ) ); + } + + pkglist_fname = xstrdup( (const char *)fname ); + if( pkglist_fname == NULL ) { usage(); } + + if( !srcdir ) { srcdir = xstrdup( (const char *)d ); } + + if( !htmlroot ) + { + char *p = NULL; + if( (p = rindex( (const char *)f, '.' )) && p != f ) + { + *p = '\0'; + to_lowercase( f ); + htmlroot = xstrdup( (const char *)f ); + } + else if( *f != '.' ) + { + to_lowercase( f ); + htmlroot = xstrdup( (const char *)f ); + } + else + { + htmlroot = xstrdup( (const char *)hardware ); + } + } + } + + free( buf ); + } + else + { + usage(); + } +} + + +/*************************************************************** + Exclude functions: + */ +static void add_exclude( const char *name ) +{ + exclude = dlist_append( exclude, (void *)xstrdup( name ) ); +} + +static void __free_exclude( void *data, void *user_data ) +{ + if( data ) { free( data ); } +} + +static void free_exclude( void ) +{ + if( exclude ) { dlist_free( exclude, __free_exclude ); exclude = NULL; } +} + +static int __compare_exclude( const void *a, const void *b ) +{ + return strncmp( (const char *)a, (const char *)b, (size_t)strlen((const char *)b) ); +} + +static const char *find_exclude( const char *name ) +{ + struct dlist *node = NULL; + + if( !exclude || !name ) return NULL; + + node = dlist_find_data( exclude, __compare_exclude, (const void *)name ); + if( node ) + { + return (const char *)node->data; + } + + return NULL; +} + +static void read_exclude_list( const char *optarg ) +{ + char *name = NULL, *p = NULL; + + name = p = (char *)optarg; + + if( !p || *p == '\0' ) return; + + while( *p == ',' ) { *p = '\0'; ++p; } + name = p; + + while( p && *p != '\0' ) + { + ++p; + + if( *p == ',' ) + { + while( *p == ',' ) { *p = '\0'; ++p; } + if( name && *name != '\0' ) { add_exclude( (const char *)name ); } + name = p; + } + + if( *p == '\0' ) + { + if( name && *name != '\0' ) { add_exclude( (const char *)name ); } + } + } +} +/* + End of exclude functions. + ***************************************************************/ + + +/*************************************************************** + Extract functions: + */ +static void _extract_pkglog( const char *group, const char *fname ) +{ + enum _input_type type = IFMT_UNKNOWN; + char uncompress = '\0'; + + type = check_input_file( &uncompress, fname ); + + if( type == IFMT_PKG ) + { + int len = 0; + char *tmp= NULL, *cmd = NULL, *tgz = NULL; + + tmp = (char *)malloc( (size_t)PATH_MAX ); + if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)tmp, PATH_MAX ); + + if( group ) { (void)sprintf( &tmp[0], "%s/%s", tmpdir, group ); } + else { (void)sprintf( &tmp[0], "%s", tmpdir ); } + + if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 ) + { + ERROR( "Cannot save PKGLOG from '%s' file", basename( (char *)fname ) ); + free( tmp ); + return; + } + + cmd = (char *)malloc( (size_t)PATH_MAX ); + if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)cmd, PATH_MAX ); + + len = snprintf( &cmd[0], PATH_MAX, "%s/pkglog -d %s %s > /dev/null 2>&1", selfdir, tmp, fname ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( "Cannot get PKGLOG from %s file", basename( (char *)fname ) ); + } + (void)sys_exec_command( cmd ); + ++__child; + + tgz = (char *)malloc( (size_t)PATH_MAX ); + if( !tgz ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)tgz, PATH_MAX ); + (void)sprintf( &tgz[0], "%s/%s", group, basename( (char *)fname ) ); + add_tarball( (char *)&tgz[0] ); + + free( tmp ); + free( cmd ); + free( tgz ); + } +} + +static void _search_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) ) + { + _extract_pkglog( grp, (const char *)path ); + } + if( S_ISDIR(entry_sb.st_mode) && grp == NULL ) + { + _search_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 ); +} + +/************************************************************** + extract_pkglogs() - returns number of extracted PKGLOGS + or 0 if no packages found in the srcdir. + The exit_status has been set. + */ +int extract_pkglogs( void ) +{ + int ret = 0; + + __done = 0; __child = 0; + + _search_packages( (const char *)srcdir, NULL ); + + if( __child > 0 ) + { + while( !__done ) usleep( 1 ); + ret = __child; + } + + __done = 0; __child = 0; + + return ret; +} +/* + End of Extract functions. + ***************************************************************/ + + +/*************************************************************** + Copy functions: + */ +static void _copy_pkglog( const char *group, const char *fname ) +{ + enum _input_type type = IFMT_UNKNOWN; + char uncompress = '\0'; + + type = check_input_file( &uncompress, fname ); + + if( type == IFMT_LOG ) + { + int len = 0; + char *tmp= NULL, *cmd = NULL; + + tmp = (char *)malloc( (size_t)PATH_MAX ); + if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)tmp, PATH_MAX ); + + if( group ) { (void)sprintf( &tmp[0], "%s/%s", tmpdir, group ); } + else { (void)sprintf( &tmp[0], "%s", tmpdir ); } + + if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 ) + { + ERROR( "Cannot copy '%s' PKGLOG file", basename( (char *)fname ) ); + free( tmp ); + return; + } + + cmd = (char *)malloc( (size_t)PATH_MAX ); + if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)cmd, PATH_MAX ); + + len = snprintf( &cmd[0], PATH_MAX, "cp %s %s/ > /dev/null 2>&1", fname, tmp ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( "Cannot copy %s PKGLOG file", basename( (char *)fname ) ); + } + (void)sys_exec_command( cmd ); + ++__child; + + free( tmp ); + free( cmd ); + } +} + +static void _search_pkglogs( 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) ) + { + _copy_pkglog( grp, (const char *)path ); + } + if( S_ISDIR(entry_sb.st_mode) && grp == NULL ) + { + _search_pkglogs( (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 ); +} + +/*********************************************************** + copy_pkglogs() - returns number of copied PKGLOGS + or 0 if no packages found in the srcdir. + The exit_status has been set. + */ +int copy_pkglogs( void ) +{ + int ret = 0; + + __done = 0; __child = 0; + + _search_pkglogs( (const char *)srcdir, NULL ); + + if( __child > 0 ) + { + while( !__done ) usleep( 1 ); + ret = __child; + } + + __done = 0; __child = 0; + + return ret; +} +/* + Enf of Copy functions. + ***************************************************************/ + + +/*********************************************************** + Remove leading spaces and take non-space characters only: + (Especialy for pkginfo lines) + */ +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'; } +} + +static size_t read_usize( char *s ) +{ + size_t size = 0; + size_t mult = 1; + double sz = 0.0; + + char suffix; + char *q, *p = (char *)0; + + if( !s || *s == '\0' ) return size; + + p = s; + + while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p; + while( *q != ' ' && *q != '\t' && *q != '\0' ) { ++q; } *q = '\0'; + + if( *p == '\0' ) return size; + + --q; + suffix = *q; + switch( suffix ) + { + /* by default size calculates in KiB - 1024 Bytes (du -s -h .) */ + case 'G': + case 'g': + mult = 1024 * 1024; + *q = '\0'; + break; + case 'M': + case 'm': + mult = 1024; + *q = '\0'; + break; + case 'K': + case 'k': + *q = '\0'; + break; + default: + break; + } + + if( sscanf( p, "%lg", &sz ) != 1 ) return size; + + return (size_t)round( sz * (double)mult ); +} + +static int read_total_files( char *s ) +{ + int n = 0; + char *q, *p = (char *)0; + + if( !s || *s == '\0' ) return n; + + p = s; + + while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p; + while( *q != ' ' && *q != '\t' && *q != '\0' ) { ++q; } *q = '\0'; + + if( *p == '\0' ) return n; + + if( sscanf( p, "%u", &n ) != 1 ) return 0; + + return n; +} + + +static struct pkg *input_package( const char *pkginfo_fname ) +{ + char *ln = NULL; + char *line = NULL; + + FILE *pkginfo = NULL; + + struct pkg *pkg = NULL; + char *pkgname = NULL, *pkgver = NULL, *group = NULL; + + if( pkginfo_fname != NULL ) + { + pkginfo = fopen( (const char *)pkginfo_fname, "r" ); + if( !pkginfo ) + { + FATAL_ERROR( "Cannot open %s file", pkginfo_fname ); + } + } + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + while( (ln = fgets( line, PATH_MAX, pkginfo )) ) + { + 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" )) && match == ln ) { + char *p = index( match, '=' ) + 1; + if( p != NULL ) pkgname = skip_spaces( p ); + } + if( (match = strstr( ln, "pkgver" )) && match == ln ) { + char *p = index( match, '=' ) + 1; + if( p != NULL ) pkgver = skip_spaces( p ); + } + if( (match = strstr( ln, "group" )) && match == ln ) { + char *p = index( match, '=' ) + 1; + if( p != NULL ) group = skip_spaces( p ); + } + } + + free( line ); + + if( pkgname && pkgver ) + { + pkg = pkg_alloc(); + if( pkg ) + { + if( group ) + { + pkg->group = group; + } + pkg->name = pkgname; + pkg->version = pkgver; + } + + } + else + { + if( group ) free( group ); + if( pkgname ) free( pkgname ); + if( pkgver ) free( pkgver ); + + FATAL_ERROR( "Invalid input .PKGINFO file" ); + } + + fclose( pkginfo ); + + return( pkg ); +} + + + +static void get_short_description( char *buf, const char *line ) +{ + char *s, *p, *q; + + if( buf ) { buf[0] = '\0'; s = buf; } + if( !line || line[0] == '\0' ) return; + + p = index( line, '(' ); + q = index( line, ')' ); + if( p && q && q > p ) + { + ++p; + while( *p && p < q ) + { + *s = *p; + ++p; ++s; + } + *s = '\0'; + } + else + { + /* + If short description declaration is incorrect at first line + of description; then we take whole first line of description: + */ + p = index( line, ':' ); ++p; + while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } + strcpy( buf, p ); + } +} + + +static 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; + *start = 0; *stop = 0; + + 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 ); +} + +static int get_requires_section( int *start, int *stop, FILE *log ) +{ + int ret = -1, found = 0; + + if( !start || !stop ) 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; + *start = 0; *stop = 0; + + 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. */ + + fseek( log, 0, SEEK_SET ); + } + + return( ret ); +} + +static int get_description_section( int *start, int *stop, FILE *log ) +{ + int ret = -1, found = 0; + + if( !start || !stop ) 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; + *start = 0; *stop = 0; + + 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. */ + + fseek( log, 0, SEEK_SET ); + } + + return( ret ); +} + +static int get_restore_links_section( int *start, int *stop, FILE *log ) +{ + int ret = -1, found = 0; + + if( !start || !stop ) 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; + *start = 0; *stop = 0; + + 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. */ + + fseek( log, 0, SEEK_SET ); + } + + return( ret ); +} + + +static int get_install_script_section( int *start, int *stop, FILE *log ) +{ + int ret = -1, found = 0; + + if( !start || !stop ) 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; + *start = 0; *stop = 0; + + 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. */ + + fseek( log, 0, SEEK_SET ); + } + + return( ret ); +} + + +static int get_file_list_section( int *start, int *stop, FILE *log ) +{ + int ret = -1, found = 0; + + if( !start || !stop ) 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; + *start = 0; *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. */ + + fseek( log, 0, SEEK_SET ); + } + + return( ret ); +} + + +int read_pkginfo( FILE *log, struct package *package ) +{ + int ret = -1; + + char *ln = NULL; + char *line = NULL; + + char *pkgname_pattern = "PACKAGE NAME:", + *pkgver_pattern = "PACKAGE VERSION:", + *arch_pattern = "ARCH:", + *distroname_pattern = "DISTRO:", + *distrover_pattern = "DISTRO VERSION:", + *group_pattern = "GROUP:", + *url_pattern = "URL:", + *license_pattern = "LICENSE:", + *uncompressed_size_pattern = "UNCOMPRESSED SIZE:", + *total_files_pattern = "TOTAL FILES:"; + + + if( !log || !package ) return ret; + + 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; + + 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 */ + { + package->pkginfo->name = skip_spaces( ln + strlen( pkgname_pattern ) ); + } + if( (match = strstr( ln, pkgver_pattern )) && match == ln ) + { + package->pkginfo->version = skip_spaces( ln + strlen( pkgver_pattern ) ); + } + if( (match = strstr( ln, arch_pattern )) && match == ln ) + { + package->pkginfo->arch = skip_spaces( ln + strlen( arch_pattern ) ); + } + if( (match = strstr( ln, distroname_pattern )) && match == ln ) + { + package->pkginfo->distro_name = skip_spaces( ln + strlen( distroname_pattern ) ); + } + if( (match = strstr( ln, distrover_pattern )) && match == ln ) + { + package->pkginfo->distro_version = skip_spaces( ln + strlen( distrover_pattern ) ); + } + if( (match = strstr( ln, group_pattern )) && match == ln ) + { + package->pkginfo->group = skip_spaces( ln + strlen( group_pattern ) ); + } + if( (match = strstr( ln, url_pattern )) && match == ln ) + { + package->pkginfo->url = skip_spaces( ln + strlen( url_pattern ) ); + } + if( (match = strstr( ln, license_pattern )) && match == ln ) + { + package->pkginfo->license = skip_spaces( ln + strlen( license_pattern ) ); + } + if( (match = strstr( ln, uncompressed_size_pattern )) && match == ln ) + { + package->pkginfo->uncompressed_size = read_usize( ln + strlen( uncompressed_size_pattern ) ); + } + if( (match = strstr( ln, total_files_pattern )) && match == ln ) + { + package->pkginfo->total_files = read_total_files( ln + strlen( total_files_pattern ) ); + } + + if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln ) + { + char *buf = NULL; + + buf = (char *)malloc( (size_t)PATH_MAX ); + if( !buf ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + /* Get short_description from PACKAGE DESCRIPTION */ + ln = fgets( line, PATH_MAX, log ); + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + + bzero( (void *)buf, PATH_MAX ); + get_short_description( buf, (const char *)line ); + if( buf[0] != '\0' ) + { + package->pkginfo->short_description = xstrdup( (const char *)buf ); + } + free( buf ); + } + + } /* End of while() */ + + free( line ); + + if( package->pkginfo->name == NULL ) ++ret; + if( package->pkginfo->version == NULL ) ++ret; + if( package->pkginfo->arch == NULL ) ++ret; + if( package->pkginfo->distro_name == NULL ) ++ret; + if( package->pkginfo->distro_version == NULL ) ++ret; + /* group can be equal to NULL */ + + fseek( log, 0, SEEK_SET ); + + return( ret ); +} + + +static unsigned int read_references( FILE *log, int start, unsigned int *cnt, struct package *package ) +{ + char *ln = NULL; + char *line = NULL; + char *p = NULL, *group = NULL, *name = NULL, *version = NULL; + int n = 1; + + unsigned int counter, pkgs = 0; + + struct pkg *pkg = NULL; + + if( !log || !cnt || *cnt == 0 || !package ) return pkgs; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + counter = *cnt; + + while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n; + + n = 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( (p = index( (const char *)ln, '=' )) ) + { + *p = '\0'; version = ++p; + if( (p = index( (const char *)ln, '/' )) ) + { + *p = '\0'; name = ++p; group = (char *)&ln[0]; + } + else + { + name = (char *)&ln[0]; group = NULL; + } + + pkg = pkg_alloc(); + + if( group ) pkg->group = xstrdup( (const char *)group ); + pkg->name = xstrdup( (const char *)name ); + pkg->version = xstrdup( (const char *)version ); + + add_reference( package, pkg ); + ++pkgs; + } + ++n; + } + else + break; + } + + free( line ); + + fseek( log, 0, SEEK_SET ); + + *cnt = pkgs; + + return pkgs; +} + + +static unsigned int read_requires( FILE *log, int start, int stop, struct package *package ) +{ + char *ln = NULL; + char *line = NULL; + char *p = NULL, *group = NULL, *name = NULL, *version = NULL; + int n = 1; + + unsigned int pkgs = 0; + + struct pkg *pkg = NULL; + + if( !log || !package ) return pkgs; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n; + + if( start && start < stop ) + { + ++n; /* skip section header */ + + 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, "PACKAGE DESCRIPTION:" ) ) break; /* if (stop - start - 1) greater than real number of requiress */ + + if( (n > start) && (n < stop) ) + { + if( (p = index( (const char *)ln, '=' )) ) + { + *p = '\0'; version = ++p; + if( (p = index( (const char *)ln, '/' )) ) + { + *p = '\0'; name = ++p; group = (char *)&ln[0]; + } + else + { + name = (char *)&ln[0]; group = NULL; + } + + pkg = pkg_alloc(); + + if( group ) pkg->group = xstrdup( (const char *)group ); + pkg->name = xstrdup( (const char *)name ); + pkg->version = xstrdup( (const char *)version ); + + add_required( package, pkg ); + ++pkgs; + } + + } + ++n; + } + + } /* End if( start && start < stop ) */ + + free( line ); + + fseek( log, 0, SEEK_SET ); + + return pkgs; +} + + +static unsigned int read_description( FILE *log, int start, int stop, struct package *package ) +{ + char *ln = NULL; + char *line = NULL; + char *pattern = NULL; + int n = 1; + + char *tmp_fname = NULL; + FILE *tmp = NULL; + + unsigned int lines = 0; + + if( !log || !package ) return lines; + + tmp_fname = (char *)malloc( (size_t)PATH_MAX ); + if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); } + + bzero( (void *)tmp_fname, PATH_MAX ); + (void)sprintf( (char *)&tmp_fname[0], "%s/.DESCRIPTION", tmpdir ); + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); } + + pattern = (char *)malloc( (size_t)strlen( package->pkginfo->name ) + 2 ); + if( !pattern ) { FATAL_ERROR( "Cannot allocate memory" ); } + + (void)sprintf( pattern, "%s:", package->pkginfo->name ); + + + while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n; + + if( start && start < stop ) + { + ++n; /* skip section header */ + + tmp = fopen( (const char *)&tmp_fname[0], "w" ); + if( !tmp ) + { + FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[0] ) ); + } + + 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( strstr( ln, "RESTORE LINKS:" ) ) break; /* if (stop - start - 1) greater than real number of lines */ + + if( (n > start) && (n < stop) ) + { + /* + skip non-significant spaces at beginning of line + and print lines started with 'pkgname:' + */ + if( (match = strstr( ln, pattern )) && lines < DESCRIPTION_NUMBER_OF_LINES ) + { + int mlen = strlen( match ), plen = strlen( pattern ); + int length = ( mlen > plen ) ? (mlen - plen - 1) : 0 ; + + if( length > DESCRIPTION_LENGTH_OF_LINE ) + { + /* WARNING( "Package DESCRIPTION contains lines with length greater than %d characters", DESCRIPTION_LENGTH_OF_LINE ); */ + match[plen + 1 + DESCRIPTION_LENGTH_OF_LINE] = '\0'; /* truncating description line */ + skip_eol_spaces( match ); /* remove spaces at end-of-line */ + } + fprintf( tmp, "%s\n", match ); + ++lines; + } + + } + ++n; + } + + if( lines < (unsigned int)DESCRIPTION_NUMBER_OF_LINES ) + { + /* WARNING( "Package DESCRIPTION contains less than %d lines", DESCRIPTION_NUMBER_OF_LINES ); */ + while( lines < (unsigned int)DESCRIPTION_NUMBER_OF_LINES ) + { + fprintf( tmp, "%s\n", pattern ); + ++lines; + } + } + + fflush( tmp ); + fclose( tmp ); + + } /* End if( start && start < stop ) */ + + free( pattern ); + free( line ); + + fseek( log, 0, SEEK_SET ); + + /* read temporary saved description */ + { + struct stat sb; + size_t size = 0; + int fd; + + char *desc = NULL; + + if( stat( tmp_fname, &sb ) == -1 ) + { + FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) ); + } + size = (size_t)sb.st_size; + + if( size ) + { + ssize_t rc = 0; + + desc = (char *)malloc( size + 1 ); + if( !desc ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)desc, size + 1 ); + + if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 ) + { + FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) ); + } + + rc = read( fd, (void *)desc, size ); + if( rc != (ssize_t)size ) { ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) ); } + + package->description = desc; + + close( fd ); + } + + } + + (void)unlink( tmp_fname ); + free( tmp_fname ); + + return lines; +} + + +static unsigned int read_restore_links( FILE *log, int start, int stop, struct package *package ) +{ + char *ln = NULL; + char *line = NULL; + int n = 1; + + char *tmp_fname = NULL; + FILE *tmp = NULL; + + unsigned int lines = 0; + + if( !log || !package ) return lines; + + tmp_fname = (char *)malloc( (size_t)PATH_MAX ); + if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); } + + bzero( (void *)tmp_fname, PATH_MAX ); + (void)sprintf( (char *)&tmp_fname[0], "%s/.RESTORELINKS", tmpdir ); + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); } + + while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n; + + if( start && start < stop ) + { + ++n; /* skip section header */ + + tmp = fopen( (const char *)&tmp_fname[0], "w" ); + if( !tmp ) + { + FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[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, "INSTALL SCRIPT:" ) ) break; /* if (stop - start - 1) greater than real number of lines */ + + if( (n > start) && (n < stop) ) + { + fprintf( tmp, "%s\n", ln ); + ++lines; + } + ++n; + } + + fflush( tmp ); + fclose( tmp ); + + } /* End if( start && start < stop ) */ + + free( line ); + + fseek( log, 0, SEEK_SET ); + + /* read temporary saved description */ + { + struct stat sb; + size_t size = 0; + int fd; + + char *links = NULL; + + if( stat( tmp_fname, &sb ) == -1 ) + { + FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) ); + } + size = (size_t)sb.st_size; + + if( size ) + { + ssize_t rc = 0; + + links = (char *)malloc( size + 1 ); + if( !links ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)links, size + 1 ); + + if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 ) + { + FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) ); + } + + rc = read( fd, (void *)links, size ); + if( rc != (ssize_t)size ) { ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) ); } + + package->restore_links = links; + + close( fd ); + } + + } + + (void)unlink( tmp_fname ); + free( tmp_fname ); + + return lines; +} + + +static unsigned int read_install_script( FILE *log, int start, int stop, struct package *package ) +{ + char *ln = NULL; + char *line = NULL; + int n = 1; + + char *tmp_fname = NULL; + FILE *tmp = NULL; + + unsigned int lines = 0; + + if( !log || !package ) return lines; + + tmp_fname = (char *)malloc( (size_t)PATH_MAX ); + if( !tmp_fname ) { FATAL_ERROR( "Cannot allocate memory" ); } + + bzero( (void *)tmp_fname, PATH_MAX ); + (void)sprintf( (char *)&tmp_fname[0], "%s/.INSTALL", tmpdir ); + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); } + + while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n; + + if( start && start < stop ) + { + ++n; /* skip section header */ + + tmp = fopen( (const char *)&tmp_fname[0], "w" ); + if( !tmp ) + { + FATAL_ERROR( "Cannot create temporary %s file", basename( (char *)&tmp_fname[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, "FILE LIST:" ) ) break; /* if (stop - start - 1) greater than real number of lines */ + + if( (n > start) && (n < stop) ) + { + fprintf( tmp, "%s\n", ln ); + ++lines; + } + ++n; + } + + fflush( tmp ); + fclose( tmp ); + + } /* End if( start && start < stop ) */ + + free( line ); + + fseek( log, 0, SEEK_SET ); + + /* read temporary saved description */ + { + struct stat sb; + size_t size = 0; + int fd; + + char *install = NULL; + + if( stat( tmp_fname, &sb ) == -1 ) + { + FATAL_ERROR( "Cannot stat temporary %s file", basename( (char *)&tmp_fname[0] ) ); + } + size = (size_t)sb.st_size; + + if( size ) + { + ssize_t rc = 0; + + install = (char *)malloc( size + 1 ); + if( !install ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)install, size + 1 ); + + if( (fd = open( (const char *)&tmp_fname[0], O_RDONLY )) == -1 ) + { + FATAL_ERROR( "Canot access temporary %s file: %s", basename( (char *)&tmp_fname[0] ), strerror( errno ) ); + } + + rc = read( fd, (void *)install, size ); + if( rc != (ssize_t)size ) { ERROR( "The %s file is not fully read", basename( (char *)&tmp_fname[0] ) ); } + + package->install_script = install; + + close( fd ); + } + + } + + (void)unlink( tmp_fname ); + free( tmp_fname ); + + return lines; +} + + +static unsigned int read_file_list( FILE *log, int start, struct package *package ) +{ + char *ln = NULL; + char *line = NULL; + int n = 1; + + unsigned int files = 0; + + if( !log || !package ) return files; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + while( (ln = fgets( line, PATH_MAX, log )) && (n < start) ) ++n; + + if( start ) + { + 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 */ + + add_file( package, (const char *)ln ); + ++files; + } + + } /* End if( start && start < stop ) */ + + free( line ); + + fseek( log, 0, SEEK_SET ); + + return files; +} + + +static void _read_pkglog( const char *group, const char *fname ) +{ + FILE *log = NULL; + char *bname = NULL; + + if( fname != NULL ) + { + log = fopen( (const char *)fname, "r" ); + if( !log ) + { + FATAL_ERROR( "Cannot open %s file", fname ); + } + bname = (char *)fname + strlen( tmpdir ) + 1; + } + + if( log != NULL ) + { + struct package *package = NULL; + int rc, start, stop; + unsigned int counter; + + package = package_alloc(); + + if( read_pkginfo( log, package ) != 0 ) + { + ERROR( "%s: Invalid PKGLOG file", bname ); + package_free( package ); + fclose( log ); + return; + } + + if( hardware ) package->hardware = xstrdup( (const char *)hardware ); + if( tarballs ) /* find tarball and allocate package->tarball */ + { + struct pkginfo *info = package->pkginfo; + const char *tgz = NULL; + char *buf = NULL; + struct stat sb; + + buf = (char *)malloc( (size_t)PATH_MAX ); + if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); } + + if( info->group ) + { + (void)sprintf( buf, "%s/%s-%s-%s-%s-%s", + info->group, info->name, info->version, info->arch, + info->distro_name, info->distro_version ); + } + else + { + (void)sprintf( buf, "%s-%s-%s-%s-%s", + info->name, info->version, info->arch, + info->distro_name, info->distro_version ); + } + tgz = find_tarball( (const char *)&buf[0] ); + if( tgz ) + { + package->tarball = xstrdup( (const char *)tgz ); + + bzero( (void *)&buf[0], PATH_MAX ); + (void)sprintf( buf, "%s/%s", srcdir, tgz ); + if( stat( buf, &sb ) != -1 ) + { + info->compressed_size = (size_t)sb.st_size; + } + } + free( buf ); + } + package->procedure = INSTALL; + package->priority = priority; + + if( package->pkginfo->group && group && strcmp( package->pkginfo->group, group ) != 0 ) + { + char *tgz; + + if( package->tarball ) { tgz = package->tarball; } + else { tgz = basename( (char *)fname ); } + + WARNING( "%s: Should be moved into '%s' subdir", tgz, package->pkginfo->group ); + } + + /****************** + read references: + */ + rc = get_references_section( &start, &stop, &counter, log ); + if( rc != 0 ) + { + ERROR( "%s: PKGLOG doesn't contains REFERENCE COUNTER section", bname ); + package_free( package ); + fclose( log ); + return; + } + if( counter > 0 ) + { + unsigned int pkgs = counter; + + if( read_references( log, start, &counter, package ) != pkgs ) + { + ERROR( "%s: Invalid REFERENCE COUNTER section", bname ); + package_free( package ); + fclose( log ); + return; + } + } + + /****************** + read requires: + */ + rc = get_requires_section( &start, &stop, log ); + if( rc != 0 ) + { + ERROR( "%s: PKGLOG doesn't contains REQUIRES section", bname ); + package_free( package ); + fclose( log ); + return; + } + if( (stop - start) > 1 ) + { + unsigned int pkgs = (unsigned int)(stop - start - 1); /* -1 skips section header */ + + if( read_requires( log, start, stop, package ) != pkgs ) + { + ERROR( "%s: Invalid REQUIRES section", bname ); + package_free( package ); + fclose( log ); + return; + } + } + + /******************* + read description: + */ + rc = get_description_section( &start, &stop, log ); + if( rc != 0 ) + { + ERROR( "%s: PKGLOG doesn't contains PACKAGE DESCRIPTION section", bname ); + package_free( package ); + fclose( log ); + return; + } + if( (stop - start) > 1 ) + { + if( read_description( log, start, stop, package ) != (unsigned int)DESCRIPTION_NUMBER_OF_LINES ) + { + ERROR( "%s: Invalid DESCRIPTION section", bname ); + package_free( package ); + fclose( log ); + return; + } + } + + /********************* + read restore links: + */ + rc = get_restore_links_section( &start, &stop, log ); + if( rc != 0 ) + { + ERROR( "%s: PKGLOG doesn't contains RESTORE LINKS section", bname ); + package_free( package ); + fclose( log ); + return; + } + if( (stop - start) > 1 ) + { + (void)read_restore_links( log, start, stop, package ); + } + + /********************* + read install script: + */ + rc = get_install_script_section( &start, &stop, log ); + if( rc != 0 ) + { + ERROR( "%s: PKGLOG doesn't contains INSTALL SCRIPT section", bname ); + package_free( package ); + fclose( log ); + return; + } + if( (stop - start) > 1 ) + { + (void)read_install_script( log, start, stop, package ); + } + + /***************** + read file_list: + */ + rc = get_file_list_section( &start, &stop, log ); + if( rc != 0 ) + { + ERROR( "%s: PKGLOG doesn't contains FILE LIST section", bname ); + package_free( package ); + fclose( log ); + return; + } + if( start ) + { + unsigned int files = read_file_list( log, start, package ); + if( files == (unsigned int)0 ) + { + /* + Packages that do not contain regular files are ignored. + For example, service package base/init-devices-1.2.3-s9xx-glibc-radix-1.1.txz + */ + if( ! DO_NOT_PRINTOUT_INFO ) + { + INFO( "%s: PKGLOG contains empty FILE LIST section", bname ); + } + package_free( package ); + fclose( log ); + return; + } + package->pkginfo->total_files = (int)files; + } + + /* Skip excluded package: */ + { + const char *name = find_exclude( (const char *)package->pkginfo->name ); + + if( name && !strcmp( name, package->pkginfo->name ) ) + { + package_free( package ); + fclose( log ); + return; + } + } + + add_package( package ); + + ++__child; + fclose( log ); + } +} + +static void _read_pkglogs( 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( check_input_file( NULL, (const char *)path ) == IFMT_LOG ) + { + _read_pkglog( grp, (const char *)path ); + } + } + if( S_ISDIR(entry_sb.st_mode) && grp == NULL ) + { + _read_pkglogs( (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 ); +} + +int read_pkglogs( void ) +{ + int ret = 0; + + __child = 0; + + _read_pkglogs( (const char *)tmpdir, NULL ); + + ret = __child; + + __child = 0; + + return ret; +} + + + +/***************************** + Count slashes in file name: + */ +static int count_slashes( char *s ) +{ + int cnt = 0; + char *p = (char *)0; + + if( !s || *s == '\0' ) return cnt; + + p = s; + while( *p ) + { + if( *p == '/' ) { + ++cnt; + } + ++p; + } + + return cnt; +} + +static void read_srcpkg_fnames( const char *flist ) +{ + struct stat st; + FILE *fp = NULL; + + if( !flist ) return; + + bzero( (void *)&st, sizeof( struct stat ) ); + + if( stat( flist, &st ) == -1 ) + { + FATAL_ERROR( "Cannot access input '%s' file or directory: %s", flist, strerror( errno ) ); + } + + if( S_ISREG(st.st_mode) ) + { + char *ln = NULL; + char *line = NULL; + int lnum = 0; + + fp = fopen( flist, "r" ); + if( !fp ) + { + FATAL_ERROR( "Cannot open %s file", flist ); + } + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + while( (ln = fgets( line, PATH_MAX, fp )) ) + { + struct srcpkg_fname *fname = NULL; + + ++lnum; + if( strlen( ln ) == 0 ) continue; + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + skip_eol_spaces( ln ); /* remove spaces at end-of-line */ + /* remove leading spaces: */ + while( (*ln == ' ' || *ln == '\t') && *ln != '\0' ) { ++ln; } + /* skip comments and empty lines: */ + if( *ln == '\0' || *ln == '#' ) continue; + + if( count_slashes( ln ) > 1 ) + { + FATAL_ERROR( "%s:%d: file name contains more than one slash symbols", flist, lnum ); + } + + if( ! isalpha( *ln ) ) + { + FATAL_ERROR( "%s:%d: file path must be relative and start with a letter (as a group name)", flist, lnum ); + } + + fname = srcpkg_fname_alloc( (const char *)ln, lnum ); + add_srcpkg_fname( fname ); + } + + free( line ); + fclose( fp ); + } + else + { + FATAL_ERROR( "Source file names list '%s' is not a regular file" ); + } +} + +static void check_srcfile( void *data, void *user_data ) +{ + struct srcpkg_fname *srcfile = (struct srcpkg_fname *)data; + + if( srcfile ) + { + struct stat st; + char *fname = NULL; + struct pkg *srcpkg = NULL; + + bzero( (void *)&st, sizeof( struct stat ) ); + + fname = (char *)malloc( (size_t)PATH_MAX ); + if( !fname ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)fname, PATH_MAX ); + + (void)sprintf( &fname[0], "%s/%s", srcdir, srcfile->name ); + + if( stat( (const char *)fname, &st ) == -1 ) + { + FATAL_ERROR( "%s:%d: Cannot access input '%s' file or directory: %s", + srcfile->name, srcfile->line, fname, strerror( errno ) ); + } + + if( S_ISREG(st.st_mode) ) + { + enum _input_type format = IFMT_UNKNOWN; + + pid_t p = (pid_t) -1; + int rc; + + int len = 0; + char *tmp= NULL, *cmd = NULL; + + tmp = (char *)malloc( (size_t)PATH_MAX ); + if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)tmp, PATH_MAX ); + + (void)sprintf( &tmp[0], "%s", tmpdir ); + if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 ) + { + FATAL_ERROR( "%s:%d: Cannot get PKGINFO from '%s' file", + srcfile->name, srcfile->line, basename( (char *)fname ) ); + } + + cmd = (char *)malloc( (size_t)PATH_MAX ); + if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)cmd, PATH_MAX ); + + len = snprintf( &cmd[0], PATH_MAX, "%s/pkginfo -d %s -o pkginfo %s > /dev/null 2>&1", selfdir, tmp, fname ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( "%s:%d: Cannot get PKGINFO from %s file", + srcfile->name, srcfile->line, basename( (char *)fname ) ); + } + p = sys_exec_command( cmd ); + rc = sys_wait_command( p, (char *)NULL, PATH_MAX ); + if( rc != 0 ) + { + FATAL_ERROR( "%s:%d: Cannot get PKGINFO from '%s' file", + srcfile->name, srcfile->line, basename( (char *)fname ) ); + } + + (void)strcat( tmp, "/.PKGINFO" ); + + bzero( (void *)&st, sizeof( struct stat ) ); + if( stat( (const char *)tmp, &st ) == -1 ) + { + FATAL_ERROR( "%s:%d: Cannot get PKGINFO from %s file: %s", + srcfile->name, srcfile->line, basename( (char *)fname ), strerror( errno ) ); + } + + srcpkg = input_package( (const char *)&tmp[0] ); + bzero( (void *)tmp, PATH_MAX ); + if( srcpkg ) + { + char *e = NULL; + + if( srcpkg->group ) + { + len = snprintf( &tmp[0], PATH_MAX, "%s/%s", srcpkg->group, basename( (char *)fname ) ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( "%s:%d: Cannot get PKGINFO from %s file", + srcfile->name, srcfile->line, basename( (char *)fname ) ); + } + } + else + { + len = snprintf( &tmp[0], PATH_MAX, "%s", basename( (char *)fname ) ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( "%s:%d: Cannot get PKGINFO from %s file", + srcfile->name, srcfile->line, basename( (char *)fname ) ); + } + } + + add_srcpkg( srcpkg ); + + remove_trailing_slash( srcdir ); + } + + free( tmp ); + free( cmd ); + } + + free( fname ); + } +} + +static void check_srcdir( void ) +{ + struct stat st; + char *fname = srcdir; + struct pkg *srcpkg = NULL; + + bzero( (void *)&st, sizeof( struct stat ) ); + + if( stat( (const char *)srcdir, &st ) == -1 ) + { + FATAL_ERROR( "Cannot access input '%s' file or directory: %s", srcdir, strerror( errno ) ); + } + + if( S_ISREG(st.st_mode) ) + { + enum _input_type format = IFMT_UNKNOWN; + + pid_t p = (pid_t) -1; + int rc; + + int len = 0; + char *tmp= NULL, *cmd = NULL; + + tmp = (char *)malloc( (size_t)PATH_MAX ); + if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)tmp, PATH_MAX ); + + (void)sprintf( &tmp[0], "%s", tmpdir ); + if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 ) + { + FATAL_ERROR( "Cannot get PKGINFO from '%s' file", basename( (char *)fname ) ); + } + + cmd = (char *)malloc( (size_t)PATH_MAX ); + if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); } + bzero( (void *)cmd, PATH_MAX ); + + len = snprintf( &cmd[0], PATH_MAX, "%s/pkginfo -d %s -o pkginfo %s > /dev/null 2>&1", selfdir, tmp, fname ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( "Cannot get PKGINFO from %s file", basename( (char *)fname ) ); + } + p = sys_exec_command( cmd ); + rc = sys_wait_command( p, (char *)NULL, PATH_MAX ); + if( rc != 0 ) + { + FATAL_ERROR( "Cannot get PKGINFO from '%s' file", basename( (char *)fname ) ); + } + + (void)strcat( tmp, "/.PKGINFO" ); + + bzero( (void *)&st, sizeof( struct stat ) ); + if( stat( (const char *)tmp, &st ) == -1 ) + { + FATAL_ERROR( "Cannot get PKGINFO from %s file: %s", basename( (char *)fname ), strerror( errno ) ); + } + + /* keep or set input file format: */ + format = check_input_file( NULL, fname ); + if( input_format == IFMT_UNKNOWN ) input_format = format; + + srcpkg = input_package( (const char *)&tmp[0] ); + bzero( (void *)tmp, PATH_MAX ); + if( srcpkg ) + { + char *e = NULL; + + if( srcpkg->group ) + { + len = snprintf( &tmp[0], PATH_MAX, "%s/%s", srcpkg->group, basename( (char *)fname ) ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( "Cannot get PKGINFO from %s file", basename( (char *)fname ) ); + } + } + else + { + len = snprintf( &tmp[0], PATH_MAX, "%s", basename( (char *)fname ) ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( "Cannot get PKGINFO from %s file", basename( (char *)fname ) ); + } + } + + add_srcpkg( srcpkg ); + + /* remove source file name (with group directory if defined) from srcdir path */ + e = strstr( (const char *)srcdir, (const char *)&tmp[0] ); + if( !e ) { e = strstr( (const char *)srcdir, (const char *)basename( (char *)fname ) ); } + *e = '\0'; + + remove_trailing_slash( srcdir ); + } + + free( tmp ); + free( cmd ); + } + + if( S_ISDIR(st.st_mode) ) + { + if( srclist_fname ) + { + read_srcpkg_fnames( srclist_fname ); + dlist_foreach( srcpkg_fnames, check_srcfile, NULL ); + } + } +} + + +static void _print_extern_requires( void *data, void *user_data ) +{ + struct pkg *pkg = (struct pkg *)data; + + if( pkg ) + { + if( pkg->group ) + fprintf( stderr, "%s/%s:%s:%s\n", pkg->group, pkg->name, pkg->version, strproc( pkg->procedure ) ); + else + fprintf( stderr, "%s:%s:%s\n", pkg->name, pkg->version, strproc( pkg->procedure ) ); + } +} + +static void print_extern_requires( void ) +{ + dlist_foreach( extern_requires, _print_extern_requires, NULL ); +} + + +/********************************************* + 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; + + 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(); */ + + tmpdir = _mk_tmpdir(); + if( !tmpdir ) + { + FATAL_ERROR( "Cannot create temporary directory" ); + } + + /******************************************************** + Check if the --source argument is a file or directory: + */ + check_srcdir(); + + /* Extract or Copy PKGLOGs into TMPDIR: */ + if( input_format == IFMT_PKG ) + { + int pkgs = extract_pkglogs(); + if( pkgs == 0 ) { FATAL_ERROR( "There are no packages in the '%s' directory", srcdir ); } + if( exit_status > 0 ) { FATAL_ERROR( "Cannot extract PKGLOG from some package" ); } + if( ! DO_NOT_PRINTOUT_INFO ) + { + INFO( "Found %d packages in the '%s' directory", pkgs, srcdir ); + } + } + else + { + int pkgs = copy_pkglogs(); + if( pkgs == 0 ) { FATAL_ERROR( "There are no PKGLOG files in the '%s' directory", srcdir ); } + if( exit_status > 0 ) { FATAL_ERROR( "Cannot copy some PKGLOG file" ); } + if( ! DO_NOT_PRINTOUT_INFO ) + { + INFO( "Found %d PKGLOG files in the '%s' directory", pkgs, srcdir ); + } + } + + /* Read PKGLOGs from TMPDIR and create Double Linked List of PACKAGES: */ + { + int pkgs = read_pkglogs(); + if( pkgs == 0 ) { FATAL_ERROR( "There are no PKGLOG files in the '%s' directory", tmpdir ); } + if( exit_status > 0 ) { FATAL_ERROR( "Cannot read some PKGLOG file" ); } + if( ! DO_NOT_PRINTOUT_INFO ) + { + /* INFO( "Found %d PKGLOG files in the '%s' directory", pkgs, tmpdir ); */ + } + } + + { + int extern_pkgs = create_provides_list( srcpkgs ); + if( output_format == OFMT_LIST ) + { + print_provides_list( (const char *)pkglist_fname ); + if( extern_pkgs ) + { + /* Output machine readable list of requires to stderr: */ + print_extern_requires(); + exit_status += 1; + } + } + if( output_format == OFMT_JSON ) print_provides_tree( (const char *)pkglist_fname, tree_format ); + free_provides_list(); + } + + if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); } + free_resources(); + + exit( exit_status ); +} |