Merge branch 'bw/forking-and-threading'
authorJunio C Hamano <gitster@pobox.com>
Tue, 30 May 2017 02:16:41 +0000 (11:16 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 30 May 2017 02:16:41 +0000 (11:16 +0900)
The "run-command" API implementation has been made more robust
against dead-locking in a threaded environment.

* bw/forking-and-threading:
usage.c: drop set_error_handle()
run-command: restrict PATH search to executable files
run-command: expose is_executable function
run-command: block signals between fork and execve
run-command: add note about forking and threading
run-command: handle dup2 and close errors in child
run-command: eliminate calls to error handling functions in child
run-command: don't die in child when duping /dev/null
run-command: prepare child environment before forking
string-list: add string_list_remove function
run-command: use the async-signal-safe execv instead of execvp
run-command: prepare command before forking
t0061: run_command executes scripts without a #! line
t5550: use write_script to generate post-update hook

1  2 
git-compat-util.h
help.c
string-list.c
usage.c
diff --combined git-compat-util.h
index 98670a3c9af15cdc662ed1535a6b322e2a7b8a38,f1f2a2d73185361a1b68c8bffb6cafe5445b54cf..4b7dcf21adbe7064963cf446bde7018629ea2c10
@@@ -319,11 -319,6 +319,11 @@@ extern char *gitdirname(char *)
  #define PRIo32 "o"
  #endif
  
 +typedef uintmax_t timestamp_t;
 +#define PRItime PRIuMAX
 +#define parse_timestamp strtoumax
 +#define TIME_MAX UINTMAX_MAX
 +
  #ifndef PATH_SEP
  #define PATH_SEP ':'
  #endif
@@@ -450,7 -445,6 +450,6 @@@ extern void (*get_error_routine(void))(
  extern void set_warn_routine(void (*routine)(const char *warn, va_list params));
  extern void (*get_warn_routine(void))(const char *warn, va_list params);
  extern void set_die_is_recursing_routine(int (*routine)(void));
- extern void set_error_handle(FILE *);
  
  extern int starts_with(const char *str, const char *prefix);
  
@@@ -621,7 -615,7 +620,7 @@@ extern int git_lstat(const char *, stru
  #endif
  
  #define DEFAULT_PACKED_GIT_LIMIT \
 -      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? 8192 : 256))
 +      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? (32 * 1024L * 1024L) : 256))
  
  #ifdef NO_PREAD
  #define pread git_pread
@@@ -889,12 -883,6 +888,12 @@@ static inline size_t xsize_t(off_t len
  __attribute__((format (printf, 3, 4)))
  extern int xsnprintf(char *dst, size_t max, const char *fmt, ...);
  
 +#ifndef HOST_NAME_MAX
 +#define HOST_NAME_MAX 256
 +#endif
 +
 +extern int xgethostname(char *buf, size_t len);
 +
  /* in ctype.c, for kwset users */
  extern const unsigned char tolower_trans_tbl[256];
  
@@@ -1069,15 -1057,6 +1068,15 @@@ static inline int regexec_buf(const reg
  #define HAVE_VARIADIC_MACROS 1
  #endif
  
 +#ifdef HAVE_VARIADIC_MACROS
 +__attribute__((format (printf, 3, 4))) NORETURN
 +void BUG_fl(const char *file, int line, const char *fmt, ...);
 +#define BUG(...) BUG_fl(__FILE__, __LINE__, __VA_ARGS__)
 +#else
 +__attribute__((format (printf, 1, 2))) NORETURN
 +void BUG(const char *fmt, ...);
 +#endif
 +
  /*
   * Preserves errno, prints a message, but gives no warning for ENOENT.
   * Returns 0 on success, which includes trying to unlink an object that does
diff --combined help.c
index a07f01e6f9fc7895f27f3ee9a4a7e291ce995b0f,0c65a2d21c2c663671407a1ec1d612ce02d0a32b..db7f3d79a016881639a8c0640451afe35b011e5e
--- 1/help.c
--- 2/help.c
+++ b/help.c
@@@ -1,6 -1,7 +1,7 @@@
  #include "cache.h"
  #include "builtin.h"
  #include "exec_cmd.h"
+ #include "run-command.h"
  #include "levenshtein.h"
  #include "help.h"
  #include "common-cmds.h"
@@@ -96,48 -97,6 +97,6 @@@ static void pretty_print_cmdnames(struc
        string_list_clear(&list, 0);
  }
  
- static int is_executable(const char *name)
- {
-       struct stat st;
-       if (stat(name, &st) || /* stat, not lstat */
-           !S_ISREG(st.st_mode))
-               return 0;
- #if defined(GIT_WINDOWS_NATIVE)
-       /*
-        * On Windows there is no executable bit. The file extension
-        * indicates whether it can be run as an executable, and Git
-        * has special-handling to detect scripts and launch them
-        * through the indicated script interpreter. We test for the
-        * file extension first because virus scanners may make
-        * it quite expensive to open many files.
-        */
-       if (ends_with(name, ".exe"))
-               return S_IXUSR;
- {
-       /*
-        * Now that we know it does not have an executable extension,
-        * peek into the file instead.
-        */
-       char buf[3] = { 0 };
-       int n;
-       int fd = open(name, O_RDONLY);
-       st.st_mode &= ~S_IXUSR;
-       if (fd >= 0) {
-               n = read(fd, buf, 2);
-               if (n == 2)
-                       /* look for a she-bang */
-                       if (!strcmp(buf, "#!"))
-                               st.st_mode |= S_IXUSR;
-               close(fd);
-       }
- }
- #endif
-       return st.st_mode & S_IXUSR;
- }
  static void list_commands_in_dir(struct cmdnames *cmds,
                                         const char *path,
                                         const char *prefix)
@@@ -411,8 -370,8 +370,8 @@@ const char *help_unknown_cmd(const cha
  
        if (SIMILAR_ENOUGH(best_similarity)) {
                fprintf_ln(stderr,
 -                         Q_("\nDid you mean this?",
 -                            "\nDid you mean one of these?",
 +                         Q_("\nThe most similar command is",
 +                            "\nThe most similar commands are",
                           n));
  
                for (i = 0; i < n; i++)
diff --combined string-list.c
index 003ca1879ef560b3db0ad9e1af8022c38800b500,8f7b69ada10ef3259f4699e1ee7554a493ab8fd3..c650500c6e51d983dc45a4be3b8dad98f1dece92
@@@ -41,7 -41,10 +41,7 @@@ static int add_entry(int insert_at, str
        if (exact_match)
                return -1 - index;
  
 -      if (list->nr + 1 >= list->alloc) {
 -              list->alloc += 32;
 -              REALLOC_ARRAY(list->items, list->alloc);
 -      }
 +      ALLOC_GROW(list->items, list->nr+1, list->alloc);
        if (index < list->nr)
                memmove(list->items + index + 1, list->items + index,
                                (list->nr - index)
@@@ -64,6 -67,24 +64,24 @@@ struct string_list_item *string_list_in
        return list->items + index;
  }
  
+ void string_list_remove(struct string_list *list, const char *string,
+                       int free_util)
+ {
+       int exact_match;
+       int i = get_entry_index(list, string, &exact_match);
+       if (exact_match) {
+               if (list->strdup_strings)
+                       free(list->items[i].string);
+               if (free_util)
+                       free(list->items[i].util);
+               list->nr--;
+               memmove(list->items + i, list->items + i + 1,
+                       (list->nr - i) * sizeof(struct string_list_item));
+       }
+ }
  int string_list_has_string(const struct string_list *list, const char *string)
  {
        int exact_match;
diff --combined usage.c
index 1f63e033e99fe3325a96132bdc5b6514d951cecb,2623c078e1378819403ed1de52d2138226120ed6..2f87ca69a8299485ee013187f99ffbdb2618d7c8
+++ b/usage.c
@@@ -6,12 -6,9 +6,9 @@@
  #include "git-compat-util.h"
  #include "cache.h"
  
- static FILE *error_handle;
  void vreportf(const char *prefix, const char *err, va_list params)
  {
        char msg[4096];
-       FILE *fh = error_handle ? error_handle : stderr;
        char *p;
  
        vsnprintf(msg, sizeof(msg), err, params);
@@@ -19,7 -16,7 +16,7 @@@
                if (iscntrl(*p) && *p != '\t' && *p != '\n')
                        *p = '?';
        }
-       fprintf(fh, "%s%s\n", prefix, msg);
+       fprintf(stderr, "%s%s\n", prefix, msg);
  }
  
  static NORETURN void usage_builtin(const char *err, va_list params)
@@@ -88,11 -85,6 +85,6 @@@ void set_die_is_recursing_routine(int (
        die_is_recursing = routine;
  }
  
- void set_error_handle(FILE *fh)
- {
-       error_handle = fh;
- }
  void NORETURN usagef(const char *err, ...)
  {
        va_list params;
@@@ -201,35 -193,3 +193,35 @@@ void warning(const char *warn, ...
        warn_routine(warn, params);
        va_end(params);
  }
 +
 +static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
 +{
 +      char prefix[256];
 +
 +      /* truncation via snprintf is OK here */
 +      if (file)
 +              snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line);
 +      else
 +              snprintf(prefix, sizeof(prefix), "BUG: ");
 +
 +      vreportf(prefix, fmt, params);
 +      abort();
 +}
 +
 +#ifdef HAVE_VARIADIC_MACROS
 +NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...)
 +{
 +      va_list ap;
 +      va_start(ap, fmt);
 +      BUG_vfl(file, line, fmt, ap);
 +      va_end(ap);
 +}
 +#else
 +NORETURN void BUG(const char *fmt, ...)
 +{
 +      va_list ap;
 +      va_start(ap, fmt);
 +      BUG_vfl(NULL, 0, fmt, ap);
 +      va_end(ap);
 +}
 +#endif