Back to index

lightning-sunbird  0.9+nobinonly
install.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "install.h"
00038 #include "install-ds.h"
00039 #include <prlock.h>
00040 #include <prio.h>
00041 #include <prmem.h>
00042 #include <prprf.h>
00043 #include <prsystem.h>
00044 #include <prproces.h>
00045 
00046 #ifdef XP_UNIX
00047 /* for chmod */
00048 #include <sys/types.h>
00049 #include <sys/stat.h>
00050 #endif
00051 
00052 /*extern "C" {*/
00053 #include <jar.h>
00054 /*}*/
00055 
00056 extern /*"C"*/
00057 int Pk11Install_AddNewModule(char* moduleName, char* dllPath,
00058                               unsigned long defaultMechanismFlags,
00059                               unsigned long cipherEnableFlags);
00060 extern /*"C"*/
00061 short Pk11Install_UserVerifyJar(JAR *jar, PRFileDesc *out,
00062        PRBool query);
00063 extern /*"C"*/
00064 const char* mySECU_ErrorString(int16);
00065 extern 
00066 int Pk11Install_yyparse();
00067 
00068 #define INSTALL_METAINFO_TAG "Pkcs11_install_script"
00069 #define SCRIPT_TEMP_FILE "pkcs11inst.tmp"
00070 #define ROOT_MARKER "%root%"
00071 #define TEMP_MARKER "%temp%"
00072 #define PRINTF_ROOT_MARKER "%%root%%"
00073 #define TEMPORARY_DIRECTORY_NAME "pk11inst.dir"
00074 #define JAR_BASE_END (JAR_BASE+100)
00075 
00076 static PRLock* errorHandlerLock=NULL;
00077 static Pk11Install_ErrorHandler errorHandler=NULL;
00078 static char* PR_Strdup(const char* str);
00079 static int rm_dash_r (char *path);
00080 static int make_dirs(char *path, int file_perms);
00081 static int dir_perms(int perms);
00082 
00083 static Pk11Install_Error DoInstall(JAR *jar, const char *installDir,
00084        const char* tempDir, Pk11Install_Platform *platform, 
00085        PRFileDesc *feedback, PRBool noverify);
00086 
00087 static char *errorString[]= {
00088        "Operation was successful", /* PK11_INSTALL_NO_ERROR */
00089        "Directory \"%s\" does not exist", /* PK11_INSTALL_DIR_DOESNT_EXIST */
00090        "File \"%s\" does not exist", /* PK11_INSTALL_FILE_DOESNT_EXIST */
00091        "File \"%s\" is not readable", /* PK11_INSTALL_FILE_NOT_READABLE */
00092        "%s",         /* PK11_INSTALL_ERROR_STRING */
00093        "Error in JAR file %s: %s",  /* PK11_INSTALL_JAR_ERROR */
00094        "No Pkcs11_install_script specified in JAR metainfo file",
00095                             /* PK11_INSTALL_NO_INSTALLER_SCRIPT */
00096        "Could not delete temporary file \"%s\"",
00097                             /*PK11_INSTALL_DELETE_TEMP_FILE */
00098        "Could not open temporary file \"%s\"", /*PK11_INSTALL_OPEN_SCRIPT_FILE*/
00099        "%s: %s", /* PK11_INSTALL_SCRIPT_PARSE */
00100        "Error in script: %s",
00101        "Unable to obtain system platform information",
00102        "Installer script has no information about the current platform (%s)",
00103        "Relative directory \"%s\" does not contain "PRINTF_ROOT_MARKER,
00104        "Module File \"%s\" not found",
00105        "Error occurred installing module \"%s\" into database",
00106        "Error extracting \"%s\" from JAR file: %s",
00107        "Directory \"%s\" is not writeable",
00108        "Could not create directory \"%s\"",
00109        "Could not remove directory \"%s\"",
00110        "Unable to execute \"%s\"",
00111        "Unable to wait for process \"%s\"",
00112        "\"%s\" returned error code %d",
00113        "User aborted operation",
00114        "Unspecified error"
00115 };
00116 
00117 enum {
00118        INSTALLED_FILE_MSG=0,
00119        INSTALLED_MODULE_MSG,
00120        INSTALLER_SCRIPT_NAME,
00121        MY_PLATFORM_IS,
00122        USING_PLATFORM,
00123        PARSED_INSTALL_SCRIPT,
00124        EXEC_FILE_MSG,
00125        EXEC_SUCCESS,
00126        INSTALLATION_COMPLETE_MSG,
00127        USER_ABORT
00128 };
00129 
00130 static char *msgStrings[] = {
00131        "Installed file %s to %s\n",
00132        "Installed module \"%s\" into module database\n",
00133        "Using installer script \"%s\"\n",
00134        "Current platform is %s\n",
00135        "Using installation parameters for platform %s\n",
00136        "Successfully parsed installation script\n",
00137        "Executing \"%s\"...\n",
00138        "\"%s\" executed successfully\n",
00139        "\nInstallation completed successfully\n",
00140        "\nAborting...\n"
00141 };
00142 
00143 /**************************************************************************
00144  * S t r i n g N o d e
00145  */
00146 typedef struct StringNode_str {
00147     char *str;
00148     struct StringNode_str* next;
00149 } StringNode;
00150 
00151 StringNode* StringNode_new()
00152 {
00153        StringNode* new_this;
00154        new_this = (StringNode*)malloc(sizeof(StringNode));
00155   new_this->str=NULL;
00156   new_this->next=NULL;
00157        return new_this;
00158 }
00159 
00160 void StringNode_delete(StringNode* s) 
00161 {
00162        if(s->str) {
00163               PR_Free(s->str);
00164               s->str=NULL;
00165        }
00166 }
00167 
00168 /*************************************************************************
00169  * S t r i n g L i s t
00170  */
00171 typedef struct StringList_str {
00172   StringNode* head;
00173        StringNode* tail;
00174 } StringList;
00175 
00176 void StringList_new(StringList* list)
00177 {
00178   list->head=NULL;
00179   list->tail=NULL;
00180 }
00181 
00182 void StringList_delete(StringList* list)
00183 {
00184        StringNode *tmp;
00185        while(list->head) {
00186               tmp = list->head;
00187               list->head = list->head->next;
00188               StringNode_delete(tmp);
00189        }
00190 }
00191 
00192 void
00193 StringList_Append(StringList* list, char* str)
00194 {
00195        if(!str) {
00196               return;
00197        }
00198 
00199        if(!list->tail) {
00200               /* This is the first element */
00201          list->head = list->tail = StringNode_new();
00202        } else {
00203               list->tail->next = StringNode_new();
00204               list->tail = list->tail->next;
00205        }
00206 
00207        list->tail->str = PR_Strdup(str);
00208        list->tail->next = NULL;    /* just to be sure */
00209 }
00210 
00211 /**************************************************************************
00212  *
00213  * P k 1 1 I n s t a l l _ S e t E r r o r H a n d l e r
00214  *
00215  * Sets the error handler to be used by the library.  Returns the current
00216  * error handler function.
00217  */
00218 Pk11Install_ErrorHandler
00219 Pk11Install_SetErrorHandler(Pk11Install_ErrorHandler handler)
00220 {
00221        Pk11Install_ErrorHandler old;
00222 
00223        if(!errorHandlerLock) {
00224               errorHandlerLock = PR_NewLock();
00225        }
00226 
00227        PR_Lock(errorHandlerLock);
00228 
00229        old = errorHandler;
00230        errorHandler = handler;
00231 
00232        PR_Unlock(errorHandlerLock);
00233 
00234        return old;
00235 }
00236 
00237 /**************************************************************************
00238  *
00239  * P k 1 1 I n s t a l l _ I n i t
00240  *
00241  * Does initialization that otherwise would be done on the fly.  Only
00242  * needs to be called by multithreaded apps, before they make any calls
00243  * to this library.
00244  */
00245 void
00246 Pk11Install_Init()
00247 {
00248        if(!errorHandlerLock) {
00249               errorHandlerLock = PR_NewLock();
00250        }
00251 }
00252 
00253 /**************************************************************************
00254  *
00255  * P k 1 1 I n s t a l l _ R e l e a s e
00256  *
00257  * Releases static data structures used by the library.  Don't use the
00258  * library after calling this, unless you call Pk11Install_Init()
00259  * first.  This function doesn't have to be called at all unless you're
00260  * really anal about freeing memory before your program exits.
00261  */
00262 void
00263 Pk11Install_Release()
00264 {
00265        if(errorHandlerLock) {
00266               PR_Free(errorHandlerLock);
00267               errorHandlerLock = NULL;
00268        }
00269 }
00270 
00271 /*************************************************************************
00272  *
00273  * e r r o r
00274  *
00275  * Takes an error code and its arguments, creates the error string,
00276  * and sends the string to the handler function if it exists.
00277  */
00278 
00279 #ifdef OSF1
00280 /* stdarg has already been pulled in from NSPR */
00281 #undef va_start
00282 #undef va_end
00283 #undef va_arg
00284 #include <varargs.h>
00285 #else
00286 #include <stdarg.h>
00287 #endif
00288 
00289 #ifdef OSF1
00290 static void
00291 error(long va_alist, ...)
00292 #else
00293 static void
00294 error(Pk11Install_Error errcode, ...)
00295 #endif
00296 {
00297 
00298        va_list ap;
00299        char *errstr;
00300        Pk11Install_ErrorHandler handler;
00301 
00302        if(!errorHandlerLock) {
00303               errorHandlerLock = PR_NewLock();
00304        }
00305 
00306        PR_Lock(errorHandlerLock);
00307 
00308        handler = errorHandler;
00309 
00310        PR_Unlock(errorHandlerLock);
00311 
00312        if(handler) {
00313 #ifdef OSF1
00314               va_start(ap);
00315               errstr = PR_vsmprintf(errorString[va_arg(ap, Pk11Install_Error)], ap);
00316 #else
00317               va_start(ap, errcode);
00318               errstr = PR_vsmprintf(errorString[errcode], ap);
00319 #endif
00320               handler(errstr);
00321               PR_smprintf_free(errstr);
00322               va_end(ap);
00323        }
00324 }
00325 
00326 /*************************************************************************
00327  *
00328  * j a r _ c a l l b a c k
00329  */
00330 static int
00331 jar_callback(int status, JAR *foo, const char *bar, char *pathname,
00332        char *errortext) {
00333        char *string;
00334 
00335        string = PR_smprintf("JAR error %d: %s in file %s\n", status, errortext,
00336               pathname);
00337        error(PK11_INSTALL_ERROR_STRING, string);
00338        PR_smprintf_free(string);
00339        return 0;
00340 }
00341        
00342 /*************************************************************************
00343  *
00344  * P k 1 1 I n s t a l l _ D o I n s t a l l
00345  *
00346  * jarFile is the path of a JAR in the PKCS #11 module JAR format.
00347  * installDir is the directory relative to which files will be
00348  *   installed.
00349  */
00350 Pk11Install_Error
00351 Pk11Install_DoInstall(char *jarFile, const char *installDir,
00352        const char *tempDir, PRFileDesc *feedback, short force, PRBool noverify)
00353 {
00354        JAR *jar;
00355        char *installer;
00356        unsigned long installer_len;
00357        int status;
00358        Pk11Install_Error ret;
00359        PRBool made_temp_file;
00360        Pk11Install_Info installInfo;
00361        Pk11Install_Platform *platform;
00362        char* errMsg;
00363        char sysname[SYS_INFO_BUFFER_LENGTH], release[SYS_INFO_BUFFER_LENGTH],
00364        arch[SYS_INFO_BUFFER_LENGTH];
00365        char *myPlatform;
00366 
00367        jar=NULL;
00368        ret = PK11_INSTALL_UNSPECIFIED;
00369        made_temp_file=PR_FALSE;
00370        errMsg=NULL;
00371        Pk11Install_Info_init(&installInfo);
00372 
00373        /*
00374        printf("Inside DoInstall, jarFile=%s, installDir=%s, tempDir=%s\n",
00375               jarFile, installDir, tempDir);
00376        */
00377 
00378        /*
00379         * Check out jarFile and installDir for validity
00380         */
00381        if( PR_Access(installDir, PR_ACCESS_EXISTS) != PR_SUCCESS ) {
00382               error(PK11_INSTALL_DIR_DOESNT_EXIST, installDir);
00383               return PK11_INSTALL_DIR_DOESNT_EXIST;
00384        }
00385        if(!tempDir) {
00386               tempDir = ".";
00387        }
00388        if( PR_Access(tempDir, PR_ACCESS_EXISTS) != PR_SUCCESS ) {
00389               error(PK11_INSTALL_DIR_DOESNT_EXIST, tempDir);
00390               return PK11_INSTALL_DIR_DOESNT_EXIST;
00391        }
00392        if( PR_Access(tempDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS ) {
00393               error(PK11_INSTALL_DIR_NOT_WRITEABLE, tempDir);
00394               return PK11_INSTALL_DIR_NOT_WRITEABLE;
00395        }
00396        if( (PR_Access(jarFile, PR_ACCESS_EXISTS) != PR_SUCCESS) ) {
00397               error(PK11_INSTALL_FILE_DOESNT_EXIST, jarFile);
00398               return PK11_INSTALL_FILE_DOESNT_EXIST;
00399        }
00400        if( PR_Access(jarFile, PR_ACCESS_READ_OK) != PR_SUCCESS ) {
00401               error(PK11_INSTALL_FILE_NOT_READABLE, jarFile);
00402               return PK11_INSTALL_FILE_NOT_READABLE;
00403        }
00404 
00405        /*
00406         * Extract the JAR file
00407         */
00408        jar = JAR_new();
00409        JAR_set_callback(JAR_CB_SIGNAL, jar, jar_callback);
00410 
00411        if(noverify) {
00412               status = JAR_pass_archive_unverified(jar, jarArchGuess, jarFile, "url");
00413        } else {
00414               status = JAR_pass_archive(jar, jarArchGuess, jarFile, "url");
00415        }
00416        if( (status < 0) || (jar->valid < 0) ) {
00417               if (status >= JAR_BASE && status <= JAR_BASE_END) {
00418                      error(PK11_INSTALL_JAR_ERROR, jarFile, JAR_get_error(status));
00419               } else {
00420                      error(PK11_INSTALL_JAR_ERROR, jarFile,
00421                        mySECU_ErrorString((int16) PORT_GetError()) );
00422               }
00423               ret=PK11_INSTALL_JAR_ERROR;
00424               goto loser;
00425        }
00426        /*printf("passed the archive\n");*/
00427 
00428        /*
00429         * Show the user security information, allow them to abort or continue
00430         */
00431        if( Pk11Install_UserVerifyJar(jar, PR_STDOUT,
00432               force?PR_FALSE:PR_TRUE) && !force) {
00433               if(feedback) {
00434                      PR_fprintf(feedback, msgStrings[USER_ABORT]);
00435               }
00436               ret=PK11_INSTALL_USER_ABORT;
00437               goto loser;
00438        }
00439 
00440        /*
00441         * Get the name of the installation file
00442         */
00443        if( JAR_get_metainfo(jar, NULL, INSTALL_METAINFO_TAG, (void**)&installer,
00444               (unsigned long*)&installer_len) ) {
00445               error(PK11_INSTALL_NO_INSTALLER_SCRIPT);
00446               ret=PK11_INSTALL_NO_INSTALLER_SCRIPT;
00447               goto loser;
00448        }
00449        if(feedback) {
00450               PR_fprintf(feedback, msgStrings[INSTALLER_SCRIPT_NAME], installer);
00451        }
00452 
00453        /*
00454         * Extract the installation file
00455         */
00456        if( PR_Access(SCRIPT_TEMP_FILE, PR_ACCESS_EXISTS) == PR_SUCCESS) {
00457               if( PR_Delete(SCRIPT_TEMP_FILE) != PR_SUCCESS) {
00458                      error(PK11_INSTALL_DELETE_TEMP_FILE, SCRIPT_TEMP_FILE);
00459                      ret=PK11_INSTALL_DELETE_TEMP_FILE;
00460                      goto loser;
00461               }
00462        }
00463        if(noverify) {
00464               status = JAR_extract(jar, installer, SCRIPT_TEMP_FILE);
00465        } else {
00466               status = JAR_verified_extract(jar, installer, SCRIPT_TEMP_FILE);
00467        }
00468        if(status) {
00469               if (status >= JAR_BASE && status <= JAR_BASE_END) {
00470                      error(PK11_INSTALL_JAR_EXTRACT, installer, JAR_get_error(status));
00471               } else {
00472                      error(PK11_INSTALL_JAR_EXTRACT, installer,
00473                        mySECU_ErrorString((int16) PORT_GetError()) );
00474               }
00475               ret = PK11_INSTALL_JAR_EXTRACT;
00476               goto loser;
00477        } else {
00478               made_temp_file = PR_TRUE;
00479        }
00480 
00481        /*
00482         * Parse the installation file into a syntax tree
00483         */
00484        Pk11Install_FD = PR_Open(SCRIPT_TEMP_FILE, PR_RDONLY, 0);
00485        if(!Pk11Install_FD) {
00486               error(PK11_INSTALL_OPEN_SCRIPT_FILE, SCRIPT_TEMP_FILE);
00487               ret=PK11_INSTALL_OPEN_SCRIPT_FILE;
00488               goto loser;
00489        }
00490        if(Pk11Install_yyparse()) {
00491               error(PK11_INSTALL_SCRIPT_PARSE, installer,
00492                      Pk11Install_yyerrstr ? Pk11Install_yyerrstr : "");
00493               ret=PK11_INSTALL_SCRIPT_PARSE;
00494               goto loser;
00495        }
00496 
00497 #if 0
00498        /* for debugging */
00499        Pk11Install_valueList->Print(0);
00500 #endif
00501 
00502        /*
00503         * From the syntax tree, build a semantic structure
00504         */
00505        errMsg = Pk11Install_Info_Generate(&installInfo,Pk11Install_valueList);
00506        if(errMsg) {
00507               error(PK11_INSTALL_SEMANTIC, errMsg);
00508               ret=PK11_INSTALL_SEMANTIC;
00509               goto loser;
00510        }
00511 #if 0
00512        installInfo.Print(0);
00513 #endif
00514 
00515        if(feedback) {
00516               PR_fprintf(feedback, msgStrings[PARSED_INSTALL_SCRIPT]);
00517        }
00518 
00519        /*
00520         * Figure out which platform to use
00521         */
00522        {
00523               sysname[0] = release[0] = arch[0] = '\0';
00524 
00525               if( (PR_GetSystemInfo(PR_SI_SYSNAME, sysname, SYS_INFO_BUFFER_LENGTH)
00526                             != PR_SUCCESS) ||
00527                   (PR_GetSystemInfo(PR_SI_RELEASE, release, SYS_INFO_BUFFER_LENGTH)
00528                             != PR_SUCCESS) ||
00529                   (PR_GetSystemInfo(PR_SI_ARCHITECTURE, arch, SYS_INFO_BUFFER_LENGTH)
00530                             != PR_SUCCESS) ) {
00531                      error(PK11_INSTALL_SYSINFO);
00532                      ret=PK11_INSTALL_SYSINFO;
00533                      goto loser;
00534               }
00535               myPlatform = PR_smprintf("%s:%s:%s", sysname, release, arch);
00536               platform = Pk11Install_Info_GetBestPlatform(&installInfo,myPlatform);
00537               if(!platform) {
00538                      error(PK11_INSTALL_NO_PLATFORM, myPlatform);
00539                      PR_smprintf_free(myPlatform);
00540                      ret=PK11_INSTALL_NO_PLATFORM;
00541                      goto loser;
00542               }
00543               if(feedback) {
00544                      PR_fprintf(feedback, msgStrings[MY_PLATFORM_IS], myPlatform);
00545                      PR_fprintf(feedback, msgStrings[USING_PLATFORM],
00546                     Pk11Install_PlatformName_GetString(&platform->name));
00547               }
00548               PR_smprintf_free(myPlatform);
00549        }
00550 
00551        /* Run the install for that platform */
00552        ret = DoInstall(jar, installDir, tempDir, platform, feedback, noverify);
00553        if(ret) {
00554               goto loser;
00555        }
00556 
00557        ret = PK11_INSTALL_SUCCESS;
00558 loser:
00559        if(Pk11Install_valueList) {
00560               Pk11Install_ValueList_delete(Pk11Install_valueList);
00561               PR_Free(Pk11Install_valueList);
00562               Pk11Install_valueList = NULL;
00563        }
00564        if(jar) {
00565               JAR_destroy(jar);
00566        }
00567        if(made_temp_file) {
00568               PR_Delete(SCRIPT_TEMP_FILE);
00569        }
00570        if(errMsg) {
00571               PR_smprintf_free(errMsg);
00572        }
00573        return ret;
00574 }
00575 
00576 /*
00578 // actually run the installation, copying files to and fro
00579 */
00580 static Pk11Install_Error
00581 DoInstall(JAR *jar, const char *installDir, const char *tempDir,
00582        Pk11Install_Platform *platform, PRFileDesc *feedback, PRBool noverify)
00583 {
00584        Pk11Install_File *file;
00585        Pk11Install_Error ret;
00586        char *reldir;
00587        char *dest;
00588        char *modDest;
00589        char *cp;
00590        int i;
00591        int status;
00592        char *tempname, *temp;
00593        StringList executables;
00594        StringNode *execNode;
00595        PRProcessAttr *attr;
00596        PRProcess *proc;
00597        char *argv[2];
00598        char *envp[1];
00599        int errcode;
00600 
00601        ret=PK11_INSTALL_UNSPECIFIED;
00602        reldir=NULL;
00603        dest=NULL;
00604        modDest=NULL;
00605        tempname=NULL;
00606 
00607        StringList_new(&executables);
00608        /*
00609        // Create Temporary directory
00610        */
00611        tempname = PR_smprintf("%s/%s", tempDir, TEMPORARY_DIRECTORY_NAME);
00612        if( PR_Access(tempname, PR_ACCESS_EXISTS)==PR_SUCCESS ) {
00613               /* Left over from previous run?  Delete it. */
00614               rm_dash_r(tempname);
00615        }
00616        if(PR_MkDir(tempname, 0700) != PR_SUCCESS) {
00617               error(PK11_INSTALL_CREATE_DIR, tempname);
00618               ret = PK11_INSTALL_CREATE_DIR;
00619               goto loser;
00620        }
00621 
00622        /*
00623        // Install all the files
00624        */
00625        for(i=0; i < platform->numFiles; i++) {
00626               file = &platform->files[i];
00627 
00628               if(file->relativePath) {
00629                      PRBool foundMarker = PR_FALSE;
00630                      reldir = PR_Strdup(file->relativePath);
00631 
00632                      /* Replace all the markers with the directories for which they stand */
00633                      while(1) {
00634                             if( (cp=PL_strcasestr(reldir, ROOT_MARKER)) ) {
00635                                    /* Has a %root% marker  */
00636                                    *cp = '\0';
00637                                    temp = PR_smprintf("%s%s%s", reldir, installDir,
00638                                           cp+strlen(ROOT_MARKER));
00639                                    PR_Free(reldir);
00640                                    reldir = temp;
00641                                    foundMarker = PR_TRUE;
00642                             } else if( (cp = PL_strcasestr(reldir, TEMP_MARKER)) ) {
00643                                    /* Has a %temp% marker */
00644                                    *cp = '\0';
00645                                    temp = PR_smprintf("%s%s%s", reldir, tempname, 
00646                                           cp+strlen(TEMP_MARKER));
00647                                    PR_Free(reldir);
00648                                    reldir = temp;
00649                                    foundMarker = PR_TRUE;
00650                             } else {
00651                                    break;
00652                             }
00653                      }
00654                      if(!foundMarker) {
00655                             /* Has no markers...this isn't really a relative directory */
00656                             error(PK11_INSTALL_BOGUS_REL_DIR, file->relativePath);
00657                             ret = PK11_INSTALL_BOGUS_REL_DIR;
00658                             goto loser;
00659                      }
00660                      dest = reldir;
00661                      reldir = NULL;
00662               } else if(file->absolutePath) {
00663                      dest = PR_Strdup(file->absolutePath);
00664               }
00665 
00666               /* Remember if this is the module file, we'll need to add it later */
00667               if(i == platform->modFile) {
00668                      modDest = PR_Strdup(dest);
00669               }
00670 
00671               /* Remember is this is an executable, we'll need to run it later */
00672               if(file->executable) {
00673                      StringList_Append(&executables,dest);
00674                      /*executables.Append(dest);*/
00675               }
00676 
00677               /* Make sure the directory we are targetting exists */
00678               if( make_dirs(dest, file->permissions) ) {
00679                      ret=PK11_INSTALL_CREATE_DIR;
00680                      goto loser;
00681               }
00682 
00683               /* Actually extract the file onto the filesystem */
00684               if(noverify) {
00685                      status = JAR_extract(jar, (char*)file->jarPath, dest);
00686               } else {
00687                      status = JAR_verified_extract(jar, (char*)file->jarPath, dest);
00688               }
00689               if(status) {
00690                      if (status >= JAR_BASE && status <= JAR_BASE_END) {
00691                             error(PK11_INSTALL_JAR_EXTRACT, file->jarPath,
00692                   JAR_get_error(status));
00693                      } else {
00694                             error(PK11_INSTALL_JAR_EXTRACT, file->jarPath,
00695                               mySECU_ErrorString((int16) PORT_GetError()) );
00696                      }
00697                      ret=PK11_INSTALL_JAR_EXTRACT;
00698                      goto loser;
00699               }
00700               if(feedback) {
00701                      PR_fprintf(feedback, msgStrings[INSTALLED_FILE_MSG],
00702                             file->jarPath, dest);
00703               }
00704 
00705               /* no NSPR command to change permissions? */
00706 #ifdef XP_UNIX
00707               chmod(dest, file->permissions);
00708 #endif
00709 
00710               /* Memory clean-up tasks */
00711               if(reldir) {
00712                      PR_Free(reldir);
00713                      reldir = NULL;
00714               }
00715               if(dest) {
00716                      PR_Free(dest);
00717                      dest = NULL;
00718               }
00719        }
00720        /* Make sure we found the module file */
00721        if(!modDest) {
00722               /* Internal problem here, since every platform is supposed to have
00723                  a module file */
00724               error(PK11_INSTALL_NO_MOD_FILE, platform->moduleName);
00725               ret=PK11_INSTALL_NO_MOD_FILE;
00726               goto loser;
00727        }
00728 
00729        /*
00730        // Execute any executable files
00731        */
00732        {
00733               argv[1] = NULL;
00734               envp[0] = NULL;
00735               for(execNode = executables.head; execNode; execNode = execNode->next) {
00736                      attr = PR_NewProcessAttr();
00737                      argv[0] = PR_Strdup(execNode->str);
00738 
00739                      /* Announce our intentions */
00740                      if(feedback) {
00741                             PR_fprintf(feedback, msgStrings[EXEC_FILE_MSG], execNode->str);
00742                      }
00743 
00744                      /* start the process */
00745                      if( !(proc=PR_CreateProcess(execNode->str, argv, envp, attr)) ) {
00746                             PR_Free(argv[0]);
00747                             PR_DestroyProcessAttr(attr);
00748                             error(PK11_INSTALL_EXEC_FILE, execNode->str);
00749                             ret=PK11_INSTALL_EXEC_FILE;
00750                             goto loser;
00751                      }
00752 
00753                      /* wait for it to finish */
00754                      if( PR_WaitProcess(proc, &errcode) != PR_SUCCESS) {
00755                             PR_Free(argv[0]);
00756                             PR_DestroyProcessAttr(attr);
00757                             error(PK11_INSTALL_WAIT_PROCESS, execNode->str);
00758                             ret=PK11_INSTALL_WAIT_PROCESS;
00759                             goto loser;
00760                      }
00761 
00762                      /* What happened? */
00763                      if(errcode) {
00764                             /* process returned an error */
00765                             error(PK11_INSTALL_PROC_ERROR, execNode->str, errcode);
00766                      } else if(feedback) {
00767                             /* process ran successfully */
00768                             PR_fprintf(feedback, msgStrings[EXEC_SUCCESS], execNode->str);
00769                      }
00770 
00771                      PR_Free(argv[0]);
00772                      PR_DestroyProcessAttr(attr);
00773               }
00774        }
00775 
00776        /*
00777        // Add the module
00778        */
00779        status = Pk11Install_AddNewModule((char*)platform->moduleName,
00780               (char*)modDest, platform->mechFlags, platform->cipherFlags );
00781 
00782        if(status != SECSuccess) {
00783               error(PK11_INSTALL_ADD_MODULE, platform->moduleName);
00784               ret=PK11_INSTALL_ADD_MODULE;
00785               goto loser;
00786        }
00787        if(feedback) {
00788               PR_fprintf(feedback, msgStrings[INSTALLED_MODULE_MSG],
00789                      platform->moduleName);
00790        }
00791 
00792        if(feedback) {
00793               PR_fprintf(feedback, msgStrings[INSTALLATION_COMPLETE_MSG]);
00794        }
00795 
00796        ret = PK11_INSTALL_SUCCESS;
00797 
00798 loser:
00799        if(reldir) {
00800               PR_Free(reldir);
00801        }
00802        if(dest) {
00803               PR_Free(dest);
00804        }
00805        if(modDest) {
00806               PR_Free(modDest);
00807        }
00808        if(tempname) {
00809               PRFileInfo info;
00810               if(PR_GetFileInfo(tempname, &info) == PR_SUCCESS) {
00811                      if((info.type == PR_FILE_DIRECTORY)) {
00812                             /* Recursively remove temporary directory */
00813                             if(rm_dash_r(tempname)) {
00814                                    error(PK11_INSTALL_REMOVE_DIR,
00815                                           tempname);
00816                                    ret=PK11_INSTALL_REMOVE_DIR;
00817                             }
00818                                    
00819                      }
00820               }
00821               PR_Free(tempname);
00822        }
00823        StringList_delete(&executables);
00824        return ret;
00825 }
00826 
00827 /*
00829 */
00830 static char*
00831 PR_Strdup(const char* str)
00832 {
00833        char *tmp = (char*) PR_Malloc(strlen(str)+1);
00834        strcpy(tmp, str);
00835        return tmp;
00836 }
00837 
00838 /*
00839  *  r m _ d a s h _ r
00840  *
00841  *  Remove a file, or a directory recursively.
00842  *
00843  */
00844 static int
00845 rm_dash_r (char *path)
00846 {
00847     PRDir   *dir;
00848     PRDirEntry *entry;
00849     PRFileInfo fileinfo;
00850     char filename[240];
00851 
00852     if(PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) {
00853         /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/
00854         return -1;
00855     }
00856     if(fileinfo.type == PR_FILE_DIRECTORY) {
00857 
00858         dir = PR_OpenDir(path);
00859         if(!dir) {
00860             return -1;
00861         }
00862 
00863         /* Recursively delete all entries in the directory */
00864         while((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
00865             sprintf(filename, "%s/%s", path, entry->name);
00866             if(rm_dash_r(filename)) return -1;
00867         }
00868 
00869         if(PR_CloseDir(dir) != PR_SUCCESS) {
00870             return -1;
00871         }
00872 
00873         /* Delete the directory itself */
00874         if(PR_RmDir(path) != PR_SUCCESS) {
00875             return -1;
00876         }
00877     } else {
00878         if(PR_Delete(path) != PR_SUCCESS) {
00879             return -1;
00880         }
00881     }
00882     return 0;
00883 }
00884 
00885 /***************************************************************************
00886  *
00887  * m a k e _ d i r s
00888  *
00889  * Ensure that the directory portion of the path exists.  This may require
00890  * making the directory, and its parent, and its parent's parent, etc.
00891  */
00892 static int
00893 make_dirs(char *path, int file_perms)
00894 {
00895        char *Path;
00896        char *start;
00897        char *sep;
00898        int ret = 0;
00899        PRFileInfo info;
00900 
00901        if(!path) {
00902               return 0;
00903        }
00904 
00905        Path = PR_Strdup(path);
00906        start = strpbrk(Path, "/\\");
00907        if(!start) {
00908               return 0;
00909        }
00910        start++; /* start right after first slash */
00911 
00912        /* Each time through the loop add one more directory. */
00913        while( (sep=strpbrk(start, "/\\")) ) {
00914               *sep = '\0';
00915 
00916               if( PR_GetFileInfo(Path, &info) != PR_SUCCESS) {
00917                      /* No such dir, we have to create it */
00918                      if( PR_MkDir(Path, dir_perms(file_perms)) != PR_SUCCESS) {
00919                             error(PK11_INSTALL_CREATE_DIR, Path);
00920                             ret = PK11_INSTALL_CREATE_DIR;
00921                             goto loser;
00922                      }
00923               } else {
00924                      /* something exists by this name, make sure it's a directory */
00925                      if( info.type != PR_FILE_DIRECTORY ) {
00926                             error(PK11_INSTALL_CREATE_DIR, Path);
00927                             ret = PK11_INSTALL_CREATE_DIR;
00928                             goto loser;
00929                      }
00930               }
00931 
00932               /* If this is the lowest directory level, make sure it is writeable */
00933               if(!strpbrk(sep+1, "/\\")) {
00934                      if( PR_Access(Path, PR_ACCESS_WRITE_OK)!=PR_SUCCESS) {
00935                             error(PK11_INSTALL_DIR_NOT_WRITEABLE, Path);
00936                             ret = PK11_INSTALL_DIR_NOT_WRITEABLE;
00937                             goto loser;
00938                      }
00939               }
00940 
00941               start = sep+1; /* start after the next slash */
00942               *sep = '/';
00943        }
00944 
00945 loser:
00946        PR_Free(Path);
00947        return ret;
00948 }
00949 
00950 /*************************************************************************
00951  * d i r _ p e r m s
00952  * 
00953  * Guesses the desired permissions on a directory based on the permissions
00954  * of a file that will be stored in it. Give read, write, and
00955  * execute to the owner (so we can create the file), read and 
00956  * execute to anyone who has read permissions on the file, and write
00957  * to anyone who has write permissions on the file.
00958  */
00959 static int
00960 dir_perms(int perms)
00961 {
00962        int ret = 0;
00963 
00964        /* owner */
00965        ret |= 0700;
00966 
00967        /* group */
00968        if(perms & 0040) {
00969               /* read on the file -> read and execute on the directory */
00970               ret |= 0050;
00971        }
00972        if(perms & 0020) {
00973               /* write on the file -> write on the directory */
00974               ret |= 0020;
00975        }
00976 
00977        /* others */
00978        if(perms & 0004) {
00979               /* read on the file -> read and execute on the directory */
00980               ret |= 0005;
00981        }
00982        if(perms & 0002) {
00983               /* write on the file -> write on the directory */
00984               ret |= 0002;
00985        }
00986 
00987        return ret;
00988 }