5 kx
5 kx /**********************************************************************
5 kx
5 kx Copyright 2019 Andrey V.Kosteltsev
5 kx
9 kx Licensed under the Radix cross Linux License, Version 1.0 .
5 kx you may not use this file except in compliance with the License.
5 kx You may obtain a copy of the License at
5 kx
9 kx https://radix-linux.su/licenses/LICENSE-1.0-en_US.txt
5 kx
5 kx Unless required by applicable law or agreed to in writing, software
5 kx distributed under the License is distributed on an "AS IS" BASIS,
5 kx WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
5 kx implied.
5 kx
5 kx **********************************************************************/
5 kx
5 kx #include <config.h>
5 kx
5 kx #include <stdlib.h>
5 kx #include <stdio.h>
5 kx #include <sys/sysinfo.h>
5 kx #include <sys/types.h>
5 kx #include <stdint.h>
5 kx #include <dirent.h>
5 kx #include <sys/stat.h> /* chmod(2) */
5 kx #include <sys/file.h> /* flock(2) */
5 kx #include <fcntl.h>
5 kx #include <linux/limits.h>
5 kx #include <alloca.h> /* alloca(3) */
5 kx #include <string.h> /* strdup(3) */
5 kx #include <strings.h> /* index(3) */
5 kx #include <libgen.h> /* basename(3) */
5 kx #include <ctype.h> /* tolower(3) */
5 kx #include <errno.h>
5 kx #include <time.h>
5 kx #include <sys/time.h>
5 kx #include <pwd.h>
5 kx #include <grp.h>
5 kx #include <stdarg.h>
5 kx #include <unistd.h>
5 kx
5 kx #include <math.h>
5 kx
5 kx #include <sys/wait.h>
5 kx
5 kx #include <sys/resource.h>
5 kx
5 kx #include <signal.h>
5 kx #if !defined SIGCHLD && defined SIGCLD
5 kx # define SIGCHLD SIGCLD
5 kx #endif
5 kx
5 kx #define _GNU_SOURCE
5 kx #include <getopt.h>
5 kx
5 kx #include <config.h>
5 kx
5 kx #include <msglog.h>
5 kx #include <wrapper.h>
5 kx #include <system.h>
5 kx
5 kx #include <cmpvers.h>
5 kx #include <dlist.h>
5 kx
5 kx #if defined( HAVE_DIALOG )
5 kx #include <dialog-ui.h>
5 kx #endif
5 kx
5 kx #define PROGRAM_NAME "install-package"
5 kx
5 kx #include <defs.h>
5 kx
5 kx
5 kx char *program = PROGRAM_NAME;
5 kx char *root = NULL, *pkgs_path = NULL, *rempkgs_path = NULL,
5 kx *pkg_fname = NULL, *asc_fname = NULL, *pkglog_fname = NULL, *pkglist_fname = NULL,
5 kx *tmpdir = NULL, *curdir = NULL, *log_fname = NULL;
5 kx
7 kx int ask = 0, rqck = 0, gpgck = 0, ignore_chrefs_errors = 0, disable_chrefs = 0;
5 kx char *description = NULL;
5 kx
5 kx int exit_status = EXIT_SUCCESS; /* errors counter */
5 kx char *selfdir = NULL;
5 kx
5 kx static char *pkgname = NULL,
5 kx *pkgver = NULL,
5 kx *arch = NULL,
5 kx *distroname = NULL,
5 kx *distrover = NULL,
5 kx *group = NULL,
5 kx *short_description = NULL,
5 kx *url = NULL,
5 kx *license = NULL,
5 kx *uncompressed_size = NULL,
5 kx *compressed_size = NULL,
5 kx *total_files = NULL;
5 kx
5 kx enum _install_mode {
5 kx CONSOLE = 0,
5 kx INFODIALOG,
5 kx MENUDIALOG
5 kx } install_mode = CONSOLE;
5 kx
5 kx enum _priority {
5 kx REQUIRED = 0, /* synonims: REQUIRED | required | REQ | req */
5 kx RECOMMENDED, /* synonims: RECOMMENDED | recommended | REC | rec */
5 kx OPTIONAL, /* synonims: OPTIONAL | optional | OPT | opt */
5 kx SKIP /* synonims: SKIP | skip | SKP | skp */
5 kx } priority = REQUIRED;
5 kx
5 kx enum _procedure
5 kx {
5 kx INSTALL = 0, /* 'install' */
5 kx UPDATE /* 'update' */
5 kx } procedure = INSTALL;
5 kx
5 kx enum _input_type {
5 kx IFMT_PKG = 0,
5 kx IFMT_LOG,
5 kx
5 kx IFMT_UNKNOWN
5 kx } input_format = IFMT_PKG;
5 kx
5 kx char uncompress = '\0';
5 kx
5 kx static struct dlist *dirs = NULL;
5 kx static struct dlist *files = NULL;
5 kx static struct dlist *links = NULL;
5 kx
5 kx static void free_list( struct dlist *list );
5 kx
5 kx
5 kx #define FREE_PKGINFO_VARIABLES() \
5 kx if( pkgname ) { free( pkgname ); } pkgname = NULL; \
5 kx if( pkgver ) { free( pkgver ); } pkgver = NULL; \
5 kx if( arch ) { free( arch ); } arch = NULL; \
5 kx if( distroname ) { free( distroname ); } distroname = NULL; \
5 kx if( distrover ) { free( distrover ); } distrover = NULL; \
5 kx if( group ) { free( group ); } group = NULL; \
5 kx if( short_description ) { free( short_description ); } short_description = NULL; \
5 kx if( description ) { free( description ); } description = NULL; \
5 kx if( url ) { free( url ); } url = NULL; \
5 kx if( license ) { free( license ); } license = NULL; \
5 kx if( uncompressed_size ) { free( uncompressed_size ); } uncompressed_size = NULL; \
5 kx if( compressed_size ) { free( compressed_size ); } compressed_size = NULL; \
5 kx if( total_files ) { free( total_files ); } total_files = NULL
5 kx
5 kx void free_resources()
5 kx {
5 kx if( root ) { free( root ); root = NULL; }
5 kx if( pkgs_path ) { free( pkgs_path ); pkgs_path = NULL; }
5 kx if( rempkgs_path ) { free( rempkgs_path ); rempkgs_path = NULL; }
5 kx if( pkg_fname ) { free( pkg_fname ); pkg_fname = NULL; }
5 kx if( asc_fname ) { free( asc_fname ); asc_fname = NULL; }
5 kx if( pkglog_fname ) { free( pkglog_fname ); pkglog_fname = NULL; }
5 kx
5 kx if( pkglist_fname ) { free( pkglist_fname ); pkglist_fname = NULL; }
5 kx
5 kx if( dirs ) { free_list( dirs ); dirs = NULL; }
5 kx if( files ) { free_list( files ); files = NULL; }
5 kx if( links ) { free_list( links ); links = NULL; }
5 kx
5 kx if( curdir ) { free( curdir ); curdir = NULL; }
5 kx if( log_fname ) { free( log_fname ); log_fname = NULL; }
5 kx
5 kx if( selfdir ) { free( selfdir ); selfdir = NULL; }
5 kx
5 kx FREE_PKGINFO_VARIABLES();
5 kx }
5 kx
5 kx void usage()
5 kx {
5 kx free_resources();
5 kx
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Usage: %s [options] <package>\n", program );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Install package.\n" );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Options:\n" );
5 kx fprintf( stdout, " -h,--help Display this information.\n" );
5 kx fprintf( stdout, " -v,--version Display the version of %s utility.\n", program );
5 kx fprintf( stdout, " -a,--always-ask Used with menudialog mode: always ask\n" );
5 kx fprintf( stdout, " if a package should be installed regardless\n" );
5 kx fprintf( stdout, " of what the package priority is. Without\n" );
5 kx fprintf( stdout, " this option, if the priority is equal to\n" );
5 kx fprintf( stdout, " REQUIRED, the package is installed without\n" );
5 kx fprintf( stdout, " asking for confirmation the installation.\n" );
5 kx fprintf( stdout, " -c,--check-requires Check package requires before install.\n" );
5 kx #if defined( HAVE_GPG2 )
5 kx fprintf( stdout, " -g,--gpg-verify Verify GPG2 signature. The signature must be\n" );
5 kx fprintf( stdout, " saved in a file whose name is the same as the\n" );
5 kx fprintf( stdout, " package file name, but with the extension '.asc'\n" );
5 kx fprintf( stdout, " and located in the same directory as the package.\n" );
5 kx #endif
5 kx fprintf( stdout, " --ignore-chrefs-errors Ignore change references errors (code: 48).\n" );
7 kx fprintf( stdout, " --disable-chrefs Do not manage references to the package.\n" );
5 kx #if defined( HAVE_DIALOG )
5 kx fprintf( stdout, " -i,--info-dialog Show package description during install\n" );
5 kx fprintf( stdout, " process using ncurses dialog.\n" );
5 kx fprintf( stdout, " -m,--menu-dialog Ask for confirmation the inatallation,\n" );
5 kx fprintf( stdout, " unless the priority is REQUIRED.\n" );
5 kx #endif
5 kx fprintf( stdout, " -l,--pkglist=<FILENAME> Specify a different package list file\n" );
5 kx fprintf( stdout, " to use for read package priority and type\n" );
5 kx fprintf( stdout, " of install procedure. By default used the\n" );
5 kx fprintf( stdout, " '.pkglist' file found in the directory\n" );
5 kx fprintf( stdout, " where source package is placed.\n" );
5 kx fprintf( stdout, " -p,--priority=<required|recommended|optional|skip>\n" );
5 kx fprintf( stdout, " Provides a priority of package instead of\n" );
5 kx fprintf( stdout, " the priority defined in the .pkglist file.\n" );
5 kx fprintf( stdout, " -r,--root=<DIR> Target rootfs path.\n" );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Parameter:\n" );
5 kx fprintf( stdout, " <package> The PACKAGE tarball.\n" );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Return codes:\n" );
5 kx fprintf( stdout, " ------+-------------------------------------------------------\n" );
5 kx fprintf( stdout, " code | status\n" );
5 kx fprintf( stdout, " ------+-------------------------------------------------------\n" );
5 kx fprintf( stdout, " 31 | package is already installed\n" );
5 kx fprintf( stdout, " 32 | package is already installed but not correct\n" );
5 kx fprintf( stdout, " 33 | previous version is already installed\n" );
5 kx fprintf( stdout, " 34 | previous version is already installed but not correct\n" );
5 kx fprintf( stdout, " 35 | a newer version is already installed\n" );
5 kx fprintf( stdout, " 36 | a newer version is already installed but not correct\n" );
5 kx fprintf( stdout, " ----+----\n" );
5 kx fprintf( stdout, " 41 | installation is aborted due to priority=SKIP\n" );
5 kx fprintf( stdout, " 42 | .pkglist appointed the 'update' procedure instead\n" );
5 kx fprintf( stdout, " 43 | pre-install script returned error status\n" );
5 kx fprintf( stdout, " 44 | uncompress process returned error status\n" );
5 kx fprintf( stdout, " 45 | restore-links script returned error status\n" );
5 kx fprintf( stdout, " 46 | post-install script returned error status\n" );
5 kx fprintf( stdout, " 47 | PKGLOG cannot be stored in the Setup Database\n" );
5 kx fprintf( stdout, " 48 | references cannot be updated in Setup Database\n" );
5 kx #if defined( HAVE_GPG2 )
5 kx fprintf( stdout, " ----+----\n" );
5 kx fprintf( stdout, " 51 | signature verification returned error status\n" );
5 kx #endif
5 kx fprintf( stdout, " ------+-------------------------------------------------------\n" );
5 kx fprintf( stdout, "\n" );
5 kx fprintf( stdout, "Upon successful completion zero is returned. Other non-zero return\n" );
5 kx fprintf( stdout, "codes imply incorrect completion of the installation.\n" );
5 kx fprintf( stdout, "\n" );
5 kx
5 kx exit( EXIT_FAILURE );
5 kx }
5 kx
5 kx void to_lowercase( char *s )
5 kx {
5 kx char *p = s;
5 kx while( p && *p ) { int c = *p; *p = tolower( c ); ++p; }
5 kx }
5 kx
5 kx void to_uppercase( char *s )
5 kx {
5 kx char *p = s;
5 kx while( p && *p ) { int c = *p; *p = toupper( c ); ++p; }
5 kx }
5 kx
5 kx void version()
5 kx {
5 kx char *upper = NULL;
5 kx
5 kx upper = (char *)alloca( strlen( program ) + 1 );
5 kx
5 kx strcpy( (char *)upper, (const char *)program );
5 kx to_uppercase( upper );
5 kx
5 kx fprintf( stdout, "%s (%s) %s\n", program, upper, PROGRAM_VERSION );
5 kx
5 kx fprintf( stdout, "Copyright (C) 2019 Andrey V.Kosteltsev.\n" );
5 kx fprintf( stdout, "This is free software. There is NO warranty; not even\n" );
5 kx fprintf( stdout, "for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" );
5 kx fprintf( stdout, "\n" );
5 kx
5 kx free_resources();
5 kx exit( EXIT_SUCCESS );
5 kx }
5 kx
5 kx
5 kx static void remove_trailing_slash( char *dir )
5 kx {
5 kx char *s;
5 kx
5 kx if( !dir || dir[0] == '\0' ) return;
5 kx
5 kx s = dir + strlen( dir ) - 1;
5 kx while( *s == '/' )
5 kx {
5 kx *s = '\0'; --s;
5 kx }
5 kx }
5 kx
5 kx
5 kx static void bind_asc_extention( char *name )
5 kx {
5 kx char *p = NULL, *q = NULL;
5 kx
5 kx if( (p = rindex( name, '.' )) && (strlen(p) < 5) )
5 kx {
5 kx if( !strncmp( p, ".gz", 3 ) ||
5 kx !strncmp( p, ".bz2", 4 ) ||
5 kx !strncmp( p, ".xz", 3 ) )
5 kx {
5 kx *p = '\0';
5 kx q = rindex( name, '.' );
5 kx if( q && (strlen(q) < 5) && !strncmp( q, ".tar", 4 ) )
5 kx {
5 kx *q = '\0';
5 kx }
5 kx }
5 kx else if( !strncmp( p, ".tar", 4 ) ||
5 kx !strncmp( p, ".tbz", 4 ) ||
5 kx !strncmp( p, ".tgz", 4 ) ||
5 kx !strncmp( p, ".txz", 4 ) )
5 kx {
5 kx *p = '\0';
5 kx }
5 kx }
5 kx
5 kx (void)strcat( name, ".asc" );
5 kx }
5 kx
5 kx ////////////////////////////////////////////////////
5 kx //static char *strmode( enum _install_mode mode )
5 kx //{
5 kx // char *p = NULL;
5 kx //
5 kx // switch( mode )
5 kx // {
5 kx // case CONSOLE:
5 kx // p = "CONSOLE";
5 kx // break;
5 kx // case INFODIALOG:
5 kx // p = "INFODIALOG";
5 kx // break;
5 kx // case MENUDIALOG:
5 kx // p = "MENUDIALOG";
5 kx // break;
5 kx // }
5 kx // return p;
5 kx //}
5 kx ////////////////////////////////////////////////////
5 kx
5 kx static char *strprio( enum _priority priority, int short_name )
5 kx {
5 kx char *p = NULL;
5 kx
5 kx switch( priority )
5 kx {
5 kx case REQUIRED:
5 kx p = ( short_name ) ? "REQ" : "required";
5 kx break;
5 kx case RECOMMENDED:
5 kx p = ( short_name ) ? "REC" : "recommended";
5 kx break;
5 kx case OPTIONAL:
5 kx p = ( short_name ) ? "OPT" : "optional";
5 kx break;
5 kx case SKIP:
5 kx p = ( short_name ) ? "SKP" : "skip";
5 kx break;
5 kx }
5 kx return p;
5 kx }
5 kx
5 kx static char *strproc( enum _procedure procedure )
5 kx {
5 kx char *p = NULL;
5 kx
5 kx switch( procedure )
5 kx {
5 kx case INSTALL:
5 kx p = "install";
5 kx break;
5 kx case UPDATE:
5 kx p = "update";
5 kx break;
5 kx }
5 kx return p;
5 kx }
5 kx
5 kx
5 kx static int _mkdir_p( const char *dir, const mode_t mode )
5 kx {
5 kx char *buf;
5 kx char *p = NULL;
5 kx struct stat sb;
5 kx
5 kx if( !dir ) return -1;
5 kx
5 kx buf = (char *)alloca( strlen( dir ) + 1 );
5 kx strcpy( buf, dir );
5 kx
5 kx remove_trailing_slash( buf );
5 kx
5 kx /* check if path exists and is a directory */
5 kx if( stat( buf, &sb ) == 0 )
5 kx {
5 kx if( S_ISDIR(sb.st_mode) )
5 kx {
5 kx return 0;
5 kx }
5 kx }
5 kx
5 kx /* mkdir -p */
5 kx for( p = buf + 1; *p; ++p )
5 kx {
5 kx if( *p == '/' )
5 kx {
5 kx *p = 0;
5 kx /* test path */
5 kx if( stat( buf, &sb ) != 0 )
5 kx {
5 kx /* path does not exist - create directory */
5 kx if( mkdir( buf, mode ) < 0 )
5 kx {
5 kx return -1;
5 kx }
5 kx } else if( !S_ISDIR(sb.st_mode) )
5 kx {
5 kx /* not a directory */
5 kx return -1;
5 kx }
5 kx *p = '/';
5 kx }
5 kx }
5 kx
5 kx /* test path */
5 kx if( stat( buf, &sb ) != 0 )
5 kx {
5 kx /* path does not exist - create directory */
5 kx if( mkdir( buf, mode ) < 0 )
5 kx {
5 kx return -1;
5 kx }
5 kx } else if( !S_ISDIR(sb.st_mode) )
5 kx {
5 kx /* not a directory */
5 kx return -1;
5 kx }
5 kx
5 kx return 0;
5 kx }
5 kx
5 kx static void _rm_tmpdir( const char *dirpath )
5 kx {
5 kx DIR *dir;
5 kx char *path;
5 kx size_t len;
5 kx
5 kx struct stat path_sb, entry_sb;
5 kx struct dirent *entry;
5 kx
5 kx if( stat( dirpath, &path_sb ) == -1 )
5 kx {
5 kx return; /* stat returns error code; errno is set */
5 kx }
5 kx
5 kx if( S_ISDIR(path_sb.st_mode) == 0 )
5 kx {
5 kx return; /* dirpath is not a directory */
5 kx }
5 kx
5 kx if( (dir = opendir(dirpath) ) == NULL )
5 kx {
5 kx return; /* Cannot open direcroty; errno is set */
5 kx }
5 kx
5 kx len = strlen( dirpath );
5 kx
5 kx while( (entry = readdir( dir )) != NULL)
5 kx {
5 kx
5 kx /* skip entries '.' and '..' */
5 kx if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
5 kx
5 kx /* determinate a full name of an entry */
5 kx path = alloca( len + strlen( entry->d_name ) + 2 );
5 kx strcpy( path, dirpath );
5 kx strcat( path, "/" );
5 kx strcat( path, entry->d_name );
5 kx
5 kx if( stat( path, &entry_sb ) == 0 )
5 kx {
5 kx if( S_ISDIR(entry_sb.st_mode) )
5 kx {
5 kx /* recursively remove a nested directory */
5 kx _rm_tmpdir( path );
5 kx }
5 kx else
5 kx {
5 kx /* remove a file object */
5 kx (void)unlink( path );
5 kx }
5 kx }
5 kx /* else { stat() returns error code; errno is set; and we have to continue the loop } */
5 kx
5 kx }
5 kx
5 kx /* remove the devastated directory and close the object of this directory */
5 kx (void)rmdir( dirpath );
5 kx
5 kx closedir( dir );
5 kx }
5 kx
5 kx static char *_mk_tmpdir( void )
5 kx {
5 kx char *buf = NULL, *p, *tmp = "/tmp";
5 kx size_t len = 0, size = 0;
5 kx
5 kx (void)umask( S_IWGRP | S_IWOTH ); /* octal 022 */
5 kx
5 kx /* Get preferred directory for tmp files */
5 kx if( (p = getenv( "TMP" )) != NULL ) {
5 kx tmp = p;
5 kx }
5 kx else if( (p = getenv( "TEMP" )) != NULL ) {
5 kx tmp = p;
5 kx }
5 kx
5 kx size = strlen( tmp ) + strlen( DISTRO_NAME ) + strlen( program ) + 12;
5 kx
5 kx buf = (char *)malloc( size );
5 kx if( !buf ) return NULL;
5 kx
5 kx len = snprintf( buf, size, (const char *)"%s/%s/%s-%.7u", tmp, DISTRO_NAME, program, getpid() );
5 kx if( len == 0 || len == size - 1 )
5 kx {
5 kx free( buf ); return NULL;
5 kx }
5 kx
5 kx _rm_tmpdir( (const char *)&buf[0] );
5 kx
5 kx if( _mkdir_p( buf, S_IRWXU | S_IRWXG | S_IRWXO ) == 0 )
5 kx {
5 kx return buf;
5 kx }
5 kx
5 kx free( buf ); return NULL;
5 kx }
5 kx
5 kx
5 kx void fatal_error_actions( void )
5 kx {
5 kx logmsg( errlog, MSG_NOTICE, "Free resources on FATAL error..." );
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx }
5 kx
5 kx void sigint( int signum )
5 kx {
5 kx (void)signum;
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx }
5 kx
5 kx static void set_signal_handlers()
5 kx {
5 kx struct sigaction sa;
5 kx sigset_t set;
5 kx
5 kx memset( &sa, 0, sizeof( sa ) );
5 kx sa.sa_handler = sigint; /* TERM, INT */
5 kx sa.sa_flags = SA_RESTART;
5 kx sigemptyset( &set );
5 kx sigaddset( &set, SIGTERM );
5 kx sigaddset( &set, SIGINT );
5 kx sa.sa_mask = set;
5 kx sigaction( SIGTERM, &sa, NULL );
5 kx sigaction( SIGINT, &sa, NULL );
5 kx
5 kx memset( &sa, 0, sizeof( sa ) ); /* ignore SIGPIPE */
5 kx sa.sa_handler = SIG_IGN;
5 kx sa.sa_flags = 0;
5 kx sigaction( SIGPIPE, &sa, NULL );
5 kx
5 kx /* System V fork+wait does not work if SIGCHLD is ignored */
5 kx signal( SIGCHLD, SIG_DFL );
5 kx }
5 kx
5 kx
5 kx static enum _input_type check_input_file( char *uncompress, const char *fname )
5 kx {
5 kx struct stat st;
5 kx size_t pkglog_size = 0;
5 kx unsigned char buf[8];
5 kx int rc, fd;
5 kx
5 kx /* SIGNATURES: https://www.garykessler.net/library/file_sigs.html */
5 kx
5 kx if( uncompress )
5 kx {
5 kx *uncompress = '\0';
5 kx }
5 kx
5 kx if( stat( fname, &st ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot access %s file: %s", basename( (char *)fname ), strerror( errno ) );
5 kx }
5 kx
5 kx pkglog_size = st.st_size;
5 kx
5 kx if( (fd = open( fname, O_RDONLY )) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot open %s file: %s", basename( (char *)fname ), strerror( errno ) );
5 kx }
5 kx
5 kx rc = (int)read( fd, (void *)&buf[0], 7 );
5 kx if( rc != 7 )
5 kx {
5 kx close( fd ); return IFMT_UNKNOWN;
5 kx }
5 kx buf[7] = '\0';
5 kx
5 kx /* TEXT */
5 kx if( !strncmp( (const char *)&buf[0], "PACKAGE", 7 ) )
5 kx {
5 kx close( fd ); return IFMT_LOG;
5 kx }
5 kx
5 kx /* GZ */
5 kx if( buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x08 )
5 kx {
5 kx if( uncompress ) { *uncompress = 'x'; }
5 kx close( fd ); return IFMT_PKG;
5 kx }
5 kx
5 kx /* BZ2 */
5 kx if( buf[0] == 0x42 && buf[1] == 0x5A && buf[2] == 0x68 )
5 kx {
5 kx if( uncompress ) { *uncompress = 'j'; }
5 kx close( fd ); return IFMT_PKG;
5 kx }
5 kx
5 kx /* XZ */
5 kx if( buf[0] == 0xFD && buf[1] == 0x37 && buf[2] == 0x7A &&
5 kx buf[3] == 0x58 && buf[4] == 0x5A && buf[5] == 0x00 )
5 kx {
5 kx if( uncompress ) { *uncompress = 'J'; }
5 kx close( fd ); return IFMT_PKG;
5 kx }
5 kx
5 kx if( pkglog_size > 262 )
5 kx {
5 kx if( lseek( fd, 257, SEEK_SET ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot check signature of %s file: %s", basename( (char *)fname ), strerror( errno ) );
5 kx }
5 kx rc = (int)read( fd, &buf[0], 5 );
5 kx if( rc != 5 )
5 kx {
5 kx FATAL_ERROR( "Cannot read signature of %s file", basename( (char *)fname ) );
5 kx }
5 kx /* TAR */
5 kx if( buf[0] == 0x75 && buf[1] == 0x73 && buf[2] == 0x74 && buf[3] == 0x61 && buf[4] == 0x72 )
5 kx {
5 kx close( fd ); return IFMT_PKG;
5 kx }
5 kx }
5 kx
5 kx close( fd ); return IFMT_UNKNOWN;
5 kx }
5 kx
5 kx
5 kx void get_args( int argc, char *argv[] )
5 kx {
5 kx #if defined( HAVE_GPG2 )
5 kx #if defined( HAVE_DIALOG )
5 kx const char* short_options = "hvacgiml:p:r:";
5 kx #else
5 kx const char* short_options = "hvacgl:p:r:";
5 kx #endif
5 kx #else
5 kx #if defined( HAVE_DIALOG )
5 kx const char* short_options = "hvaciml:p:r:";
5 kx #else
5 kx const char* short_options = "hvacl:p:r:";
5 kx #endif
5 kx #endif
5 kx
5 kx #define IGNORE_CHREFS_ERRORS 872
7 kx #define DISABLE_CHREFS 873
5 kx
5 kx const struct option long_options[] =
5 kx {
5 kx { "help", no_argument, NULL, 'h' },
5 kx { "version", no_argument, NULL, 'v' },
5 kx { "always-ask", no_argument, NULL, 'a' },
5 kx { "check-requires", no_argument, NULL, 'c' },
5 kx #if defined( HAVE_GPG2 )
5 kx { "gpg-verify", no_argument, NULL, 'g' },
5 kx #endif
5 kx { "ignore-chrefs-errors", no_argument, NULL, IGNORE_CHREFS_ERRORS },
7 kx { "disable-chrefs", no_argument, NULL, DISABLE_CHREFS },
5 kx #if defined( HAVE_DIALOG )
5 kx { "info-dialog", no_argument, NULL, 'i' },
5 kx { "menu-dialog", no_argument, NULL, 'm' },
5 kx #endif
5 kx { "pkglist", required_argument, NULL, 'l' },
5 kx { "priority", required_argument, NULL, 'p' },
5 kx { "root", required_argument, NULL, 'r' },
5 kx { NULL, 0, NULL, 0 }
5 kx };
5 kx
5 kx int ret;
5 kx int option_index = 0;
5 kx
5 kx while( (ret = getopt_long( argc, argv, short_options, long_options, &option_index )) != -1 )
5 kx {
5 kx switch( ret )
5 kx {
5 kx case 'h':
5 kx {
5 kx usage();
5 kx break;
5 kx }
5 kx case 'v':
5 kx {
5 kx version();
5 kx break;
5 kx }
5 kx case 'a':
5 kx {
5 kx ask = 1;
5 kx break;
5 kx }
5 kx case 'c':
5 kx {
5 kx rqck = 1;
5 kx break;
5 kx }
5 kx #if defined( HAVE_GPG2 )
5 kx case 'g':
5 kx {
5 kx gpgck = 1;
5 kx break;
5 kx }
5 kx #endif
5 kx
5 kx #if defined( HAVE_DIALOG )
5 kx case 'i':
5 kx {
5 kx install_mode = INFODIALOG;
5 kx break;
5 kx }
5 kx case 'm':
5 kx {
5 kx install_mode = MENUDIALOG;
5 kx break;
5 kx }
5 kx #endif
5 kx
5 kx case IGNORE_CHREFS_ERRORS:
5 kx {
5 kx ignore_chrefs_errors = 1;
5 kx break;
5 kx }
5 kx
7 kx case DISABLE_CHREFS:
7 kx {
7 kx disable_chrefs = 1;
7 kx break;
7 kx }
7 kx
5 kx case 'p':
5 kx {
5 kx if( optarg != NULL )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx if( strlen( (const char *)optarg ) > 2 )
5 kx {
5 kx to_lowercase( optarg );
5 kx if( (match = strstr( optarg, "req" )) && match == optarg ) {
5 kx priority = REQUIRED;
5 kx }
5 kx else if( (match = strstr( optarg, "rec" )) && match == optarg ) {
5 kx priority = RECOMMENDED;
5 kx }
5 kx else if( (match = strstr( optarg, "opt" )) && match == optarg ) {
5 kx priority = OPTIONAL;
5 kx }
5 kx else if( (match = strstr( optarg, "sk" )) && match == optarg ) {
5 kx priority = SKIP;
5 kx }
5 kx else {
5 kx FATAL_ERROR( "Unknown --priority '%s' value", optarg );
5 kx }
5 kx }
5 kx else
5 kx {
5 kx FATAL_ERROR( "Unknown --priority '%s' value", optarg );
5 kx }
5 kx }
5 kx else
5 kx /* option is present but without value */
5 kx usage();
5 kx break;
5 kx }
5 kx
5 kx case 'l':
5 kx {
5 kx if( optarg != NULL )
5 kx {
5 kx pkglist_fname = xstrdup( (const char *)optarg );
5 kx }
5 kx else
5 kx /* option is present but without value */
5 kx usage();
5 kx break;
5 kx }
5 kx
5 kx case 'r':
5 kx {
5 kx if( optarg != NULL )
5 kx {
5 kx char cwd[PATH_MAX];
5 kx
5 kx bzero( (void *)cwd, PATH_MAX );
5 kx if( optarg[0] != '/' && curdir )
5 kx {
5 kx /* skip current directory definition './' at start of argument: */
5 kx if( !strncmp( optarg, "./", 2 ) && strncmp( optarg, "..", 2 ) )
5 kx (void)sprintf( cwd, "%s/%s", curdir, optarg + 2 );
5 kx else if( (strlen( optarg ) == 1) && !strncmp( optarg, ".", 1 ) )
5 kx (void)sprintf( cwd, "%s", curdir );
5 kx else
5 kx (void)sprintf( cwd, "%s/%s", curdir, optarg );
5 kx root = xstrdup( (const char *)cwd );
5 kx }
5 kx else
5 kx {
5 kx root = xstrdup( (const char *)optarg );
5 kx }
5 kx remove_trailing_slash( root );
5 kx }
5 kx else
5 kx /* option is present but without value */
5 kx usage();
5 kx break;
5 kx }
5 kx
5 kx case '?': default:
5 kx {
5 kx usage();
5 kx break;
5 kx }
5 kx }
5 kx }
5 kx
5 kx
5 kx if( optind < argc )
5 kx {
5 kx struct stat st;
5 kx char *buf = NULL;
5 kx
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx
5 kx buf = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)buf, PATH_MAX );
5 kx
5 kx /* absolute path to input package: */
5 kx if( argv[optind][0] != '/' && curdir )
5 kx (void)sprintf( buf, "%s/%s", curdir, (const char *)argv[optind] );
5 kx else
5 kx (void)strcpy( buf, (const char *)argv[optind] );
5 kx
5 kx if( stat( (const char *)&buf[0], &st ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot access '%s' file: %s", buf, strerror( errno ) );
5 kx }
5 kx
5 kx if( S_ISREG(st.st_mode) )
5 kx {
5 kx pkg_fname = xstrdup( (const char *)&buf[0] );
5 kx bind_asc_extention( buf );
5 kx asc_fname = xstrdup( (const char *)&buf[0] );
5 kx free( buf );
5 kx }
5 kx else
5 kx {
5 kx FATAL_ERROR( "Input package '%s' is not a regular file", (const char *)argv[optind] );
5 kx }
5 kx }
5 kx else
5 kx {
5 kx usage();
5 kx }
5 kx
5 kx
5 kx if( !pkgs_path )
5 kx {
5 kx struct stat st;
5 kx char *buf = NULL;
5 kx int len;
5 kx
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx
5 kx buf = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)buf, PATH_MAX );
5 kx
5 kx if( !root )
5 kx {
5 kx buf[0] = '/'; buf[1] = '\0';
5 kx root = xstrdup( (const char *)buf );
5 kx }
5 kx else
5 kx {
5 kx len = strlen( root );
5 kx
5 kx (void)strcpy( buf, (const char *)root );
5 kx if( buf[ len - 1 ] != '/' )
5 kx {
5 kx buf[len] = '/'; buf[len+1] = '\0';
5 kx free( root ); root = xstrdup( (const char *)buf );
5 kx }
5 kx }
5 kx
5 kx if( stat( (const char *)&buf[0], &st ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot access '%s' file or directory: %s", buf, strerror( errno ) );
5 kx }
5 kx if( !S_ISDIR(st.st_mode) )
5 kx {
5 kx FATAL_ERROR( "Defined --root '%s' is not a directory", buf );
5 kx }
5 kx
5 kx len = strlen( (const char *)buf );
5 kx
5 kx (void)strcat( buf, PACKAGES_PATH );
5 kx if( _mkdir_p( buf, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot access '/%s' directory", PACKAGES_PATH );
5 kx }
5 kx pkgs_path = xstrdup( (const char *)&buf[0] );
5 kx
5 kx /*********************************************
5 kx Create other directories of Setup Database:
5 kx */
5 kx buf[len] = '\0';
5 kx (void)strcat( buf, REMOVED_PKGS_PATH );
5 kx if( _mkdir_p( buf, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot access '/%s' directory", REMOVED_PKGS_PATH );
5 kx }
5 kx rempkgs_path = xstrdup( (const char *)&buf[0] );
5 kx
5 kx buf[len] = '\0';
5 kx (void)strcat( buf, SETUP_PATH );
5 kx if( _mkdir_p( buf, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot access '/%s' directory", SETUP_PATH );
5 kx }
5 kx
5 kx /*********************************************
5 kx Allocate memory for Setup LOG File name:
5 kx */
5 kx buf[len] = '\0';
5 kx (void)strcat( buf, LOG_PATH );
5 kx (void)strcat( buf, SETUP_LOG_FILE );
5 kx log_fname = xstrdup( (const char *)&buf[0] );
5 kx
5 kx free( buf );
5 kx
5 kx } /* End if( !pkgs_path ) */
5 kx }
5 kx
5 kx static void setup_log( char *format, ... )
5 kx {
5 kx FILE *fp = NULL;
5 kx
5 kx time_t t = time( NULL );
5 kx struct tm tm = *localtime(&t);
5 kx
5 kx va_list argp;
5 kx
5 kx if( ! format ) return;
5 kx
5 kx fp = fopen( (const char *)log_fname, "a" );
5 kx if( !fp )
5 kx {
5 kx FATAL_ERROR( "Cannot open /%s%s file", LOG_PATH, SETUP_LOG_FILE );
5 kx }
5 kx
5 kx fprintf( fp, "[%04d-%02d-%02d %02d:%02d:%02d]: ",
5 kx tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
5 kx tm.tm_hour, tm.tm_min, tm.tm_sec );
5 kx
5 kx va_start( argp, format );
5 kx vfprintf( fp, format, argp );
5 kx fprintf( fp, "\n" );
5 kx
5 kx fflush( fp );
5 kx fclose( fp );
5 kx }
5 kx
5 kx /***********************************************************
5 kx Remove leading spaces and take non-space characters only:
5 kx (Especialy for pkginfo lines)
5 kx */
5 kx static char *skip_spaces( char *s )
5 kx {
5 kx char *q, *p = (char *)0;
5 kx
5 kx if( !s || *s == '\0' ) return p;
5 kx
5 kx p = s;
5 kx
5 kx while( (*p == ' ' || *p == '\t') && *p != '\0' ) { ++p; } q = p;
5 kx while( *q != ' ' && *q != '\t' && *q != '\0' ) { ++q; } *q = '\0';
5 kx
5 kx if( *p == '\0' ) return (char *)0;
5 kx
5 kx return( xstrdup( (const char *)p ) );
5 kx }
5 kx
5 kx
5 kx /*******************************
5 kx remove spaces at end of line:
5 kx */
5 kx static void skip_eol_spaces( char *s )
5 kx {
5 kx char *p = (char *)0;
5 kx
5 kx if( !s || *s == '\0' ) return;
5 kx
5 kx p = s + strlen( s ) - 1;
5 kx while( isspace( *p ) ) { *p-- = '\0'; }
5 kx }
5 kx
5 kx
5 kx static char *trim( char *s )
5 kx {
5 kx char *p = (char *)0;
5 kx
5 kx if( !s || *s == '\0' ) return p;
5 kx
5 kx p = s + strlen( s ) - 1;
5 kx while( isspace( *p ) ) { *p-- = '\0'; }
5 kx p = s; while( isspace( *p ) ) { ++p; }
5 kx
5 kx return( p );
5 kx }
5 kx
5 kx
5 kx static char *size_to_string( size_t pkgsize )
5 kx {
5 kx int nd;
5 kx double sz = (double)pkgsize / (double)1024;
5 kx
5 kx char *ret = NULL;
5 kx char *tmp = NULL;
5 kx
5 kx tmp = (char *)malloc( PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx if( sz > (double)1048576 )
5 kx {
5 kx sz = sz / (double)1048576;
5 kx /*
5 kx NOTE:
5 kx ----
5 kx Операция округления до одного знака после десятичной точки: sz = round(sz*10.0)/10.0;
5 kx здесь не нужна; можно обойтись вычислением количества цифр, выводимых на печать с помощью
5 kx формата '%.*g':
5 kx
5 kx Количество десятичных цифр, необходимое для предстваления целой части числа + 1(одна)
5 kx десятичная цифра после десятичной точки. Формат %.*g не будет выводить дробную часть
5 kx числа, если после округления, до одного знака после десятичной точки, дробная часть
5 kx равна нулю:
5 kx */
5 kx nd = (int)ceil(log10(floor(sz) + 1.0)) + 1;
5 kx (void)sprintf( (char *)&tmp[0], "%.*gG", nd, sz );
5 kx }
5 kx else if( sz > (double)1024 )
5 kx {
5 kx sz = sz / (double)1024;
5 kx nd = (int)ceil(log10(floor(sz) + 1.0)) + 1;
5 kx (void)sprintf( (char *)&tmp[0], "%.*gM", nd, sz );
5 kx }
5 kx else
5 kx {
5 kx nd = (int)ceil(log10(floor(sz) + 1.0)) + 1;
5 kx (void)sprintf( (char *)&tmp[0], "%.*gK", nd, sz );
5 kx }
5 kx
5 kx ret = xstrdup( (const char *)&tmp[0] );
5 kx free( tmp );
5 kx
5 kx return ret;
5 kx }
5 kx
5 kx static void read_input_pkginfo( const char *pkginfo_fname )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx FILE *pkginfo = NULL;
5 kx
5 kx if( pkginfo_fname != NULL )
5 kx {
5 kx pkginfo = fopen( (const char *)pkginfo_fname, "r" );
5 kx if( !pkginfo )
5 kx {
5 kx FATAL_ERROR( "Cannot open %s file", pkginfo_fname );
5 kx }
5 kx }
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, pkginfo )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( (match = strstr( ln, "pkgname" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) pkgname = skip_spaces( p );
5 kx }
5 kx if( (match = strstr( ln, "pkgver" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) pkgver = skip_spaces( p );
5 kx }
5 kx if( (match = strstr( ln, "arch" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) arch = skip_spaces( p );
5 kx }
5 kx if( (match = strstr( ln, "distroname" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) distroname = skip_spaces( p );
5 kx }
5 kx if( (match = strstr( ln, "distrover" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) distrover = skip_spaces( p );
5 kx }
5 kx
5 kx if( (match = strstr( ln, "group" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) group = skip_spaces( p );
5 kx }
5 kx
5 kx if( (match = strstr( ln, "short_description" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL )
5 kx {
5 kx char *b = index( p, '"'),
5 kx *e = rindex( p, '"');
5 kx if( b && e && ( b != e ) )
5 kx {
5 kx p = ++b; *e = '\0';
5 kx short_description = xstrdup( (const char *)p );
5 kx }
5 kx }
5 kx }
5 kx if( (match = strstr( ln, "url" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) url = skip_spaces( p );
5 kx }
5 kx if( (match = strstr( ln, "license" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) license = skip_spaces( p );
5 kx }
5 kx
5 kx if( (match = strstr( ln, "uncompressed_size" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) uncompressed_size = skip_spaces( p );
5 kx }
5 kx if( (match = strstr( ln, "total_files" )) && match == ln ) {
5 kx char *p = index( match, '=' ) + 1;
5 kx if( p != NULL ) total_files = skip_spaces( p );
5 kx }
5 kx }
5 kx
5 kx free( line );
5 kx
5 kx if( !pkgname || !pkgver || !arch || !distroname || !distrover )
5 kx {
5 kx FATAL_ERROR( "Invalid input .PKGINFO file" );
5 kx }
5 kx
5 kx fclose( pkginfo );
5 kx }
5 kx
5 kx
5 kx static void read_service_files( void )
5 kx {
5 kx struct stat st;
5 kx char *fname = pkg_fname;
5 kx
5 kx enum _input_type type = IFMT_UNKNOWN;
5 kx
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx
5 kx if( stat( (const char *)fname, &st ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot access input '%s' file: %s", fname, strerror( errno ) );
5 kx }
5 kx
5 kx type = check_input_file( &uncompress, fname );
5 kx if( type != IFMT_PKG )
5 kx {
5 kx FATAL_ERROR( "Unknown format of input '%s' file", fname );
5 kx }
5 kx
5 kx if( S_ISREG(st.st_mode) )
5 kx {
5 kx pid_t p = (pid_t) -1;
5 kx int rc;
5 kx
5 kx int len = 0;
5 kx char *tmp= NULL, *cmd = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx (void)sprintf( &tmp[0], "%s", tmpdir );
5 kx if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGINFO from '%s' file", basename( (char *)fname ) );
5 kx }
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "%s/pkginfo -d %s"
5 kx " -o pkginfo,description,requires,restore-links,install-script,filelist"
5 kx " %s > /dev/null 2>&1",
5 kx selfdir, tmp, fname );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGINFO from %s file", basename( (char *)fname ) );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx if( rc != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGINFO from '%s' file", basename( (char *)fname ) );
5 kx }
5 kx
5 kx (void)strcat( tmp, "/.PKGINFO" );
5 kx read_input_pkginfo( (const char *)&tmp[0] );
5 kx *(strstr( tmp, "/.PKGINFO" )) = '\0'; /* :restore tmpdir in tmp[] buffer */
5 kx
5 kx compressed_size = size_to_string( st.st_size );
5 kx
5 kx /******************
5 kx Get PKGLOG file:
5 kx */
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "%s/pkglog -m -d %s %s > /dev/null 2>&1",
5 kx selfdir, tmp, tmp );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGLOG from %s file", basename( (char *)fname ) );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx if( rc != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGLOG from '%s' file", basename( (char *)fname ) );
5 kx }
5 kx
5 kx if( group )
5 kx (void)sprintf( cmd, "%s/%s/%s-%s-%s-%s-%s", tmp, group, pkgname, pkgver, arch, distroname, distrover );
5 kx else
5 kx (void)sprintf( cmd, "%s/%s-%s-%s-%s-%s", tmp, pkgname, pkgver, arch, distroname, distrover );
5 kx
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx if( stat( (const char *)cmd, &st ) == -1 )
5 kx {
5 kx FATAL_ERROR( "Cannot get PKGLOG from '%s' file: %s", basename( (char *)fname ), strerror( errno ) );
5 kx }
5 kx
5 kx pkglog_fname = xstrdup( (const char *)cmd );
5 kx
5 kx /*************************************
5 kx Attempt to read packages list file:
5 kx */
5 kx {
5 kx if( !pkglist_fname )
5 kx {
5 kx /*****************************************
5 kx Get source packages path if applicable:
5 kx */
5 kx (void)strcpy( cmd, (const char *)fname );
5 kx (void)strcpy( tmp, dirname( cmd ) );
5 kx
5 kx if( group && !strcmp( group, basename( tmp ) ) )
5 kx (void)strcpy( cmd, (const char *)dirname( tmp ) );
5 kx else
5 kx (void)strcpy( cmd, (const char *)tmp );
5 kx
5 kx /*****************************************
5 kx Save default packages list file name:
5 kx */
5 kx (void)strcat( cmd, "/.pkglist" );
5 kx pkglist_fname = xstrdup( (const char *)cmd );
5 kx }
5 kx
5 kx /**************************
5 kx read .pkglist if exists:
5 kx */
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx if( (stat( (const char *)pkglist_fname, &st ) == 0) && S_ISREG(st.st_mode) )
5 kx {
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx FILE *pkglist = NULL;
5 kx
5 kx pkglist = fopen( (const char *)pkglist_fname, "r" );
5 kx if( !pkglist )
5 kx {
5 kx FATAL_ERROR( "Cannot open %s file", pkglist_fname );
5 kx }
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, pkglist )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( (match = strstr( ln, pkgname )) && match == ln )
5 kx {
5 kx char *p = NULL;
5 kx char *name = NULL, *vers = NULL, *desc = NULL, *ball = NULL, *proc = NULL, *prio = NULL;
5 kx
5 kx name = ln;
5 kx if( (p = index( (const char *)name, ':' )) ) { *p = '\0'; vers = ++p; name = trim( name ); } else continue;
5 kx if( (p = index( (const char *)vers, ':' )) ) { *p = '\0'; desc = ++p; vers = trim( vers ); } else continue;
5 kx if( (p = index( (const char *)desc, ':' )) ) { *p = '\0'; ball = ++p; desc = trim( desc ); } else continue;
5 kx if( (p = index( (const char *)ball, ':' )) ) { *p = '\0'; proc = ++p; ball = trim( ball ); } else continue;
5 kx if( (p = index( (const char *)proc, ':' )) ) { *p = '\0'; prio = ++p; proc = trim( proc ); } else continue;
5 kx prio = trim( prio );
5 kx
5 kx if( name && vers && desc && ball && proc && prio )
5 kx {
5 kx char *grp = index( (const char *)ball, '/' );
5 kx if( grp )
5 kx {
5 kx *grp = '\0'; grp = ball; grp = trim( grp );
5 kx if( strcmp( group, grp ) ) continue;
5 kx }
5 kx
5 kx /* read priority: */
5 kx if( strlen( (const char*)prio ) > 2 )
5 kx {
5 kx char *m = NULL;
5 kx
5 kx to_lowercase( prio );
5 kx if( (m = strstr( prio, "req" )) && m == prio ) {
5 kx priority = REQUIRED;
5 kx }
5 kx else if( (m = strstr( prio, "rec" )) && m == prio ) {
5 kx priority = RECOMMENDED;
5 kx }
5 kx else if( (m = strstr( prio, "opt" )) && m == prio ) {
5 kx priority = OPTIONAL;
5 kx }
5 kx else if( (m = strstr( prio, "sk" )) && m == prio ) {
5 kx priority = SKIP;
5 kx }
5 kx else {
5 kx priority = REQUIRED;
5 kx }
5 kx }
5 kx else
5 kx {
5 kx priority = REQUIRED;
5 kx }
5 kx
5 kx /* read procedure: */
5 kx if( strlen( (const char*)proc ) > 5 )
5 kx {
5 kx char *m = NULL;
5 kx
5 kx to_lowercase( proc );
5 kx if( (m = strstr( proc, "install" )) && m == proc ) {
5 kx procedure = INSTALL;
5 kx }
5 kx else if( (m = strstr( proc, "update" )) && m == proc ) {
5 kx procedure = UPDATE;
5 kx }
5 kx else {
5 kx procedure = INSTALL;
5 kx }
5 kx }
5 kx else
5 kx {
5 kx procedure = INSTALL;
5 kx }
5 kx }
5 kx
5 kx } /* End if( match ) */
5 kx
5 kx } /* End of while( ln = fgets() ) */
5 kx
5 kx free( line );
5 kx fclose( pkglist );
5 kx
5 kx } /* End of reading .pkglist */
5 kx
5 kx } /* End of attemption of reading .pkflist file */
5 kx
5 kx free( cmd );
5 kx free( tmp );
5 kx
5 kx if( priority == SKIP )
5 kx {
5 kx exit_status = 41;
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx char *tmp = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx (void)sprintf( &tmp[0],
5 kx "\nInstall procedure is skipped due to specified\nthe '%s' priority.\n",
5 kx strprio( priority, 0 ) );
5 kx
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx (const char *)&tmp[0], 6, 0, 0 );
5 kx
5 kx free( tmp );
5 kx #else
5 kx fprintf( stdout,
5 kx "\nInstall procedure of package '%s-%s' is skipped due to specified '%s' priority.\n\n",
5 kx pkgname, pkgver, strprio( priority, 0 ) );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout,
5 kx "\nInstall procedure of package '%s-%s' is skipped due to specified '%s' priority.\n\n",
5 kx pkgname, pkgver, strprio( priority, 0 ) );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx
5 kx exit( exit_status );
5 kx }
5 kx
5 kx if( procedure != INSTALL )
5 kx {
5 kx exit_status = 42;
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx char *tmp = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx (void)sprintf( &tmp[0],
5 kx "\nInstall procedure is skipped because the '%s' procedure\nis specified.\n",
5 kx strproc( procedure ) );
5 kx
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx (const char *)&tmp[0], 6, 0, 0 );
5 kx
5 kx free( tmp );
5 kx #else
5 kx fprintf( stdout,
5 kx "\nInstall procedure of package '%s-%s' is skipped because the '%s' procedure is specified.\n\n",
5 kx pkgname, pkgver, strproc( procedure ) );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout,
5 kx "\nInstall procedure of package '%s-%s' is skipped because the '%s' procedure is specified.\n\n",
5 kx pkgname, pkgver, strproc( procedure ) );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx
5 kx exit( exit_status );
5 kx }
5 kx
5 kx }
5 kx else
5 kx {
5 kx FATAL_ERROR( "Input %s file is not a regular file", basename( (char *)fname ) );
5 kx }
5 kx }
5 kx
5 kx static void check_package( void )
5 kx {
7 kx pid_t p = (pid_t) -1;
7 kx int rc = EXIT_SUCCESS;
5 kx
5 kx int len = 0;
5 kx char *cmd = NULL;
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "%s/check-package --quiet --root=%s %s > /dev/null 2>&1",
5 kx selfdir, root, pkglog_fname );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot check whether the package '%s-%s' is already installed", pkgname, pkgver );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx switch( rc )
5 kx {
5 kx case 30:
5 kx /* Package is not installed. Continue the installation. */
5 kx break;
5 kx case 31:
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nPackage is already installed.\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nPackage '%s-%s' is already installed.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nPackage '%s-%s' is already installed.\n\n", pkgname, pkgver );
5 kx }
5 kx break;
5 kx case 32:
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nPackage is already installed but not correct.\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nPackage '%s-%s' is already installed but not correct.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nPackage '%s-%s' is already installed but not correct.\n\n", pkgname, pkgver );
5 kx }
5 kx break;
5 kx case 33:
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nPrevious version of package is installed.\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nPrevious version of package '%s-%s' is installed.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nPrevious version of package '%s-%s' is installed.\n\n", pkgname, pkgver );
5 kx }
5 kx break;
5 kx case 34:
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nPrevious version of package is installed but not correct.\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nPrevious version of package '%s-%s' is installed but not correct.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nPrevious version of package '%s-%s' is installed but not correct.\n\n", pkgname, pkgver );
5 kx }
5 kx break;
5 kx case 35:
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nA newer version of package is already installed.\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nA newer version of package '%s-%s' is already installed.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nA newer version of package '%s-%s' is already installed.\n\n", pkgname, pkgver );
5 kx }
5 kx break;
5 kx case 36:
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nA newer version of package is installed but not correct.\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nA newer version of package '%s-%s' is installed but not correct.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nA newer version of package '%s-%s' is installed but not correct.\n\n", pkgname, pkgver );
5 kx }
5 kx break;
5 kx default:
5 kx FATAL_ERROR( "Cannot check whether the package '%s-%s' is already installed", pkgname, pkgver );
5 kx break;
5 kx }
5 kx
5 kx free( cmd );
5 kx
5 kx if( rc != 30 )
5 kx {
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( rc );
5 kx }
5 kx }
5 kx
5 kx
5 kx static void check_requires( void )
5 kx {
5 kx pid_t p = (pid_t) -1;
5 kx int rc;
5 kx
5 kx int len = 0;
5 kx char *cmd = NULL;
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "%s/check-requires --root=%s %s > /dev/null 2>&1",
5 kx selfdir, root, pkglog_fname );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot check required packages for '%s-%s' package", pkgname, pkgver );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx
5 kx free( cmd );
5 kx
5 kx if( rc != 0 )
5 kx {
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nPackage requires other packages to be installed.\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nPackage '%s-%s' requires other packages to be installed.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nPackage '%s-%s' requires other packages to be installed.\n\n", pkgname, pkgver );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( rc );
5 kx }
5 kx }
5 kx
5 kx /********************************************************
5 kx Read .FILELIST and .RESTORELINKS functions used for
5 kx roolback in case postinstall errors:
5 kx */
5 kx static int __cmp_list_items( const void *a, const void *b )
5 kx {
5 kx if( a && b )
5 kx return strcmp( (const char *)a, (const char *)b );
5 kx else if( a )
5 kx return 1;
5 kx else
5 kx return -1;
5 kx }
5 kx
5 kx static void __free_list( void *data, void *user_data )
5 kx {
5 kx if( data ) { free( data ); }
5 kx }
5 kx
5 kx static void free_list( struct dlist *list )
5 kx {
5 kx if( list ) { dlist_free( list, __free_list ); }
5 kx }
5 kx
5 kx ////////////////////////////////////////////////////
5 kx //static void __print_list( void *data, void *user_data )
5 kx //{
5 kx // int *counter = (int *)user_data;
5 kx //
5 kx // if( counter ) { fprintf( stdout, "item[%.5d]: %s\n", *counter, (char *)data ); ++(*counter); }
5 kx // else { fprintf( stdout, "item: %s\n", (char *)data ); }
5 kx //}
5 kx //
5 kx //static void print_list( struct dlist *list )
5 kx //{
5 kx // int cnt = 0;
5 kx // if( list ) { dlist_foreach( list, __print_list, (void *)&cnt ); }
5 kx //}
5 kx ////////////////////////////////////////////////////
5 kx
5 kx static void read_filelist( void )
5 kx {
5 kx struct stat st;
5 kx FILE *fp = NULL;
5 kx
5 kx char *ln = NULL;
5 kx char *line = NULL, *tmp = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx (void)sprintf( &tmp[0], "%s/.FILELIST", tmpdir );
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx if( (stat( (const char *)&tmp[0], &st ) == -1) )
5 kx {
5 kx FATAL_ERROR( "Cannot get .FILELIST from '%s' file", basename( (char *)pkg_fname ) );
5 kx }
5 kx
5 kx fp = fopen( (const char *)&tmp[0], "r" );
5 kx if( !fp )
5 kx {
5 kx FATAL_ERROR( "Cannot open .FILELIST file" );
5 kx }
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)line, PATH_MAX );
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, fp )) )
5 kx {
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( *(ln + strlen(ln) - 1) == '/' )
5 kx {
5 kx *(ln + strlen(ln) - 1) = '\0';
5 kx (void)sprintf( &tmp[0], "%s%s", (const char *)root, (const char *)ln );
5 kx dirs = dlist_append( dirs, xstrdup( (const char *)&tmp[0] ) );
5 kx }
5 kx else
5 kx {
5 kx (void)sprintf( &tmp[0], "%s%s", (const char *)root, (const char *)ln );
5 kx files = dlist_append( files, xstrdup( (const char *)&tmp[0] ) );
5 kx }
5 kx
5 kx } /* End of while( file list entry ) */
5 kx
5 kx fclose( fp );
5 kx
5 kx free( line );
5 kx free( tmp );
5 kx }
5 kx
5 kx static void read_restorelinks( void )
5 kx {
5 kx struct stat st;
5 kx FILE *fp = NULL;
5 kx
5 kx char *ln = NULL;
5 kx char *line = NULL, *tmp = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx (void)sprintf( &tmp[0], "%s/.RESTORELINKS", tmpdir );
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx if( (stat( (const char *)&tmp[0], &st ) == -1) || (st.st_size < 8) )
5 kx {
5 kx free( tmp );
5 kx return;
5 kx }
5 kx
5 kx fp = fopen( (const char *)&tmp[0], "r" );
5 kx if( !fp )
5 kx {
5 kx FATAL_ERROR( "Cannot open .RESTORELINKS file" );
5 kx }
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)line, PATH_MAX );
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, fp )) )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx skip_eol_spaces( ln ); /* remove spaces at end-of-line */
5 kx
5 kx if( (match = strstr( ln, "; rm -rf " )) )
5 kx {
5 kx char *q = NULL;
5 kx char *p = strstr( ln, "cd" ) + 2;
5 kx char *f = strstr( ln, "; rm -rf" ) + 8;
5 kx
5 kx if( !p || !f ) continue;
5 kx
5 kx while( (*p == ' ' || *p == '\t') && *p != '\0' ) ++p;
5 kx while( (*f == ' ' || *f == '\t') && *f != '\0' ) ++f;
5 kx
5 kx q = p; while( *q != ' ' && *q != '\t' && *q != ';' && *q != '\0' ) ++q; *q = '\0';
5 kx q = f; while( *q != ' ' && *q != '\t' && *q != ';' && *q != '\0' ) ++q; *q = '\0';
5 kx
5 kx if( p && f )
5 kx {
5 kx (void)sprintf( &tmp[0], "%s%s/%s", (const char *)root, p, f );
5 kx links = dlist_append( links, xstrdup( (const char *)&tmp[0] ) );
5 kx }
5 kx }
5 kx } /* End of while( restore links entry ) */
5 kx
5 kx fclose( fp );
5 kx
5 kx free( line );
5 kx free( tmp );
5 kx }
5 kx
5 kx /*
5 kx End of read .FILELIST and .RESTORELINKS functions.
5 kx ********************************************************/
5 kx
5 kx /********************************************************
5 kx Rollback functions:
5 kx */
5 kx static void __remove_link( void *data, void *user_data )
5 kx {
5 kx const char *fname = (const char *)data;
5 kx
5 kx if( fname )
5 kx {
5 kx (void)unlink( fname );
5 kx }
5 kx }
5 kx
5 kx static void __remove_file( void *data, void *user_data )
5 kx {
5 kx const char *fname = (const char *)data;
5 kx
5 kx if( fname )
5 kx {
5 kx char *p = rindex( fname, '.' );
5 kx /*
5 kx Если .new файл остался с тем же именем, это значит что до инсталляции
5 kx в системе существовал такой же файл но без расширения .new и при этом
5 kx он отличался от нового. В данном случае надо удалять только файл .new.
5 kx
5 kx Если же файл .new не существует, то надо удалять такой же файл но без
5 kx расширения .new .
5 kx */
5 kx if( p && !strncmp( (const char *)p, ".new", 4 ) )
5 kx {
5 kx struct stat st;
5 kx
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx if( (stat( fname, &st ) == -1) ) *p = '\0';
5 kx }
5 kx
5 kx (void)unlink( fname );
5 kx }
5 kx }
5 kx
5 kx static int is_dir_empty( const char *dirpath )
5 kx {
5 kx int ret = 0;
5 kx
5 kx DIR *dir;
5 kx char *path;
5 kx size_t len;
5 kx
5 kx struct stat path_sb, entry_sb;
5 kx struct dirent *entry;
5 kx
5 kx if( stat( dirpath, &path_sb ) == -1 ) return ret; /* stat returns error code; errno is set */
5 kx if( S_ISDIR(path_sb.st_mode) == 0 ) return ret; /* dirpath is not a directory */
5 kx if( (dir = opendir(dirpath) ) == NULL ) return ret; /* Cannot open direcroty; errno is set */
5 kx
5 kx ret = 1;
5 kx
5 kx len = strlen( dirpath );
5 kx while( (entry = readdir( dir )) != NULL)
5 kx {
5 kx /* skip entries '.' and '..' */
5 kx if( ! strcmp( entry->d_name, "." ) || ! strcmp( entry->d_name, ".." ) ) continue;
5 kx
5 kx /* determinate a full name of an entry */
5 kx path = alloca( len + strlen( entry->d_name ) + 2 );
5 kx strcpy( path, dirpath );
5 kx strcat( path, "/" );
5 kx strcat( path, entry->d_name );
5 kx
5 kx if( stat( path, &entry_sb ) == 0 )
5 kx {
5 kx ret = 0;
5 kx break;
5 kx }
5 kx /* else { stat() returns error code; errno is set; and we have to continue the loop } */
5 kx }
5 kx closedir( dir );
5 kx
5 kx return ret;
5 kx }
5 kx
5 kx static void __remove_dir( void *data, void *user_data )
5 kx {
5 kx const char *dname = (const char *)data;
5 kx
5 kx if( dname && is_dir_empty( (const char *)dname ) )
5 kx {
5 kx (void)rmdir( dname );
5 kx }
5 kx }
5 kx
5 kx static void rollback( void )
5 kx {
5 kx /* Try to change CWD to the ROOT directory: */
5 kx (void)chdir( (const char *)root );
5 kx
5 kx if( links ) { dlist_foreach( links, __remove_link, NULL ); }
5 kx
5 kx if( files ) { dlist_foreach( files, __remove_file, NULL ); }
5 kx
5 kx if( dirs )
5 kx {
5 kx dirs = dlist_sort( dirs, __cmp_list_items );
5 kx dirs = dlist_reverse( dirs );
5 kx dlist_foreach( dirs, __remove_dir, NULL );
5 kx }
5 kx
5 kx /* Try to remove PKGLOG file */
5 kx {
5 kx char *tmp = NULL;
5 kx
5 kx tmp = (char *)malloc( PATH_MAX );
5 kx if( tmp )
5 kx {
5 kx const char *fname = basename( (char *)pkglog_fname );
5 kx
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx if( group )
5 kx (void)sprintf( &tmp[0], "%s/%s/%s", pkgs_path, group, fname );
5 kx else
5 kx (void)sprintf( &tmp[0], "%s/%s", pkgs_path, fname );
5 kx
5 kx (void)unlink( (const char *)&tmp[0] );
5 kx
5 kx if( group )
5 kx {
5 kx const char *dir = (const char *)dirname( (char *)&tmp[0] );
5 kx if( is_dir_empty( dir ) )
5 kx {
5 kx (void)rmdir( dir );
5 kx }
5 kx }
5 kx free( tmp );
5 kx }
5 kx }
5 kx
5 kx /* Try to change CWD to the CURRENT directory: */
5 kx (void)chdir( (const char *)curdir );
5 kx }
5 kx /*
5 kx End of rollback functions.
5 kx ********************************************************/
5 kx
5 kx static void read_description( void )
5 kx {
5 kx struct stat st;
5 kx FILE *fp = NULL;
5 kx
5 kx char *buf = NULL, *tmp = NULL;
5 kx char *lp = NULL;
5 kx int n = 0;
5 kx
5 kx char *ln = NULL;
5 kx char *line = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx buf = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !buf ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)buf, PATH_MAX );
5 kx
5 kx (void)sprintf( &tmp[0], "%s/.DESCRIPTION", tmpdir );
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx if( (stat( (const char *)&tmp[0], &st ) == -1) || (st.st_size < 8) )
5 kx {
5 kx free( tmp );
5 kx return;
5 kx }
5 kx
5 kx fp = fopen( (const char *)&tmp[0], "r" );
5 kx if( !fp )
5 kx {
5 kx FATAL_ERROR( "Cannot open .DESCRIPTION file" );
5 kx }
5 kx
5 kx (void)sprintf( (char *)&buf[0], "%s:", pkgname );
5 kx
5 kx line = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !line ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)line, PATH_MAX );
5 kx
5 kx lp = (char *)&tmp[0];
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx (void)sprintf( (char *)&tmp[0], "\n" );
5 kx ++lp;
5 kx
5 kx while( (ln = fgets( line, PATH_MAX, fp )) && n < DESCRIPTION_NUMBER_OF_LINES )
5 kx {
5 kx char *match = NULL;
5 kx
5 kx ln[strlen(ln) - 1] = '\0'; /* replace new-line symbol */
5 kx
5 kx if( (match = strstr( (const char *)ln, (const char *)buf )) && match == ln ) /* at start of line only */
5 kx {
5 kx int mlen = strlen( match ), plen = strlen( buf );
5 kx int length = ( mlen > plen ) ? (mlen - plen - 1) : 0 ;
5 kx
5 kx if( length > DESCRIPTION_LENGTH_OF_LINE )
5 kx {
5 kx /* WARNING( "Package DESCRIPTION contains lines with length greater than %d characters", DESCRIPTION_LENGTH_OF_LINE ); */
5 kx match[plen + 1 + DESCRIPTION_LENGTH_OF_LINE] = '\0'; /* truncating description line */
5 kx skip_eol_spaces( match ); /* remove spaces at end-of-line */
5 kx }
5 kx
5 kx match += plen + 1;
5 kx if( match[0] != '\0' ) { (void)sprintf( lp, " %s\n", match ); lp += strlen( match ) + 2; }
5 kx else { (void)sprintf( lp, "\n" ); ++lp; }
5 kx ++n;
5 kx }
5 kx } /* End of while( ln = fgets() ) */
5 kx
5 kx fclose( fp );
5 kx
5 kx (void)sprintf( lp, " Uncompressed Size: %s\n", uncompressed_size );
5 kx lp += strlen( uncompressed_size ) + 21;
5 kx (void)sprintf( lp, " Compressed Size: %s\n", compressed_size );
5 kx lp += strlen( compressed_size ) + 21;
5 kx
5 kx description = xstrdup( (const char *)&tmp[0] );
5 kx
5 kx free( buf );
5 kx free( line );
5 kx free( tmp );
5 kx }
5 kx
5 kx static int ask_for_install( void )
5 kx {
5 kx int ret = 0; /* continue installation */
5 kx #if defined( HAVE_DIALOG )
5 kx /******************************************************
5 kx Ask for install dialog shown only in MENUDIALOG mode
5 kx when priority != REQUIRED or --always-ask=yes:
5 kx */
5 kx if( (install_mode == MENUDIALOG) && (((priority == REQUIRED) && ask) || (priority != REQUIRED)) )
5 kx {
5 kx ret = ask_install_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx description, 18, 0, 0 );
5 kx }
5 kx
5 kx if( ret )
5 kx {
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nInstallation terminated by user.\n", 5, 0, 0 );
5 kx }
5 kx #endif
5 kx return ret;
5 kx }
5 kx
5 kx
5 kx static void show_install_progress( void )
5 kx {
5 kx fprintf( stdout, "\033[2J" ); /* clear screen */
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx description, 16, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\n Install: %s-%s [%s]...\n", pkgname, pkgver, strprio( priority, 0 ));
5 kx /*************************************************
5 kx Ruler: 68 characters + 2 spaces left and right:
5 kx
5 kx | ----handy-ruler----------------------------------------------------- | */
5 kx fprintf( stdout, "|======================================================================|\n" );
5 kx fprintf( stdout, "%s\n", description );
5 kx fprintf( stdout, "|======================================================================|\n\n" );
5 kx fprintf( stdout, "\n\n\n" ); /* 3 lines up for final message */
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\n Install: %s-%s [%s]...\n", pkgname, pkgver, strprio( priority, 0 ));
5 kx /*************************************************
5 kx Ruler: 68 characters + 2 spaces left and right:
5 kx
5 kx | ----handy-ruler----------------------------------------------------- | */
5 kx fprintf( stdout, "|======================================================================|\n" );
5 kx fprintf( stdout, "%s\n", description );
5 kx fprintf( stdout, "|======================================================================|\n\n" );
5 kx fprintf( stdout, "\n\n\n" ); /* 3 lines up for final message */
5 kx }
5 kx }
5 kx
5 kx
5 kx static void pre_install_routine( void )
5 kx {
5 kx pid_t p = (pid_t) -1;
5 kx int rc;
5 kx
5 kx int len = 0;
5 kx char *cmd = NULL;
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "cd %s && %s/.INSTALL pre_install %s > /dev/null 2>&1",
5 kx root, tmpdir, pkgver );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot run pre-install script for '%s-%s' package", pkgname, pkgver );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx
5 kx free( cmd );
5 kx
5 kx if( rc != 0 )
5 kx {
5 kx exit_status = 43;
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\n\\Z1Pre-install script returned error status.\\Zn\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nPre-install script of '%s-%s' returned error status.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nPre-install script of '%s-%s' returned error status.\n\n", pkgname, pkgver );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( exit_status );
5 kx }
5 kx }
5 kx
7 kx static int __nstreams( void )
7 kx {
7 kx int ret = 1;
7 kx int nprocs = get_nprocs();
7 kx
7 kx if( nprocs > 4 )
7 kx {
7 kx ret = nprocs / 2;
7 kx }
7 kx
7 kx return ret;
7 kx }
7 kx
5 kx static const char *fill_decompressor( char *buffer, char compressor )
5 kx {
5 kx switch( compressor )
5 kx {
5 kx case 'J':
7 kx (void)sprintf( buffer, "xz --threads=%d -dc", __nstreams() );
5 kx break;
5 kx case 'j':
5 kx (void)sprintf( buffer, "bzip2 -dc" );
5 kx break;
5 kx case 'z':
5 kx (void)sprintf( buffer, "gzip -dc" );
5 kx break;
5 kx default:
5 kx (void)sprintf( buffer, "cat -" );
5 kx break;
5 kx }
5 kx return (const char *)buffer;
5 kx }
5 kx
5 kx static void uncompress_package( void )
5 kx {
7 kx pid_t p = (pid_t) -1;
7 kx int rc = EXIT_SUCCESS;
5 kx
5 kx int len = 0;
5 kx char *cmd = NULL;
5 kx
5 kx char decompressor[64];
5 kx
5 kx (void)fill_decompressor( (char *)&decompressor[0], uncompress );
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "cat %s | %s | tar -C %s "
5 kx "--exclude='.DESCRIPTION' "
5 kx "--exclude='.FILELIST' "
5 kx "--exclude='.INSTALL' "
5 kx "--exclude='.PKGINFO' "
5 kx "--exclude='.REQUIRES' "
5 kx "--exclude='.RESTORELINKS' "
5 kx "-xf - > /dev/null 2>&1",
5 kx pkg_fname, decompressor, root );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot uncompress '%s-%s' package", pkgname, pkgver );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx
5 kx free( cmd );
5 kx
5 kx if( rc != 0 )
5 kx {
5 kx exit_status = 44;
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\n\\Z1Cannot uncompress package.\\Zn\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nCannot uncompress '%s-%s' package.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nCannot uncompress '%s-%s' package.\n\n", pkgname, pkgver );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( exit_status );
5 kx }
5 kx }
5 kx
5 kx static void restore_links( void )
5 kx {
5 kx struct stat st;
5 kx pid_t p = (pid_t) -1;
5 kx int rc;
5 kx
5 kx int len = 0;
5 kx char *cmd = NULL;
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx (void)sprintf( &cmd[0], "%s/.RESTORELINKS", tmpdir );
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx if( (stat( (const char *)&cmd[0], &st ) == -1) || (st.st_size < 8) )
5 kx {
5 kx free( cmd );
5 kx return;
5 kx }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "cd %s && sh %s/.RESTORELINKS > /dev/null 2>&1",
5 kx root, tmpdir );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot restore links for '%s-%s' package", pkgname, pkgver );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx
5 kx free( cmd );
5 kx
5 kx if( rc != 0 )
5 kx {
5 kx rollback();
5 kx
5 kx exit_status = 45;
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\n\\Z1Restore-links script returned error status.\\Zn\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nRestore-links script of '%s-%s' returned error status.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nRestore-links script of '%s-%s' returned error status.\n\n", pkgname, pkgver );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( exit_status );
5 kx }
5 kx }
5 kx
5 kx static void post_install_routine( void )
5 kx {
5 kx pid_t p = (pid_t) -1;
5 kx int rc;
5 kx
5 kx int len = 0;
5 kx char *cmd = NULL;
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "cd %s && %s/.INSTALL post_install %s > /dev/null 2>&1",
5 kx root, tmpdir, pkgver );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot run post-install script for '%s-%s' package", pkgname, pkgver );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx
5 kx free( cmd );
5 kx
5 kx if( rc != 0 )
5 kx {
5 kx rollback();
5 kx
5 kx exit_status = 46;
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\n\\Z1Post-install script returned error status.\\Zn\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nPost-install script of '%s-%s' returned error status.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nPost-install script of '%s-%s' returned error status.\n\n", pkgname, pkgver );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( exit_status );
5 kx }
5 kx }
5 kx
5 kx static void finalize_installation( void )
5 kx {
5 kx pid_t p = (pid_t) -1;
5 kx int rc;
5 kx
5 kx int len = 0;
5 kx char *cmd = NULL, *tmp = NULL;
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx if( group )
5 kx (void)sprintf( &tmp[0], "%s/%s/", pkgs_path, group );
5 kx else
5 kx (void)sprintf( &tmp[0], "%s/", pkgs_path );
5 kx
5 kx if( _mkdir_p( tmp, S_IRWXU | S_IRWXG | S_IRWXO ) != 0 )
5 kx {
5 kx FATAL_ERROR( "Cannot access '/%s' directory", PACKAGES_PATH );
5 kx }
5 kx
5 kx /****************************************
5 kx Store PKGLOG file into Setup Database:
5 kx */
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "cp %s %s > /dev/null 2>&1",
5 kx pkglog_fname, (const char *)&tmp[0] );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot store '%s' pkglog file", basename( (char *)pkglog_fname ) );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx if( rc != 0 )
5 kx {
5 kx rollback();
5 kx
5 kx free( cmd );
5 kx free( tmp );
5 kx
5 kx exit_status = 47;
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\n\\Z1Cannot store PKGLOG file into Setup Database.\\Zn\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nCannot store '%s' pkglog file into Setup Database.\n\n", basename( (char *)pkglog_fname ) );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nCannot store '%s' pkglog file into Setup Database.\n\n", basename( (char *)pkglog_fname ) );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( exit_status );
5 kx }
5 kx
5 kx /*********************************************
5 kx Increment references in the Setup Database:
5 kx */
7 kx if( !disable_chrefs )
5 kx {
7 kx if( group )
7 kx len = snprintf( &cmd[0], PATH_MAX,
7 kx "%s/chrefs --operation=inc --destination=%s %s/%s > /dev/null 2>&1",
7 kx selfdir, pkgs_path, group, basename( (char *)pkglog_fname ) );
7 kx else
7 kx len = snprintf( &cmd[0], PATH_MAX,
7 kx "%s/chrefs --operation=inc --destination=%s %s > /dev/null 2>&1",
7 kx selfdir, pkgs_path, basename( (char *)pkglog_fname ) );
7 kx if( len == 0 || len == PATH_MAX - 1 )
7 kx {
7 kx FATAL_ERROR( "Cannot increment '%s-%s' package references", pkgname, pkgver );
7 kx }
7 kx p = sys_exec_command( cmd );
7 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx
7 kx free( cmd );
5 kx
7 kx if( (rc != 0) && !ignore_chrefs_errors )
7 kx {
7 kx free( tmp );
5 kx
7 kx rollback();
5 kx
7 kx exit_status = 48;
5 kx
7 kx if( install_mode != CONSOLE )
7 kx {
5 kx #if defined( HAVE_DIALOG )
7 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
7 kx "\n\\Z1Cannot increment package references in Setup Database.\\Zn\n", 5, 0, 0 );
5 kx #else
7 kx fprintf( stdout, "\nCannot increment '%s-%s' package references in Setup Database.\n\n", pkgname, pkgver );
5 kx #endif
7 kx }
7 kx else
7 kx {
7 kx fprintf( stdout, "\nCannot increment '%s-%s' package references in Setup Database.\n\n", pkgname, pkgver );
7 kx }
7 kx
7 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
7 kx free_resources();
7 kx exit( exit_status );
5 kx }
5 kx }
5 kx
5 kx /*************************************************
5 kx Remove backup PKGLOG file from removed-packages
5 kx directory if exists:
5 kx */
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx {
5 kx const char *fname = basename( (char *)pkglog_fname );
5 kx
5 kx if( group )
5 kx (void)sprintf( &tmp[0], "%s/%s/%s", rempkgs_path, group, fname );
5 kx else
5 kx (void)sprintf( &tmp[0], "%s/%s", rempkgs_path, fname );
5 kx
5 kx (void)unlink( (const char *)&tmp[0] );
5 kx
5 kx if( group )
5 kx {
5 kx const char *dir = (const char *)dirname( (char *)&tmp[0] );
5 kx if( is_dir_empty( dir ) )
5 kx {
5 kx (void)rmdir( dir );
5 kx }
5 kx }
5 kx }
5 kx
5 kx free( tmp );
5 kx }
5 kx
5 kx #if defined( HAVE_GPG2 )
5 kx static void verify_gpg_signature( void )
5 kx {
5 kx struct stat st;
5 kx pid_t p = (pid_t) -1;
5 kx int rc;
5 kx
5 kx int len = 0;
5 kx char *cmd = NULL;
5 kx
5 kx bzero( (void *)&st, sizeof( struct stat ) );
5 kx
5 kx /******************************************************************
5 kx Do not try to verify signature if '.asc' file is not accessible:
5 kx */
5 kx if( stat( (const char *)asc_fname, &st ) == -1 ) return;
5 kx
5 kx cmd = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !cmd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cmd, PATH_MAX );
5 kx
5 kx len = snprintf( &cmd[0], PATH_MAX,
5 kx "gpg2 --verify %s %s > /dev/null 2>&1",
5 kx asc_fname, pkg_fname );
5 kx if( len == 0 || len == PATH_MAX - 1 )
5 kx {
5 kx FATAL_ERROR( "Cannot verify GPG2 signature of '%s-%s' package", pkgname, pkgver );
5 kx }
5 kx p = sys_exec_command( cmd );
5 kx rc = sys_wait_command( p, (char *)NULL, PATH_MAX );
5 kx
5 kx free( cmd );
5 kx
5 kx if( rc != 0 )
5 kx {
5 kx exit_status = 51;
5 kx
5 kx if( install_mode != CONSOLE )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\n\\Z1Cannot verify GPG2 signature of the package.\\Zn\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nGPG2 signature verification of '%s-%s' package returned error status.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx fprintf( stdout, "\nGPG2 signature verification of '%s-%s' package returned error status.\n\n", pkgname, pkgver );
5 kx }
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( exit_status );
5 kx }
5 kx }
5 kx #endif
5 kx
5 kx
5 kx static void dialogrc( void )
5 kx {
5 kx struct stat st;
5 kx char *tmp = NULL;
5 kx
5 kx tmp = (char *)malloc( (size_t)PATH_MAX );
5 kx if( !tmp ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)tmp, PATH_MAX );
5 kx
5 kx /* imagine that the utility is in /sbin directory: */
5 kx (void)sprintf( &tmp[0], "%s/../usr/share/%s/.dialogrc", selfdir, PACKAGE_NAME );
5 kx if( stat( (const char *)&tmp[0], &st ) == -1 )
5 kx {
5 kx /* finaly assume that /usr/sbin is a sbindir: */
5 kx (void)sprintf( &tmp[0], "%s/../../usr/share/%s/.dialogrc", selfdir, PACKAGE_NAME );
5 kx }
5 kx
5 kx setenv( "DIALOGRC", (const char *)&tmp[0], 1 );
5 kx
5 kx free( tmp );
5 kx }
5 kx
5 kx static char *get_curdir( void )
5 kx {
5 kx char *cwd = NULL;
5 kx
5 kx cwd = (char *)malloc( PATH_MAX );
5 kx if( !cwd ) { FATAL_ERROR( "Cannot allocate memory" ); }
5 kx bzero( (void *)cwd, PATH_MAX );
5 kx
5 kx if( getcwd( cwd, (size_t)PATH_MAX ) != NULL )
5 kx {
5 kx char *p = NULL;
5 kx remove_trailing_slash( cwd );
5 kx p = xstrdup( (const char *)cwd );
5 kx free( cwd );
5 kx return p;
5 kx }
5 kx else
5 kx {
5 kx FATAL_ERROR( "Cannot get absolute path to current directory" );
5 kx }
5 kx
5 kx return (char *)NULL;
5 kx }
5 kx
5 kx
5 kx /*********************************************
5 kx Get directory where this program is placed:
5 kx */
5 kx char *get_selfdir( void )
5 kx {
5 kx char *buf = NULL;
5 kx ssize_t len;
5 kx
5 kx buf = (char *)malloc( PATH_MAX );
5 kx if( !buf )
5 kx {
5 kx FATAL_ERROR( "Cannot allocate memory" );
5 kx }
5 kx
5 kx bzero( (void *)buf, PATH_MAX );
5 kx len = readlink( "/proc/self/exe", buf, (size_t)PATH_MAX );
5 kx if( len > 0 && len < PATH_MAX )
5 kx {
5 kx char *p = xstrdup( (const char *)dirname( buf ) );
5 kx free( buf );
5 kx return p;
5 kx }
5 kx FATAL_ERROR( "Cannot determine self directory. Please mount /proc filesystem" );
5 kx }
5 kx
5 kx void set_stack_size( void )
5 kx {
5 kx const rlim_t stack_size = 16 * 1024 * 1024; /* min stack size = 16 MB */
5 kx struct rlimit rl;
5 kx int ret;
5 kx
5 kx ret = getrlimit( RLIMIT_STACK, &rl );
5 kx if( ret == 0 )
5 kx {
5 kx if( rl.rlim_cur < stack_size )
5 kx {
5 kx rl.rlim_cur = stack_size;
5 kx ret = setrlimit( RLIMIT_STACK, &rl );
5 kx if( ret != 0 )
5 kx {
5 kx fprintf(stderr, "setrlimit returned result = %d\n", ret);
5 kx FATAL_ERROR( "Cannot set stack size" );
5 kx }
5 kx }
5 kx }
5 kx }
5 kx
5 kx
5 kx int main( int argc, char *argv[] )
5 kx {
5 kx gid_t gid;
5 kx
5 kx set_signal_handlers();
5 kx
5 kx gid = getgid();
5 kx setgroups( 1, &gid );
5 kx
5 kx fatal_error_hook = fatal_error_actions;
5 kx
5 kx selfdir = get_selfdir();
5 kx curdir = get_curdir();
5 kx dialogrc();
5 kx
5 kx errlog = stderr;
5 kx
5 kx program = basename( argv[0] );
5 kx get_args( argc, argv );
5 kx
5 kx /* set_stack_size(); */
5 kx
5 kx tmpdir = _mk_tmpdir();
5 kx if( !tmpdir )
5 kx {
5 kx FATAL_ERROR( "Cannot create temporary directory" );
5 kx }
5 kx
5 kx
5 kx /************************************************************
5 kx Getting Service Files, reading pkginfo, preserving pkglog:
5 kx */
5 kx read_service_files();
5 kx
5 kx /****************************************************
5 kx Checking whether the package is already installed:
5 kx */
5 kx check_package();
5 kx
5 kx if( rqck ) check_requires();
5 kx #if defined( HAVE_GPG2 )
5 kx if( gpgck ) verify_gpg_signature();
5 kx #endif
5 kx
5 kx read_filelist();
5 kx read_restorelinks();
5 kx
5 kx read_description();
5 kx
5 kx if( ask_for_install() )
5 kx {
5 kx /* Terminate installation: */
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx exit( exit_status );
5 kx }
5 kx
5 kx show_install_progress();
5 kx
5 kx /*************
5 kx DO INSTALL:
5 kx */
5 kx pre_install_routine();
5 kx uncompress_package();
5 kx restore_links();
5 kx post_install_routine();
5 kx finalize_installation();
5 kx
5 kx fprintf( stdout, "\033[3A" ); /* move cursor up 3 lines */
5 kx
5 kx if( (install_mode != CONSOLE) && (install_mode == MENUDIALOG) )
5 kx {
5 kx #if defined( HAVE_DIALOG )
5 kx info_pkg_box( "Install:", pkgname, pkgver, strprio( priority, 0 ),
5 kx "\nPackage has been installed.\n", 5, 0, 0 );
5 kx #else
5 kx fprintf( stdout, "\nPackage '%s-%s' has been installed.\n\n", pkgname, pkgver );
5 kx #endif
5 kx }
5 kx else
5 kx {
5 kx if( (install_mode != INFODIALOG) )
5 kx {
5 kx fprintf( stdout, "\nPackage '%s-%s' has been installed.\n\n", pkgname, pkgver );
5 kx }
5 kx }
5 kx
5 kx setup_log( "Package '%s-%s' has been installed", pkgname, pkgver );
5 kx
5 kx if( tmpdir ) { _rm_tmpdir( (const char *)tmpdir ); free( tmpdir ); }
5 kx free_resources();
5 kx
5 kx exit( exit_status );
5 kx }