diff options
author | kx <kx@radix.pro> | 2023-04-11 01:18:34 +0300 |
---|---|---|
committer | kx <kx@radix.pro> | 2023-04-11 01:18:34 +0300 |
commit | 11c606a6888dc269ef018359469a7276c3ad8f67 (patch) | |
tree | 368294bb7cadcd5c44ccd082187d6a4433401027 /src/pkginfo.c | |
parent | 8c55752ed5b29a22fdab9faaa6ff27b7cafa6791 (diff) | |
download | pkgtools-11c606a6888dc269ef018359469a7276c3ad8f67.tar.xz |
Version 0.2.1pkgtools-0.2.1
Diffstat (limited to 'src/pkginfo.c')
-rw-r--r-- | src/pkginfo.c | 1573 |
1 files changed, 1573 insertions, 0 deletions
diff --git a/src/pkginfo.c b/src/pkginfo.c new file mode 100644 index 0000000..2e93a7c --- /dev/null +++ b/src/pkginfo.c @@ -0,0 +1,1573 @@ + +/********************************************************************** + + 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 <fcntl.h> +#include <linux/limits.h> +#include <alloca.h> /* alloca(3) */ +#include <string.h> /* strdup(3) */ +#include <strings.h> /* index(3) */ +#include <libgen.h> /* basename(3) */ +#include <ctype.h> /* tolower(3) */ +#include <errno.h> +#include <time.h> +#include <sys/time.h> +#include <pwd.h> +#include <grp.h> +#include <stdarg.h> +#include <unistd.h> + +#include <sys/resource.h> + +#include <signal.h> +#if !defined SIGCHLD && defined SIGCLD +# define SIGCHLD SIGCLD +#endif + +#define _GNU_SOURCE +#include <getopt.h> + + +#include <msglog.h> +#include <wrapper.h> +#include <system.h> + +#define PROGRAM_NAME "pkginfo" + +#include <defs.h> + + +char *program = PROGRAM_NAME; +char *destination = NULL, *operation = NULL, *pkglog_fname = NULL; +int exit_status = EXIT_SUCCESS; /* errors counter */ +char *selfdir = NULL; + +char *pkgname = NULL, + *pkgver = NULL, + *arch = NULL, + *distroname = NULL, + *distrover = NULL, + *group = NULL, + *url = NULL, + *license = NULL, + *uncompressed_size = NULL, + *total_files = NULL; + +FILE *pkglog = NULL; +FILE *output = NULL; + + +#define FREE_PKGINFO_VARIABLES() \ + if( pkgname ) { free( pkgname ); } pkgname = NULL; \ + if( pkgver ) { free( pkgver ); } pkgver = NULL; \ + if( arch ) { free( arch ); } arch = NULL; \ + if( distroname ) { free( distroname ); } distroname = NULL; \ + if( distrover ) { free( distrover ); } distrover = NULL; \ + if( group ) { free( group ); } group = NULL; \ + if( url ) { free( url ); } url = NULL; \ + if( license ) { free( license ); } license = NULL; \ + if( uncompressed_size ) { free( uncompressed_size ); } uncompressed_size = NULL; \ + if( total_files ) { free( total_files ); } total_files = NULL + +void free_resources() +{ + if( selfdir ) { free( selfdir ); selfdir = NULL; } + if( destination ) { free( destination ); destination = NULL; } + if( operation ) { free( operation ); operation = NULL; } + if( pkglog_fname ) { free( pkglog_fname ); pkglog_fname = NULL; } + + FREE_PKGINFO_VARIABLES(); +} + +void usage() +{ + free_resources(); + + fprintf( stdout, "\n" ); + fprintf( stdout, "Usage: %s [options] <pkglog|package>\n", program ); + fprintf( stdout, "\n" ); + fprintf( stdout, "Read information from <pkglog> or <package> file and create\n" ); + fprintf( stdout, "requested package's service files in the destination 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, " -d,--destination=<DIR> Target directory to save output files.\n" ); + fprintf( stdout, " -o,--operations=<OP1,..,OPn> Comma separated list of:\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "Operations:\n" ); + fprintf( stdout, " ----------------+----------------\n" ); + fprintf( stdout, " operation name | output file\n" ); + fprintf( stdout, " ----------------+----------------\n" ); + fprintf( stdout, " pkginfo | .PKGINFO\n" ); + fprintf( stdout, " references | .REFERENCES\n" ); + fprintf( stdout, " requires | .REQUIRES\n" ); + fprintf( stdout, " description | .DESCRIPTION\n" ); + fprintf( stdout, " restore-links | .RESTORELINKS\n" ); + fprintf( stdout, " install-script | .INSTALL\n" ); + fprintf( stdout, " filelist | .FILELIST\n" ); + fprintf( stdout, " ----------------+----------------\n" ); + fprintf( stdout, "\n" ); + fprintf( stdout, "Parameter:\n" ); + fprintf( stdout, " <pkglog|package> PKGLOG file or package tarball.\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; + } +} + +void fatal_error_actions( void ) +{ + logmsg( errlog, MSG_NOTICE, "Free resources on FATAL error..." ); + free_resources(); +} + +void sigint( int signum ) +{ + (void)signum; + free_resources(); +} + +static void set_signal_handlers() +{ + struct sigaction sa; + sigset_t set; + + memset( &sa, 0, sizeof( sa ) ); + sa.sa_handler = sigint; /* TERM, INT */ + sa.sa_flags = SA_RESTART; + sigemptyset( &set ); + sigaddset( &set, SIGTERM ); + sigaddset( &set, SIGINT ); + sa.sa_mask = set; + sigaction( SIGTERM, &sa, NULL ); + sigaction( SIGINT, &sa, NULL ); + + memset( &sa, 0, sizeof( sa ) ); /* ignore SIGPIPE */ + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + sigaction( SIGPIPE, &sa, NULL ); + + /* System V fork+wait does not work if SIGCHLD is ignored */ + signal( SIGCHLD, SIG_DFL ); +} + +enum _pkglog_type +{ + PKGLOG_TEXT = 0, + PKGLOG_GZ, + PKGLOG_BZ2, + PKGLOG_XZ, + PKGLOG_TAR, + + PKGLOG_UNKNOWN +}; + +static enum _pkglog_type pkglog_type = PKGLOG_UNKNOWN; +static char uncompress[2] = { 0, 0 }; + + +static enum _pkglog_type check_pkglog_file( const char *fname ) +{ + struct stat st; + size_t pkglog_size = 0; + unsigned char buf[8]; + int rc, fd; + + /* SIGNATURES: https://www.garykessler.net/library/file_sigs.html */ + + uncompress[0] = '\0'; + + if( stat( fname, &st ) == -1 ) + { + FATAL_ERROR( "Cannot access %s file: %s", basename( (char *)fname ), strerror( errno ) ); + } + + pkglog_size = st.st_size; + + if( (fd = open( fname, O_RDONLY )) == -1 ) + { + FATAL_ERROR( "Cannot open %s file: %s", basename( (char *)fname ), strerror( errno ) ); + } + + rc = (int)read( fd, (void *)&buf[0], 7 ); + if( rc != 7 ) + { + FATAL_ERROR( "Unknown type of input file %s", basename( (char *)fname ) ); + } + buf[7] = '\0'; + + /* TEXT */ + if( !strncmp( (const char *)&buf[0], "PACKAGE", 7 ) ) + { + close( fd ); return PKGLOG_TEXT; + } + + /* GZ */ + if( buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x08 ) + { + uncompress[0] = 'x'; + close( fd ); return PKGLOG_GZ; + } + + /* BZ2 */ + if( buf[0] == 0x42 && buf[1] == 0x5A && buf[2] == 0x68 ) + { + uncompress[0] = 'j'; + close( fd ); return PKGLOG_BZ2; + } + + /* XZ */ + if( buf[0] == 0xFD && buf[1] == 0x37 && buf[2] == 0x7A && + buf[3] == 0x58 && buf[4] == 0x5A && buf[5] == 0x00 ) + { + uncompress[0] = 'J'; + close( fd ); return PKGLOG_XZ; + } + + if( pkglog_size > 262 ) + { + if( lseek( fd, 257, SEEK_SET ) == -1 ) + { + FATAL_ERROR( "Cannot check signature of %s file: %s", basename( (char *)fname ), strerror( errno ) ); + } + rc = (int)read( fd, &buf[0], 5 ); + if( rc != 5 ) + { + FATAL_ERROR( "Cannot read signature of %s file", basename( (char *)fname ) ); + } + /* TAR */ + if( buf[0] == 0x75 && buf[1] == 0x73 && buf[2] == 0x74 && buf[3] == 0x61 && buf[4] == 0x72 ) + { + close( fd ); return PKGLOG_TAR; + } + } + + close( fd ); return PKGLOG_UNKNOWN; +} + + +void get_args( int argc, char *argv[] ) +{ + const char* short_options = "hvd:o:"; + + const struct option long_options[] = + { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "destination", required_argument, NULL, 'd' }, + { "operations", required_argument, NULL, 'o' }, + { NULL, 0, NULL, 0 } + }; + + int ret; + int option_index = 0; + + while( (ret = getopt_long( argc, argv, short_options, long_options, &option_index )) != -1 ) + { + switch( ret ) + { + case 'h': + { + usage(); + break; + } + case 'v': + { + version(); + break; + } + + case 'd': + { + if( optarg != NULL ) + { + destination = xstrdup( (const char *)optarg ); + remove_trailing_slash( destination ); + } + else + /* option is present but without value */ + usage(); + break; + } + case 'o': + { + operation = xstrdup( (const char *)optarg ); + to_lowercase( operation ); + break; + } + + case '?': default: + { + usage(); + break; + } + } + } + + if( destination == NULL ) + { + char cwd[PATH_MAX]; + if( getcwd( cwd, sizeof(cwd) ) != NULL ) + destination = xstrdup( (const char *)cwd ); + else + destination = xstrdup( "." ); + } + + if( operation == NULL ) usage(); + + /* last command line argument is the LOGFILE */ + if( optind < argc ) + { + pkglog_fname = xstrdup( (const char *)argv[optind++] ); + if( pkglog_fname == NULL ) + { + usage(); + } + pkglog_type = check_pkglog_file( (const char *)pkglog_fname ); + if( pkglog_type == PKGLOG_UNKNOWN ) + { + ERROR( "%s: Unknown input file format", basename( pkglog_fname ) ); + usage(); + } + } + else + { + usage(); + } +} + + +/* + Especialy for pkginfo lines. + Remove leading spaces and take non-space characters only: + */ +static char *skip_spaces( char *s ) +{ + char *q, *p = (char *)0; + + if( !s || *s == '\0' ) return p; + + p = s; + + while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p; + while( *q != ' ' && *q != '\t' && *q != '\0' ) { ++q; } *q = '\0'; + + if( *p == '\0' ) return (char *)0; + + return( xstrdup( (const char *)p ) ); +} + +/* + remove spaces at end of line: + */ +static void skip_eol_spaces( char *s ) +{ + char *p = (char *)0; + + if( !s || *s == '\0' ) return; + + p = s + strlen( s ) - 1; + while( isspace( *p ) ) { *p-- = '\0'; } +} + + +int printf_variable( FILE *output, char *log_fname, char *name, char *value, char *pattern, int error ) +{ + int exit_status = 0; /* local errors counter */ + char buf[24]; + char *p; + + bzero( (void *)buf, 24 ); + + if( pattern ) + (void)sprintf( (char *)&buf[0], "%s", pattern ); + + p = (char *)&buf[0]; + p[strlen(buf) - 1] = '\0'; /* skip colon at end of pattern */ + + if( value ) + { + fprintf( output, "%s=%s\n", name, value ); + } + else + { + if( error ) + { + ERROR( "There is no %s declaration in the %s file", p, log_fname ); + } + else + { + if( ! DO_NOT_WARN_ABOUT_OPT_PKGINFO_ITEMS ) + WARNING( "There is no %s declaration in the %s file", p, log_fname ); + } + } + + return( exit_status ); +} + + +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 ) + { + *s = '"'; ++s; /* start " */ + ++p; + while( *p && p < q ) + { + *s = *p; + ++p; ++s; + } + *s++ = '"'; /* stop " */ + *s = '\0'; + } +} + +int write_pkginfo() +{ + int ret = -1; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( destination != NULL ) + { + char *output_fname = NULL; + + output_fname = (char *)alloca( strlen( destination ) + 10 ); + strcpy( output_fname, destination ); + strcat( output_fname, "/.PKGINFO" ); + output = fopen( (const char *)output_fname, "w" ); + if( !output ) + { + FATAL_ERROR( "Cannot create %s file", output_fname ); + } + } + + if( (pkglog != NULL) && (output != NULL) ) + { + char *ln = NULL; + char *line = NULL; + char *desc = 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:"; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + char *match = NULL; + + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + skip_eol_spaces( ln ); /* remove spaces at end-of-line */ + + if( (match = strstr( ln, pkgname_pattern )) && match == ln ) /* at start of line only */ + { + pkgname = skip_spaces( ln + strlen( pkgname_pattern ) ); + } + if( (match = strstr( ln, pkgver_pattern )) && match == ln ) + { + pkgver = skip_spaces( ln + strlen( pkgver_pattern ) ); + } + if( (match = strstr( ln, arch_pattern )) && match == ln ) + { + arch = skip_spaces( ln + strlen( arch_pattern ) ); + } + if( (match = strstr( ln, distroname_pattern )) && match == ln ) + { + distroname = skip_spaces( ln + strlen( distroname_pattern ) ); + } + if( (match = strstr( ln, distrover_pattern )) && match == ln ) + { + distrover = skip_spaces( ln + strlen( distrover_pattern ) ); + } + if( (match = strstr( ln, group_pattern )) && match == ln ) + { + group = skip_spaces( ln + strlen( group_pattern ) ); + } + if( (match = strstr( ln, url_pattern )) && match == ln ) + { + url = skip_spaces( ln + strlen( url_pattern ) ); + } + if( (match = strstr( ln, license_pattern )) && match == ln ) + { + license = skip_spaces( ln + strlen( license_pattern ) ); + } + if( (match = strstr( ln, uncompressed_size_pattern )) && match == ln ) + { + uncompressed_size = skip_spaces( ln + strlen( uncompressed_size_pattern ) ); + } + if( (match = strstr( ln, total_files_pattern )) && match == ln ) + { + total_files = skip_spaces( 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, pkglog ); + 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' ) + { + desc = xstrdup( (const char *)buf ); + } + free( buf ); + } + } + + free( line ); + + ret += printf_variable( output, pkglog_fname, "pkgname", pkgname, pkgname_pattern, 1 ); + ret += printf_variable( output, pkglog_fname, "pkgver", pkgver, pkgver_pattern, 1 ); + ret += printf_variable( output, pkglog_fname, "arch", arch, arch_pattern, 1 ); + ret += printf_variable( output, pkglog_fname, "distroname", distroname, distroname_pattern, 1 ); + ret += printf_variable( output, pkglog_fname, "distrover", distrover, distrover_pattern, 1 ); + ret += printf_variable( output, pkglog_fname, "group", group, group_pattern, 0 ); + if( desc != NULL ) + { + ret += printf_variable( output, pkglog_fname, "short_description", desc, "SHORT DESCRIPTION:", 0 ); + free( desc ); desc = NULL; + } + ret += printf_variable( output, pkglog_fname, "url", url, url_pattern, 0 ); + ret += printf_variable( output, pkglog_fname, "license", license, license_pattern, 0 ); + ret += printf_variable( output, pkglog_fname, "uncompressed_size", uncompressed_size, uncompressed_size_pattern, 0 ); + ret += printf_variable( output, pkglog_fname, "total_files", total_files, total_files_pattern, 0 ); + + FREE_PKGINFO_VARIABLES(); + + fclose( pkglog ); pkglog = NULL; + fclose( output ); output = NULL; + } + + return( ret ); +} + + +/* + NOTE: + 1. first line has number 1. + 2. sections are ordered according to following list: + */ +int reference_counter = 0; +int requires = 0; +int package_description = 0; +int restore_links = 0; +int install_script = 0; +int file_list = 0; + +int refcount = 0; + + +int get_pkglog_sections() +{ + int ret = -1, found = 0; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( pkglog != NULL ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + char *match = NULL; + + if( (match = strstr( ln, "REFERENCE COUNTER:" )) && match == ln ) /* at start of line only */ + { + reference_counter = ret + 1; + ++found; + } + if( (match = strstr( ln, "REQUIRES:" )) && match == ln ) + { + requires = ret + 1; + ++found; + } + if( (match = strstr( ln, "PACKAGE DESCRIPTION:" )) && match == ln ) + { + package_description = ret + 1; + ++found; + } + if( (match = strstr( ln, "RESTORE LINKS:" )) && match == ln ) + { + restore_links = ret + 1; + ++found; + } + if( (match = strstr( ln, "INSTALL SCRIPT:" )) && match == ln ) + { + install_script = ret + 1; + ++found; + } + if( (match = strstr( ln, "FILE LIST:" )) && match == ln ) + { + file_list = ret + 1; + ++found; + } + + ++ret; + } + + free( line ); + + ret = found; + + fclose( pkglog ); pkglog = NULL; + } + + return( ret ); +} + + +int get_pkglog_line( char *pattern ) +{ + int ret = -1, found = 0; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( pkglog != NULL ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + char *match = NULL; + + if( (match = strstr( ln, pattern )) && match == ln ) /* at start of line only */ + { + ++ret; + ++found; + break; + } + ++ret; + } + if( !found ) ret = 0; + + free( line ); + + fclose( pkglog ); pkglog = NULL; + } + return( ret ); +} + + +int get_ref_cnt() +{ + int ret = -1, found = 0; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( pkglog != NULL ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + 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, "REFERENCE COUNTER:" )) && match == ln ) /* at start of line only */ + { + char *cnt = skip_spaces( ln + strlen( "REFERENCE COUNTER:" ) ); + ret = atoi( cnt ); + free( cnt ); + ++found; + break; + } + } + if( !found ) ret = -1; + + free( line ); + + fclose( pkglog ); pkglog = NULL; + } + return( ret ); +} + + +int write_references() +{ + int ret = -1; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( destination != NULL ) + { + char *output_fname = NULL; + + output_fname = (char *)alloca( strlen( destination ) + 13 ); + strcpy( output_fname, destination ); + strcat( output_fname, "/.REFERENCES" ); + output = fopen( (const char *)output_fname, "w" ); + if( !output ) + { + FATAL_ERROR( "Cannot create %s file", output_fname ); + } + } + + if( (pkglog != NULL) && (output != NULL) ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + if( reference_counter && reference_counter < requires ) + { + int n = 1, lines = 0; + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + skip_eol_spaces( ln ); /* remove spaces at end-of-line */ + + if( (n > reference_counter) && (n < requires) ) + { + fprintf( output, "%s\n", ln ); + ++lines; + } + ++n; + } + + ret = lines; /* number of lines in the LIST */ + } + + free( line ); + + fclose( pkglog ); pkglog = NULL; + fclose( output ); output = NULL; + } + + return( ret ); +} + + +int write_requires() +{ + int ret = -1; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( destination != NULL ) + { + char *output_fname = NULL; + + output_fname = (char *)alloca( strlen( destination ) + 11 ); + strcpy( output_fname, destination ); + strcat( output_fname, "/.REQUIRES" ); + output = fopen( (const char *)output_fname, "w" ); + if( !output ) + { + FATAL_ERROR( "Cannot create %s file", output_fname ); + } + } + + if( (pkglog != NULL) && (output != NULL) ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + if( requires && requires < package_description ) + { + int n = 1, lines = 0; + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + skip_eol_spaces( ln ); /* remove spaces at end-of-line */ + + if( (n > requires) && (n < package_description) ) + { + fprintf( output, "%s\n", ln ); + ++lines; + } + ++n; + } + + ret = lines; /* number of lines in the LIST */ + } + + free( line ); + + fclose( pkglog ); pkglog = NULL; + fclose( output ); output = NULL; + } + + return( ret ); +} + + +int write_package_description() +{ + int ret = -1; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( destination != NULL ) + { + char *output_fname = NULL; + + output_fname = (char *)alloca( strlen( destination ) + 14 ); + strcpy( output_fname, destination ); + strcat( output_fname, "/.DESCRIPTION" ); + output = fopen( (const char *)output_fname, "w" ); + if( !output ) + { + FATAL_ERROR( "Cannot create %s file", output_fname ); + } + } + + if( (pkglog != NULL) && (output != NULL) ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + if( package_description && package_description < restore_links ) + { + int n = 1, lines = 0; + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + skip_eol_spaces( ln ); /* remove spaces at end-of-line */ + + if( (n > package_description) && (n < restore_links) ) + { + fprintf( output, "%s\n", ln ); + ++lines; + } + ++n; + } + + ret = lines; /* number of lines in the LIST */ + } + + free( line ); + + fclose( pkglog ); pkglog = NULL; + fclose( output ); output = NULL; + } + + return( ret ); +} + + +int write_restore_links() +{ + int ret = -1; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( destination != NULL ) + { + char *output_fname = NULL; + + output_fname = (char *)alloca( strlen( destination ) + 15 ); + strcpy( output_fname, destination ); + strcat( output_fname, "/.RESTORELINKS" ); + output = fopen( (const char *)output_fname, "w" ); + if( !output ) + { + FATAL_ERROR( "Cannot create %s file", output_fname ); + } + } + + if( (pkglog != NULL) && (output != NULL) ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + if( restore_links && restore_links < install_script ) + { + int n = 1, lines = 0; + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + skip_eol_spaces( ln ); /* remove spaces at end-of-line */ + + if( (n > restore_links) && (n < install_script) ) + { + fprintf( output, "%s\n", ln ); + ++lines; + } + ++n; + } + + ret = lines; /* number of lines in the LIST */ + } + + free( line ); + + fclose( pkglog ); pkglog = NULL; + fclose( output ); output = NULL; + } + + return( ret ); +} + + +int write_install_script() +{ + int ret = -1; + char *output_fname = NULL; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( destination != NULL ) + { + output_fname = (char *)alloca( strlen( destination ) + 10 ); + strcpy( output_fname, destination ); + strcat( output_fname, "/.INSTALL" ); + output = fopen( (const char *)output_fname, "w" ); + if( !output ) + { + FATAL_ERROR( "Cannot create %s file", output_fname ); + } + } + + if( (pkglog != NULL) && (output != NULL) ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + if( install_script && install_script < file_list ) + { + int n = 1, lines = 0; + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + skip_eol_spaces( ln ); /* remove spaces at end-of-line */ + + if( (n > install_script) && (n < file_list) ) + { + fprintf( output, "%s\n", ln ); + ++lines; + } + ++n; + } + + ret = lines; /* number of lines in the LIST */ + } + + free( line ); + + fclose( pkglog ); pkglog = NULL; + fclose( output ); output = NULL; + } + + chmod( (const char *)output_fname, (mode_t)0755 ); + + return( ret ); +} + + +int write_filelist() +{ + int ret = -1; + + if( pkglog_fname != NULL ) + { + pkglog = fopen( (const char *)pkglog_fname, "r" ); + if( !pkglog ) + { + FATAL_ERROR( "Cannot open %s file", pkglog_fname ); + } + } + + if( destination != NULL ) + { + char *output_fname = NULL; + + output_fname = (char *)alloca( strlen( destination ) + 11 ); + strcpy( output_fname, destination ); + strcat( output_fname, "/.FILELIST" ); + output = fopen( (const char *)output_fname, "w" ); + if( !output ) + { + FATAL_ERROR( "Cannot create %s file", output_fname ); + } + } + + if( (pkglog != NULL) && (output != NULL) ) + { + char *ln = NULL; + char *line = NULL; + + line = (char *)malloc( (size_t)PATH_MAX ); + if( !line ) + { + FATAL_ERROR( "Cannot allocate memory" ); + } + + ++ret; + + if( file_list ) + { + int n = 1, lines = 0; + + ++ret; + + while( (ln = fgets( line, PATH_MAX, pkglog )) ) + { + ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */ + skip_eol_spaces( ln ); /* remove spaces at end-of-line */ + + if( n > file_list ) + { + fprintf( output, "%s\n", ln ); + ++lines; + } + ++n; + } + + ret = lines; /* number of lines in the LIST */ + } + + free( line ); + + fclose( pkglog ); pkglog = NULL; + fclose( output ); output = NULL; + } + + return( ret ); +} + + +/********************************************* + 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[] ) +{ + int sections = 0; + 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(); */ + + if( pkglog_type == PKGLOG_TEXT ) + { + sections = get_pkglog_sections(); + if( sections < 3 ) + { + FATAL_ERROR( "%s: Wrong PKGLOG file format", basename( pkglog_fname) ); + } + + refcount = get_ref_cnt(); + + if( strstr( operation, "pkginfo" ) ) exit_status += write_pkginfo(); + + if( strstr( operation, "references" ) ) + { + if( !reference_counter ) + { + WARNING( "The REFERENCE COUNTER is not present in %s file", basename( pkglog_fname ) ); + } + else + { + if( write_references() != refcount ) + { + WARNING( "The REFERENCE COUNTER invalid in %s file", basename( pkglog_fname ) ); + } + } + } + + if( strstr( operation, "requires" ) ) + { + if( write_requires() <= 0 ) + { + if( ! DO_NOT_WARN_ABOUT_EMPTY_REQUIRES ) + WARNING( "The REQUIRES is not present in %s file", basename( pkglog_fname ) ); + } + } + + if( strstr( operation, "description" ) ) + { + if( write_package_description() <= 0 ) + { + WARNING( "The PACKAGE DESCRIPTION is not present in %s file", basename( pkglog_fname ) ); + } + } + + if( strstr( operation, "restore-links" ) ) + { + if( write_restore_links() <= 0 ) + { + if( ! DO_NOT_WARN_ABOUT_EMPTY_RESTORE_LINKS ) + WARNING( "The RESTORE LINKS is not present in %s file", basename( pkglog_fname ) ); + } + } + + if( strstr( operation, "install-script" ) ) + { + if( write_install_script() <= 0 ) + { + ERROR( "The INSTALL SCRIPT is not present in %s file", basename( pkglog_fname ) ); + } + } + + if( strstr( operation, "filelist" ) ) + { + if( write_filelist() <= 0 ) + { + ERROR( "The FILE LIST is not present in %s file", basename( pkglog_fname ) ); + } + } + + } + else /* TARBALL: */ + { + pid_t p = (pid_t) -1; + int rc; + + int len = 0; + char *cmd = NULL, *errmsg = NULL, *wmsg = NULL; + + cmd = (char *)malloc( (size_t)PATH_MAX ); + if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); } + + errmsg = (char *)malloc( (size_t)PATH_MAX ); + if( !errmsg ) { FATAL_ERROR( "Cannot allocate memory" ); } + + wmsg = (char *)malloc( (size_t)PATH_MAX ); + if( !wmsg ) { FATAL_ERROR( "Cannot allocate memory" ); } + + + if( strstr( operation, "pkginfo" ) ) /* strongly required */ + { + bzero( (void *)cmd, PATH_MAX ); + bzero( (void *)errmsg, PATH_MAX ); + bzero( (void *)wmsg, PATH_MAX ); + + (void)sprintf( &errmsg[0], "Cannot get .PKGINFO from %s file", basename( pkglog_fname ) ); + + len = snprintf( &cmd[0], PATH_MAX, "tar -C %s -x%sf %s %s > /dev/null 2>&1", destination, uncompress, pkglog_fname, ".PKGINFO" ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( errmsg ); + } + p = sys_exec_command( cmd ); + rc = sys_wait_command( p, (char *)&wmsg[0], PATH_MAX ); + if( rc != 0 ) + { + /***************************************** + if( rc > 0 ) { return TAR exit status } + else { return EXIT_FAILURE } + */ + if( rc > 0 ) exit_status = rc - 1; /* ERROR() will add one */ + ERROR( errmsg ); + if( fatal_error_hook) fatal_error_hook(); + exit( exit_status ); + } + } + + /* .REFERENCES is not present in package tarball */ + + if( strstr( operation, "requires" ) ) /* optional; may be warning */ + { + bzero( (void *)cmd, PATH_MAX ); + bzero( (void *)errmsg, PATH_MAX ); + bzero( (void *)wmsg, PATH_MAX ); + + (void)sprintf( &errmsg[0], "Cannot get .REQUIRES from %s file", basename( pkglog_fname ) ); + + (void)sprintf( &cmd[0], "tar -C %s -x%sf %s %s > /dev/null 2>&1", destination, uncompress, pkglog_fname, ".REQUIRES" ); + p = sys_exec_command( cmd ); + rc = sys_wait_command( p, (char *)&wmsg[0], PATH_MAX ); + if( rc != 0 && DO_NOT_WARN_ABOUT_EMPTY_REQUIRES == 0 ) + { + WARNING( errmsg ); + } + } + + if( strstr( operation, "description" ) ) /* optional; always warning */ + { + bzero( (void *)cmd, PATH_MAX ); + bzero( (void *)wmsg, PATH_MAX ); + + (void)sprintf( &cmd[0], "tar -C %s -x%sf %s %s > /dev/null 2>&1", destination, uncompress, pkglog_fname, ".DESCRIPTION" ); + p = sys_exec_command( cmd ); + rc = sys_wait_command( p, (char *)&wmsg[0], PATH_MAX ); + if( rc != 0 ) + { + WARNING( "Cannot get package .DESCRIPTION from %s file", basename( pkglog_fname ) ); + } + } + + if( strstr( operation, "restore-links" ) ) /* optional; may be warning */ + { + bzero( (void *)cmd, PATH_MAX ); + bzero( (void *)errmsg, PATH_MAX ); + bzero( (void *)wmsg, PATH_MAX ); + + (void)sprintf( &errmsg[0], "Cannot get .RESTORELINKS script from %s file", basename( pkglog_fname ) ); + + (void)sprintf( &cmd[0], "tar -C %s -x%sf %s %s > /dev/null 2>&1", destination, uncompress, pkglog_fname, ".RESTORELINKS" ); + p = sys_exec_command( cmd ); + rc = sys_wait_command( p, (char *)&wmsg[0], PATH_MAX ); + if( rc != 0 && DO_NOT_WARN_ABOUT_EMPTY_RESTORE_LINKS == 0 ) + { + WARNING( errmsg ); + } + } + + if( strstr( operation, "install-script" ) ) /* strongly required */ + { + bzero( (void *)cmd, PATH_MAX ); + bzero( (void *)errmsg, PATH_MAX ); + bzero( (void *)wmsg, PATH_MAX ); + + (void)sprintf( &errmsg[0], "Cannot get .INSTALL script from %s file", basename( pkglog_fname ) ); + + len = snprintf( &cmd[0], PATH_MAX, "tar -C %s -x%sf %s %s > /dev/null 2>&1", destination, uncompress, pkglog_fname, ".INSTALL" ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( errmsg ); + } + p = sys_exec_command( cmd ); + rc = sys_wait_command( p, (char *)&wmsg[0], PATH_MAX ); + if( rc != 0 ) + { + /***************************************** + if( rc > 0 ) { return TAR exit status } + else { return EXIT_FAILURE } + */ + if( rc > 0 ) exit_status = rc - 1; /* ERROR() will add one */ + ERROR( errmsg ); + if( fatal_error_hook) fatal_error_hook(); + exit( exit_status ); + } + } + + if( strstr( operation, "filelist" ) ) /* strongly required */ + { + bzero( (void *)cmd, PATH_MAX ); + bzero( (void *)errmsg, PATH_MAX ); + bzero( (void *)wmsg, PATH_MAX ); + + (void)sprintf( &errmsg[0], "Cannot get .FILELIST from %s file", basename( pkglog_fname ) ); + + len = snprintf( &cmd[0], PATH_MAX, "tar -C %s -x%sf %s %s > /dev/null 2>&1", destination, uncompress, pkglog_fname, ".FILELIST" ); + if( len == 0 || len == PATH_MAX - 1 ) + { + FATAL_ERROR( errmsg ); + } + p = sys_exec_command( cmd ); + rc = sys_wait_command( p, (char *)&wmsg[0], PATH_MAX ); + if( rc != 0 ) + { + /***************************************** + if( rc > 0 ) { return TAR exit status } + else { return EXIT_FAILURE } + */ + if( rc > 0 ) exit_status = rc - 1; /* ERROR() will add one */ + ERROR( errmsg ); + if( fatal_error_hook) fatal_error_hook(); + exit( exit_status ); + } + } + + if( cmd ) free( cmd ); + if( errmsg ) free( errmsg ); + if( wmsg ) free( wmsg ); + } + + + free_resources(); + + exit( exit_status ); +} |