/************************************************************************/ /* Copyright (C) 2004 Michael C. Shultz */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or (at*/ /* your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA */ /* 02111-1307, USA. */ /* */ /* Michael C. Shultz */ /* ringworm@inbox.lv */ /* Box 3238 Landers, CA 92285 */ /************************************************************************/ #include <pmupgrade.h> int upgrade( void ); void catch_SIGINT( int ); MGsDb config_db; char config_db_file[] = DATADIR"configure.db"; int main( ) { int errorCode = 0; int skip = 0; /****************************************************************/ /* cycle upgrade routine until it returns a "2", meaning there */ /* is nothing left to process, or possibly an error */ /****************************************************************/ while( 1 == 1 ) { if( skip == 0 ) { skip = 1; MGmDbArray( config_db, config_db_file, "r" ); } if( ( errorCode = upgrade() ) != 2 ) { break; } } if( errorCode ) { fprintf( stdout, "portmanager info: All ports up to date\n"); MGmDbArrayFree( config_db ); return( 1 ); } exit( 0 ); } /********************************************************************************/ /* upgrade routine */ /********************************************************************************/ int upgrade( void ) { MGsDb port_dependencies; MGsDb ports_installed; MGsDb ports_old; char cacheFile[] = DATADIR PORTS_CACHE_DB; char id[] = "pmupgrade"; char* command = 0; char* options; int IDX_config = 0; int IDX_port_dependencies = 0; int IDX_ports_installed = 0; int IDX_ports_old = 0; int IDX_ports_old_2 = 0; int errorCode = 0; int parentOK = 0; int skip = 0; /*********************************************************************************/ /* use comand /usr/local/bin/pmStatus to build ports_installed.db port_dependencies.db and ports_old.db */ /*********************************************************************************/ errorCode = system( "pmStatus" ); if( !MGrIfFileExist( cacheFile ) ) { /* if here then the cache is reset, try 1 more time */ errorCode = system( "pmStatus" ); } if( errorCode != 0 ) { fprintf( stderr, "%s %s error: pmStatus returned an error, cannot continue\n", id, ver ); fflush( stderr ); exit(1); /* return( 1 ); */ } /*********************************** MGmDbArray: a = dbase structure name b = dbase file name string c = open mode string ************************************/ MGmDbArray( ports_old, DATADIR PORTS_OLD_DB, "r" ); if( errno ) { /* fprintf( stderr, "%s %s error: MGmDbArray returned with an error\n", id, ver ); */ return( 1 ); } MGmDbArray( ports_installed, DATADIR PORTS_INSTALLED_DB, "r" ); if( errno ) { fprintf( stderr, "%s %s error: MGmDbArray returned with an error\n", id, ver ); return( 1 ); } MGmDbArray( port_dependencies, DATADIR PORT_DEPENDENCIES_DB, "r" ); if( errno ) { fprintf( stderr, "%s %s error: MGmDbArray returned with an error\n", id, ver ); return( 1 ); } /****************************************************************************************/ /* find the priority port to upgrade */ /****************************************************************************************/ /* Need a major overhaul here, change to work something like: ports_old.db contains ports to be updated each record gets a serries of checks, if skip = 1 then no update if 0 then update resons to set skip to 1 dependency port name not in ports_installed.db a. dependency never installed b. Xorg/XFree86 conflict dependency port name in ports_old.db a. dependency needs to be upgraded first */ /****************************************************************************************/ /* IDX_ports_old = Out of date rocord index */ /* port_dependencies.recordQty = dependent port data base record quantity */ /* a) port_dependencies is a MGsDb structure, see libMG/src/libMG.h */ /****************************************************************************************/ IDX_ports_old = 0; while( IDX_ports_old < ports_old.recordQty ) { skip = 0; /* ok to upgrade */ IDX_port_dependencies = 0; /* loop while dependecy ports index ptr is less than qty of dependency ports records */ while( IDX_port_dependencies < port_dependencies.recordQty ) { /* if dependency port record matches an out of date ports record then... */ if( !( strcmp( port_dependencies.array[IDX_port_dependencies][0], ports_old.array[IDX_ports_old][1] ) ) ) { IDX_ports_old_2 = 0; /* see if dependency port is to be upgraded */ /* loop through out of date port records */ while( IDX_ports_old_2 < ports_old.recordQty ) { /* dependency port needs to be upgraded first before out of date port */ if( !( strcmp( port_dependencies.array[IDX_port_dependencies][2], ports_old.array[IDX_ports_old_2][0] ) ) ) { fprintf( stderr, "->SKIP upgrading %s \n->reason: until %s is upgraded\n", ports_old.array[IDX_ports_old][1], ports_old.array[IDX_ports_old_2][1] ); fflush( stderr ); skip = 1; } /************************************/ /* print any parent not in ports_installed.db */ /************************************/ IDX_ports_installed = 0; parentOK = 0; while( IDX_ports_installed < ports_installed.recordQty ) { if( !( strcmp( port_dependencies.array[IDX_port_dependencies][1], ports_installed.array[IDX_ports_installed][0] ) ) ) { parentOK = 1; } IDX_ports_installed++; } if( parentOK == 0 ) { fprintf( stderr, "info: port %s built with OLD dependancy %s\n", ports_old.array[IDX_ports_old_2][0], port_dependencies.array[IDX_port_dependencies][1] ); fflush( stderr ); } IDX_ports_old_2++; } } IDX_port_dependencies++; } if( skip == 0 ) { /* system( "clear" ); */ fprintf( stderr, "------------------------------------------------\n" ); fprintf( stderr, "OK TO UPGRADE %s\n", ports_old.array[IDX_ports_old][1] ); fprintf( stderr, "%s %s upgrading: %s. Executing command:\n", id, ver, ports_old.array[IDX_ports_old][1] ); while( fflush( stderr ) ); /************************************************************************/ /* Command "1" " make clean " */ /************************************************************************/ IDX_config = 0; options = (char*)malloc(1); options[0] = 0; while(IDX_config < config_db.recordQty) { if( strnstr( ports_old.array[IDX_ports_old][0], config_db.array[IDX_config][0], strlen(ports_old.array[IDX_ports_old][0]) ) != NULL ) { free( options ); options = (char*)malloc(strlen(config_db.array[IDX_config][1])+1); strncpy( options, config_db.array[IDX_config][1], strlen(config_db.array[IDX_config][1])+1 ); break; } IDX_config++; } command = (char*)malloc( strlen( "cd " ) + strlen(PORTSDIR) + strlen(ports_old.array[IDX_ports_old][0]) + strlen( "; make clean " ) + strlen(options) + 1 ); strncpy( command, "cd ", strlen( "cd " ) + 1 ); strncat( command, PORTSDIR, strlen(PORTSDIR) + 1 ); strncat( command, ports_old.array[IDX_ports_old][0], strlen(ports_old.array[IDX_ports_old][0]) + 1 ); strncat( command, "; make clean ", strlen( "; make clean " ) + 1); strncat( command, options, strlen(options) + 1); fprintf( stdout, "%s\n", command ); fprintf( stderr, "------------------------------------------------\n" ); errorCode = system(command); if( errorCode != 0 ) { fprintf( stderr, "%s %s error: make clean returned an error, cannot continue\n", id, ver ); fflush( stderr ); exit(1); /* return( 1 ); */ } free( command ); if( errorCode != 0 ) { return( 1 ); } /************************************************************************/ /* Command "2" " make " */ /************************************************************************/ command = (char*)malloc( strlen( "cd " ) + strlen(PORTSDIR) + strlen(ports_old.array[IDX_ports_old][0]) + strlen( "; make " ) + strlen(options) + 1 ); strncpy( command, "cd ", strlen( "cd " ) + 1 ); strncat( command, PORTSDIR, strlen(PORTSDIR) + 1 ); strncat( command, ports_old.array[IDX_ports_old][0], strlen(ports_old.array[IDX_ports_old][0]) + 1 ); strncat( command, "; make ", strlen( "; make " ) + 1); strncat( command, options, strlen(options) + 1); fprintf( stdout, "%s\n", command ); errorCode = system(command); /* Now here an error would indeed cause problems!!! An abort is a really good idea... */ if( errorCode != 0 ) { fprintf( stderr, "%s %s error: make returned an error, cannot continue\n", id, ver ); fflush( stderr ); exit(1); /* return( 1 ); */ } free( command ); if( errorCode != 0 ) { return( 1 ); } /************************************************************************/ /* Command "3" " pkg_create -b " */ /************************************************************************/ command = ( char* )malloc( strlen( "( cd /tmp; pkg_create -b " ) + strlen( ports_old.array[IDX_ports_old][1] ) + 3 ); strncpy( command, "( cd /tmp; pkg_create -b ", strlen("( cd /tmp; pkg_create -b ") + 1 ); strncat( command, ports_old.array[IDX_ports_old][1], strlen(ports_old.array[IDX_ports_old][1]) + 1 ); strncat( command, " )", 3 ); fprintf( stderr, "------------------------------------------------\n" ); fprintf( stderr, " backing up installed port before removing it \n" ); fprintf( stderr, "%s %s command: #3 %s\n", id, ver, command ); fprintf( stderr, "------------------------------------------------\n" ); fflush( stderr ); errorCode = system(command); /* An error here is no big deal, if for example the port is not installed it will not be able to have a backup package made for it. */ /* if( errorCode != 0 ) { fprintf( stderr, "%s %s error: pkg_create returned an error, cannot continue\n", id, ver ); fflush( stderr ); return( 1 ); } */ free( command ); fprintf( stderr, "------------------------------------------------\n" ); /************************************************************************/ /* Command "4" " make deinstall " */ /************************************************************************/ command = (char*)malloc( strlen( "cd " ) + strlen(PORTSDIR) + strlen(ports_old.array[IDX_ports_old][0]) + strlen( "; make deinstall " ) + strlen(options) + 1 ); strncpy( command, "cd ", strlen( "cd " ) + 1 ); strncat( command, PORTSDIR, strlen(PORTSDIR) + 1 ); strncat( command, ports_old.array[IDX_ports_old][0], strlen(ports_old.array[IDX_ports_old][0]) + 1 ); strncat( command, "; make deinstall ", strlen( "; make deinstall " ) + 1); strncat( command, options, strlen(options) + 1); fprintf( stdout, "%s\n", command ); errorCode = system(command); /* If deinstall has started, even with an error it is better to continue and try to install the new port */ /* if( errorCode != 0 ) { fprintf( stderr, "%s %s error: make deinstall returned an error, cannot continue\n", id, ver ); fflush( stderr ); return( 1 ); } */ free( command ); fprintf( stderr, "------------------------------------------------\n" ); /************************************************************************/ /* Command "5" " make reinstall " */ /************************************************************************/ command = (char*)malloc( strlen( "cd " ) + strlen(PORTSDIR) + strlen(ports_old.array[IDX_ports_old][0]) + strlen( "; make reinstall " ) + strlen(options) + 1 ); strncpy( command, "cd ", strlen( "cd " ) + 1 ); strncat( command, PORTSDIR, strlen(PORTSDIR) + 1 ); strncat( command, ports_old.array[IDX_ports_old][0], strlen(ports_old.array[IDX_ports_old][0]) + 1 ); strncat( command, "; make reinstall ", strlen( "; make reinstall " ) + 1); strncat( command, options, strlen(options) + 1); fprintf( stdout, "%s\n", command ); errorCode = system(command); /* probably good idea to abort if an error during reinstall, leave this in for now.... */ if( errorCode != 0 ) { fprintf( stderr, "%s %s error: make reinstall returned an error, cannot continue\n", id, ver ); fflush( stderr ); exit(1); /* return( 1 ); */ } free( command ); if( errorCode != 0 ) { command = ( char* )malloc( strlen( "( pkg_add /tmp/.tgz )" ) + strlen( ports_old.array[IDX_ports_old][1] ) + 1 ); strcpy( command, "( pkg_add -f /tmp/" ); strcat( command, ports_old.array[IDX_ports_old][1] ); strcat( command, ".tgz )" ); fprintf( stderr, "------------------------------------------------\n" ); fprintf( stderr, " restoring original port from backup \n" ); fprintf( stderr, "%s %s command: #5!! ***Emergancy restore*** %s\n", id, ver, command ); fprintf( stderr, "------------------------------------------------\n" ); fflush( stderr ); errorCode = system(command); if( errorCode != 0 ) { fprintf( stderr, "%s %s error: FAILED TO RESTORE BACKUP COPY, really sorry ! cannot continue\n", id, ver ); fflush( stderr ); exit(1); /* return( 1 ); */ } free( command ); fprintf( stderr, "------------------------------------------------\n" ); fprintf( stderr, " aborting upgrade due to port install failure, \n" ); fprintf( stderr, " try again after port error is corrected \n" ); fprintf( stderr, "------------------------------------------------\n" ); fflush( stderr ); return( 1 ); } else { command = ( char* )malloc( strlen( "( cd /tmp; rm -f .tgz )" ) + strlen( ports_old.array[IDX_ports_old][1] ) + 1 ); strcpy( command, "( cd /tmp; rm -f " ); strcat( command, ports_old.array[IDX_ports_old][1] ); strcat( command, ".tgz )" ); fprintf( stderr, "---------------------------------------------------------------\n" ); fprintf( stderr, " deleting backup copy, installation of updated port successful \n" ); fprintf( stderr, "%s %s command: #6 %s\n", id, ver, command ); fprintf( stderr, "---------------------------------------------------------------\n" ); fflush( stderr ); errorCode = system(command); /* error is no big deal here, if the backup package wasn't made it can't be deleted... */ /* if( errorCode != 0 ) { fprintf( stderr, "%s %s error: deleting backup copy returned an error, cannot continue\n", id, ver ); fflush( stderr ); return( 1 ); } */ free( command ); } fprintf( stderr, "---------------------------------------------------------------\n" ); /************************************************************************/ /* Command "7" " make package " */ /************************************************************************/ command = (char*)malloc( strlen( "cd " ) + strlen(PORTSDIR) + strlen(ports_old.array[IDX_ports_old][0]) + strlen( "; make package " ) + strlen(options) + 1 ); strncpy( command, "cd ", strlen( "cd " ) + 1 ); strncat( command, PORTSDIR, strlen(PORTSDIR) + 1 ); strncat( command, ports_old.array[IDX_ports_old][0], strlen(ports_old.array[IDX_ports_old][0]) + 1 ); strncat( command, "; make package ", strlen( "; make package " ) + 1); strncat( command, options, strlen(options) + 1); fprintf( stdout, "%s\n", command ); errorCode = system(command); /* some ports cannot be made into packages, want to ignore errors here... */ /* if( errorCode != 0 ) { fprintf( stderr, "%s %s error: make package returned an error, cannot continue\n", id, ver ); fflush( stderr ); return( 1 ); } */ free( command ); fprintf( stderr, "---------------------------------------------------------------\n" ); /************************************************************************/ /* Command "8" " make clean " */ /************************************************************************/ command = (char*)malloc( strlen( "cd " ) + strlen(PORTSDIR) + strlen(ports_old.array[IDX_ports_old][0]) + strlen( "; make clean " ) + strlen(options) + 1 ); strncpy( command, "cd ", strlen( "cd " ) + 1 ); strncat( command, PORTSDIR, strlen(PORTSDIR) + 1 ); strncat( command, ports_old.array[IDX_ports_old][0], strlen(ports_old.array[IDX_ports_old][0]) + 1 ); strncat( command, "; make clean ", strlen( "; make clean " ) + 1); strncat( command, options, strlen(options) + 1); fprintf( stdout, "%s\n", command ); errorCode = system(command); /* an abort if we can't clean??? I don't think it is a good idea, may reconsider this later... */ /* if( errorCode != 0 ) { fprintf( stderr, "%s %s error: make clean returned an error, cannot continue\n", id, ver ); fflush( stderr ); return( 1 ); } */ free( command ); return( 2 ); } IDX_ports_old++; } /*.............................................*/ /* check each port before upgrading for: 1 a parent listed in ports_old 1.1 skip current port 2 a parent not listed in ports_installed.db 2.1 add unlisted parent to ports_old 2.2 skip current port note on #2, there is a problem where if a parent port was never installed, pmUpgrade cycles. Need to check and see if a parent's directory is listed in ports_installed.db. If it is not there, that port needs to be freshly installed. I am holding off on this until a pmAdd routine is written, for now, when cycling occurs, just manually add the parent port. See pmUpgrade(1) DIAGNOSTICS section for more details. */ /*.............................................*/ MGmDbArrayFree( ports_installed ); MGmDbArrayFree( port_dependencies ); MGmDbArrayFree( ports_old ); fprintf( stderr, "pmUpgrade complete, all ports upgraded!\n" ); fflush( stderr ); return( 0 ); } /******************/ /* signal handler */ /******************/ /* this doesn't seem to be working, maybe we need to fork the make commands? */ void catch_SIGINT( int signalID ) { sigset_t mask_set; /* used to set a signal masking set. */ sigset_t old_set; /* used to store the old mask set. */ pid_t my_pid = getpid(); /* re-set the signal handler again to catch_SIGSEGV, for next time */ signal( SIGINT, catch_SIGINT ); /* mask any further signals while we're inside the handler. */ sigfillset(&mask_set); sigprocmask(SIG_SETMASK, &mask_set, &old_set); if( signalID == SIGINT ) { /* re-set the signal handler again to catch_int, for next time */ signal(SIGINT, catch_SIGINT); printf("exiting pmupdate <ctl-c pressed>\n"); fflush(stdout); kill(my_pid, SIGSTOP); } }