Let scripts run before and after each patch, and upon successful execution of
authorRyan C. Gordon <icculus@icculus.org>
Wed, 18 May 2005 19:51:28 +0000
changeset 91 6db187bc77c7
parent 90 1b004ccf775b
child 92 879a145aa111
Let scripts run before and after each patch, and upon successful execution of all patches.
mojopatch.c
platform.h
platform_unix.c
--- a/mojopatch.c	Wed May 18 18:23:13 2005 +0000
+++ b/mojopatch.c	Wed May 18 19:51:28 2005 +0000
@@ -201,6 +201,8 @@
 static char **ignorelist = NULL;
 static int ignorecount = 0;
 
+char *patchfiledir = NULL;
+
 static unsigned int maxxdeltamem = 128;  /* in megabytes. */
 
 static unsigned char iobuf[512 * 1024];
@@ -697,7 +699,7 @@
     va_end(ap);
     buf[sizeof(buf)-1] = '\0';
 	_dlog("(xdelta call: [%s].)", buf);
-    return(spawn_xdelta(buf));
+    return(spawn_xdelta(buf) == SPAWN_RETURNGOOD);
 } /* _do_xdelta */
 
 
@@ -2147,6 +2149,35 @@
 } /* chdir_by_identifier */
 
 
+static int run_script(const char *name)
+{
+    SpawnResult rc;
+    char cwd[MAX_PATH];
+
+    if (getcwd(cwd, sizeof (cwd)) == NULL)
+        return(0);
+
+    if (patchfiledir != NULL)
+    {
+        if (chdir(patchfiledir) == -1)
+            return(0);
+    } /* if */
+
+    rc = spawn_script(name, cwd);
+
+    if (chdir(cwd) == -1)
+        return(0);
+
+    if (rc == SPAWN_FILENOTFOUND)
+        return(1);  /* "success" */
+
+    else if (rc == SPAWN_FAILED)
+        _fatal("Failed to run %s script!");
+
+    return(rc == SPAWN_RETURNGOOD);
+} /* run_script */
+
+
 static int process_patch_header(SerialArchive *ar, PatchHeader *h)
 {
     int retval = PATCHSUCCESS;
@@ -2196,7 +2227,9 @@
             else
             {
                 assert(rc == ISPATCHABLE_YES);
-                if (*h->readmefname)
+                if (!run_script("prepatch"))
+                    retval = PATCHERROR;
+                else if (*h->readmefname)
                     retval = show_and_install_readme(h->readmefname, h->readmedata);
             } /* else */
         } /* else */
@@ -2209,6 +2242,23 @@
 } /* process_patch_header */
 
 
+static char *get_real_filedir(const char *fname)
+{
+    char *ptr;
+    char *buf = (char *) alloca(strlen(fname) + 1);
+    strcpy(buf, fname);
+
+    assert(strlen(PATH_SEP) == 1);  /* need better code if this doesn't fly. */
+    ptr = strrchr(buf, (PATH_SEP)[0]);
+    if (!ptr)
+        strcpy(buf, ".");  /* current dir */
+    else
+        *ptr = '\0';  /* chop filename. */
+
+    return(get_realpath(buf));
+} /* get_real_filedir */
+
+
 static int do_patching(void)
 {
     SerialArchive ar;
@@ -2225,6 +2275,12 @@
     if (!open_serialized_archive(&ar, patchfile, 1, &do_progress, &file_size))
         return(PATCHERROR);
 
+    if ((patchfiledir = get_real_filedir(patchfile)) == NULL)
+    {
+        _fatal("internal error!");  /* !!! FIXME: better error? */
+        return(PATCHERROR);
+    } /* if */
+
     if (file_size == 0)
         do_progress = 0;  /* prevent a division by zero. */
 
@@ -2263,12 +2319,16 @@
             } /* if */
         } /* if */
 
-        if (!skip_patch)
-            installed_patches++;
-        else
+        if (skip_patch)
         {
             skipped_patches++;
             skip_patch = 0;  /* reset for next patch... */
+        } /* if */
+        else
+        {
+            installed_patches++;
+            if (!run_script("postpatch"))
+                goto do_patching_done;
         } /* else */
 
         /* !!! FIXME: This loses command line overrides! */
@@ -2285,18 +2345,28 @@
             _fatal("Your installation has not been modified.");
         else if (!quietonsuccess)
             ui_success("Patching successful!");
-    }
+    } /* if */
 
 do_patching_done:
     close_serialized_archive(&ar);
 
-    if ((retval == PATCHERROR) && (report_error))
+    if (retval == PATCHERROR)
     {
         ui_total_progress(-1);
-        _fatal("There were problems, so I'm aborting.");
-        if (!info_only())
-            _fatal("The product is possibly damaged and requires a fresh installation.");
+        if (report_error)
+        {
+            _fatal("There were problems, so I'm aborting.");
+            if (!info_only())
+                _fatal("The product is possibly damaged and requires a fresh installation.");
+        } /* if */
     } /* if */
+    else
+    {
+        run_script("patchingdone");
+    } /* else */
+
+    free(patchfiledir);
+    patchfiledir = NULL;
 
     return(retval);
 } /* do_patching */
--- a/platform.h	Wed May 18 18:23:13 2005 +0000
+++ b/platform.h	Wed May 18 19:51:28 2005 +0000
@@ -37,6 +37,14 @@
     struct MOJOPATCH_FILELIST *next;
 } file_list;
 
+typedef enum
+{
+    SPAWN_FILENOTFOUND,
+    SPAWN_FAILED,
+    SPAWN_RETURNGOOD,
+    SPAWN_RETURNBAD
+} SpawnResult;
+
 /* Your mainline calls this. */
 int mojopatch_main(int argc, char **argv);
 
@@ -57,11 +65,12 @@
 int get_file_size(const char *fname, long *fsize);
 char *get_current_dir(char *buf, size_t bufsize);
 char *get_realpath(const char *path);
-int spawn_xdelta(const char *cmdline);
 int update_version(const char *ver);
 int calc_tmp_filenames(char **tmp1, char **tmp2);
 int locate_product_by_identifier(const char *str, char *buf, size_t bufsize);
 int get_product_version(const char *ident, char *buf, size_t bufsize);
+SpawnResult spawn_xdelta(const char *cmdline);
+SpawnResult spawn_script(const char *scriptname, const char *dstdir);
 
 #ifdef __cplusplus
 }
--- a/platform_unix.c	Wed May 18 18:23:13 2005 +0000
+++ b/platform_unix.c	Wed May 18 19:51:28 2005 +0000
@@ -467,29 +467,25 @@
 } /* spawn_thread */
 
 
-int spawn_xdelta(const char *cmdline)
+static SpawnResult spawn_binary(const char *cmd)
 {
-    const char *binname = "xdelta";
-    char *cmd = alloca(strlen(cmdline) + strlen(basedir) + strlen(binname) + 5);
-    if (!cmd)
-        return(0);
-
-    sprintf(cmd, "\"%s/%s\" %s", basedir, binname, cmdline);
+    int *ptr = NULL;
+    int rc = 127;
 
 #if !USE_PTHREAD
-    int rc = 0;
     pid_t pid = fork();
     if (pid == -1)
     {
         int e = errno;
         _fatal("fork() failed: %d (%s)", e, strerror(e));
-        return(0);
+        return(SPAWN_FAILED);
     } /* if */
 
     else if (pid == 0)   /* child process. */
     {
-        rc = spawn_thread(cmd);
-        exit(1);  /* !!! FIXME    *((int *) rc) == 0 ); */
+        ptr = (int *) spawn_thread((void *) cmd);
+        if (ptr) rc = *ptr;
+        exit(rc != 0);
     } /* else if */
 
     else
@@ -499,16 +495,15 @@
             ui_pump();
             usleep(10000);
         } /* while */
-        return(1);
+        return((rc == 0) ? SPAWN_RETURNGOOD : SPAWN_RETURNBAD);
     } /* else */
 #else
     pthread_t thr;
-    void *rc;
 
     thread_alive = 1;
 
     if (pthread_create(&thr, NULL, spawn_thread, cmd) != 0)
-        return(0);
+        return(SPAWN_FAILED);
 
     while (thread_alive)
     {
@@ -516,12 +511,38 @@
         usleep(10000);
     } /* while */
 
-    pthread_join(thr, &rc);
-    return(1);  /* !!! FIXME    *((int *) rc) == 0 ); */
+    pthread_join(thr, (void **) &ptr);
+    if (ptr) rc = *ptr;
+    return((rc == 0) ? SPAWN_RETURNGOOD : SPAWN_RETURNBAD);
 #endif
+} /* spawn_binary */
+
+
+SpawnResult spawn_xdelta(const char *cmdline)
+{
+    const char *binname = "xdelta";
+    char *cmd = alloca(strlen(cmdline) + strlen(basedir) + strlen(binname) + 5);
+    if (!cmd)
+        return(SPAWN_FAILED);
+
+    sprintf(cmd, "\"%s/%s\" %s", basedir, binname, cmdline);
+    return(spawn_binary(cmd));
 } /* spawn_xdelta */
 
 
+/* you are chdir()'d to the directory with the patchfile here. */
+SpawnResult spawn_script(const char *scriptname, const char *dstdir)
+{
+    char *cmd = alloca(strlen(scriptname) + strlen(dstdir) + 32);
+
+    if (!file_exists(scriptname))
+        return(SPAWN_FILENOTFOUND);
+
+    sprintf(cmd, "./%s '%s'", scriptname, dstdir);
+    return(spawn_binary(cmd));
+} /* spawn_script */
+
+
 char *get_current_dir(char *buf, size_t bufsize)
 {
     size_t buflen = 0;