gopkg.in/openshift/source-to-image.v1@v1.2.0/hack/windows/sigintwrap/sigintwrap.c (about)

     1  // sigintwrap: wrapper for non-Cygwin executables, capturing Cygwin SIGINTs and
     2  // forwarding them as a CTRL+BREAK events to the non-Cygwin executable. After
     3  // "Solution For Handling Signals In Non-Cygwin Apps With
     4  // SetConsoleCtrlHandler", Anthony DeRosa,
     5  // http://marc.info/?l=cygwin&m=111047278517873
     6  
     7  
     8  #include <sys/cygwin.h>
     9  #include <pthread.h>
    10  #include <signal.h>
    11  #include <stdio.h>
    12  #include <unistd.h>
    13  #include <windows.h>
    14  
    15  
    16  static PROCESS_INFORMATION pi;
    17  
    18  
    19  static void *
    20  wait_for_process(void *ptr) {
    21    WaitForSingleObject(pi.hProcess, INFINITE);
    22    return NULL;
    23  }
    24  
    25  
    26  static void
    27  sigint(int signal) {
    28    GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pi.dwProcessId);
    29  }
    30  
    31  
    32  static int
    33  needs_path_conversion(const char *s) {
    34    // See winsup/cygwin/environ.cc.
    35    return !(strncmp(s, "HOME=", 5) &&
    36             strncmp(s, "LD_LIBRARY_PATH=", 16) &&
    37             strncmp(s, "PATH=", 5) &&
    38             strncmp(s, "TEMP=", 5) &&
    39             strncmp(s, "TMP=", 4) &&
    40             strncmp(s, "TMPDIR=", 7));
    41  }
    42  
    43  
    44  static char *
    45  prepare_env() {
    46    char **p;
    47  
    48    int len = 1;
    49    for(p = environ; *p; p++)
    50      if(needs_path_conversion(*p)) {
    51        char *eq = strchr(*p, '=');
    52        len += eq - *p + 1;
    53        len += cygwin_conv_path_list(CCP_POSIX_TO_WIN_A, eq + 1, NULL, 0);
    54      } else
    55        len += strlen(*p) + 1;
    56  
    57    char *env = (char *)malloc(len);
    58    char *e = env;
    59    for(p = environ; *p; p++)
    60      if(needs_path_conversion(*p)) {
    61        char *eq = strchr(*p, '=');
    62        e = stpncpy(e, *p, eq - *p + 1);
    63        cygwin_conv_path_list(CCP_POSIX_TO_WIN_A, eq + 1, e, env + len - e - 1);
    64        while(*e++);
    65      } else
    66        e = stpcpy(e, *p) + 1;
    67    *e = '\0';
    68  
    69    return env;
    70  }
    71  
    72  
    73  int
    74  main(int argc, char **argv) {
    75    if(argc != 2) {
    76      fprintf(stderr, "usage: %s 'c:\\path\\to\\command.exe [arg...]'\n",
    77              argv[0]);
    78      return 1;
    79    }
    80  
    81    STARTUPINFO si;
    82    ZeroMemory(&si, sizeof(si));
    83    si.cb = sizeof(si);
    84  
    85    char *env = prepare_env();
    86  
    87    if(!CreateProcess(NULL, argv[1], NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP,
    88                      env, NULL, &si, &pi)) {
    89      LPTSTR msg;
    90      FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
    91                    FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0,
    92                    (LPTSTR)&msg, 0, NULL);
    93      fputs(msg, stderr);
    94      LocalFree(msg);
    95      free(env);
    96      return 1;
    97    }
    98  
    99    free(env);
   100  
   101    signal(SIGINT, sigint);
   102  
   103    // We call WaitForSingleObject on another thread because it cannot be
   104    // interrupted by cygwin signals.  pthread_join can be.
   105    pthread_t thread;
   106    pthread_create(&thread, NULL, wait_for_process, NULL);
   107    pthread_join(thread, NULL);
   108  
   109    DWORD exitcode;
   110    GetExitCodeProcess(pi.hProcess, &exitcode);
   111  
   112    CloseHandle(pi.hProcess);
   113    CloseHandle(pi.hThread);
   114  
   115    return exitcode;
   116  }