LCOV - code coverage report
Current view: top level - ccache - execute.c (source / functions) Hit Total Coverage
Test: ccache.lcov.info Lines: 42 58 72.4 %
Date: 2015-06-29 Functions: 4 4 100.0 %
Branches: 20 36 55.6 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) Andrew Tridgell 2002
       3                 :            :  * Copyright (C) Joel Rosdahl 2011
       4                 :            :  *
       5                 :            :  * This program is free software; you can redistribute it and/or modify it
       6                 :            :  * under the terms of the GNU General Public License as published by the Free
       7                 :            :  * Software Foundation; either version 3 of the License, or (at your option)
       8                 :            :  * any later version.
       9                 :            :  *
      10                 :            :  * This program is distributed in the hope that it will be useful, but WITHOUT
      11                 :            :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12                 :            :  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
      13                 :            :  * more details.
      14                 :            :  *
      15                 :            :  * You should have received a copy of the GNU General Public License along with
      16                 :            :  * this program; if not, write to the Free Software Foundation, Inc., 51
      17                 :            :  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      18                 :            :  */
      19                 :            : 
      20                 :            : #include "ccache.h"
      21                 :            : 
      22                 :            : extern struct conf *conf;
      23                 :            : 
      24                 :            : static char *
      25                 :            : find_executable_in_path(const char *name, const char *exclude_name, char *path);
      26                 :            : 
      27                 :            : #ifdef _WIN32
      28                 :            : /*
      29                 :            :  * Re-create a win32 command line string based on **argv.
      30                 :            :  * http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
      31                 :            :  */
      32                 :            : char *
      33                 :            : win32argvtos(char *prefix, char **argv)
      34                 :            : {
      35                 :            :         char *arg;
      36                 :            :         char *ptr;
      37                 :            :         char *str;
      38                 :            :         int l = 0;
      39                 :            :         int i, j;
      40                 :            : 
      41                 :            :         i = 0;
      42                 :            :         arg = prefix ? prefix : argv[i++];
      43                 :            :         do {
      44                 :            :                 int bs = 0;
      45                 :            :                 for (j = 0; arg[j]; j++) {
      46                 :            :                         switch (arg[j]) {
      47                 :            :                         case '\\':
      48                 :            :                                 bs++;
      49                 :            :                                 break;
      50                 :            :                         case '"':
      51                 :            :                                 bs = (bs << 1) + 1;
      52                 :            :                         default:
      53                 :            :                                 l += bs + 1;
      54                 :            :                                 bs = 0;
      55                 :            :                         }
      56                 :            :                 }
      57                 :            :                 l += (bs << 1) + 3;
      58                 :            :         } while ((arg = argv[i++]));
      59                 :            : 
      60                 :            :         str = ptr = malloc(l + 1);
      61                 :            :         if (!str)
      62                 :            :                 return NULL;
      63                 :            : 
      64                 :            :         i = 0;
      65                 :            :         arg = prefix ? prefix : argv[i++];
      66                 :            :         do {
      67                 :            :                 int bs = 0;
      68                 :            :                 *ptr++ = '"';
      69                 :            :                 for (j = 0; arg[j]; j++) {
      70                 :            :                         switch (arg[j]) {
      71                 :            :                         case '\\':
      72                 :            :                                 bs++;
      73                 :            :                                 break;
      74                 :            :                         case '"':
      75                 :            :                                 bs = (bs << 1) + 1;
      76                 :            :                         default:
      77                 :            :                                 while (bs && bs--)
      78                 :            :                                         *ptr++ = '\\';
      79                 :            :                                 *ptr++ = arg[j];
      80                 :            :                         }
      81                 :            :                 }
      82                 :            :                 bs <<= 1;
      83                 :            :                 while (bs && bs--)
      84                 :            :                         *ptr++ = '\\';
      85                 :            :                 *ptr++ = '"';
      86                 :            :                 *ptr++ = ' ';
      87                 :            :         } while ((arg = argv[i++]));
      88                 :            :         ptr[-1] = '\0';
      89                 :            : 
      90                 :            :         return str;
      91                 :            : }
      92                 :            : 
      93                 :            : char *
      94                 :            : win32getshell(char *path)
      95                 :            : {
      96                 :            :         char *path_env;
      97                 :            :         char *sh = NULL;
      98                 :            :         const char *ext;
      99                 :            : 
     100                 :            :         ext = get_extension(path);
     101                 :            :         if (ext && strcasecmp(ext, ".sh") == 0 && (path_env = getenv("PATH")))
     102                 :            :                 sh = find_executable_in_path("sh.exe", NULL, path_env);
     103                 :            :         if (!sh && getenv("CCACHE_DETECT_SHEBANG")) {
     104                 :            :                 /* Detect shebang. */
     105                 :            :                 FILE *fp;
     106                 :            :                 fp = fopen(path, "r");
     107                 :            :                 if (fp) {
     108                 :            :                         char buf[10];
     109                 :            :                         fgets(buf, sizeof(buf), fp);
     110                 :            :                         buf[9] = 0;
     111                 :            :                         if (str_eq(buf, "#!/bin/sh") && (path_env = getenv("PATH")))
     112                 :            :                                 sh = find_executable_in_path("sh.exe", NULL, path_env);
     113                 :            :                         fclose(fp);
     114                 :            :                 }
     115                 :            :         }
     116                 :            : 
     117                 :            :         return sh;
     118                 :            : }
     119                 :            : 
     120                 :            : void add_exe_ext_if_no_to_fullpath(char *full_path_win_ext, size_t max_size,
     121                 :            :                                    const char *ext, const char *path) {
     122                 :            :         if (!ext || (!str_eq(".exe", ext)
     123                 :            :                      && !str_eq(".bat", ext)
     124                 :            :                      && !str_eq(".EXE", ext)
     125                 :            :                      && !str_eq(".BAT", ext))) {
     126                 :            :                 snprintf(full_path_win_ext, max_size, "%s.exe", path);
     127                 :            :         } else {
     128                 :            :                 snprintf(full_path_win_ext, max_size, "%s", path);
     129                 :            :         }
     130                 :            : }
     131                 :            : 
     132                 :            : int
     133                 :            : win32execute(char *path, char **argv, int doreturn,
     134                 :            :              int fd_stdout, int fd_stderr)
     135                 :            : {
     136                 :            :         PROCESS_INFORMATION pi;
     137                 :            :         STARTUPINFO si;
     138                 :            :         BOOL ret;
     139                 :            :         DWORD exitcode;
     140                 :            :         char *sh = NULL;
     141                 :            :         char *args;
     142                 :            : 
     143                 :            :         memset(&pi, 0x00, sizeof(pi));
     144                 :            :         memset(&si, 0x00, sizeof(si));
     145                 :            : 
     146                 :            :         sh = win32getshell(path);
     147                 :            :         if (sh)
     148                 :            :                 path = sh;
     149                 :            : 
     150                 :            :         si.cb = sizeof(STARTUPINFO);
     151                 :            :         if (fd_stdout != -1) {
     152                 :            :                 si.hStdOutput = (HANDLE)_get_osfhandle(fd_stdout);
     153                 :            :                 si.hStdError = (HANDLE)_get_osfhandle(fd_stderr);
     154                 :            :                 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
     155                 :            :                 si.dwFlags = STARTF_USESTDHANDLES;
     156                 :            :                 if (si.hStdOutput == INVALID_HANDLE_VALUE
     157                 :            :                     || si.hStdError == INVALID_HANDLE_VALUE) {
     158                 :            :                         return -1;
     159                 :            :                 }
     160                 :            :         } else {
     161                 :            :                 /* redirect subprocess stdout, stderr into current process */
     162                 :            :                 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
     163                 :            :                 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
     164                 :            :                 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
     165                 :            :                 si.dwFlags = STARTF_USESTDHANDLES;
     166                 :            :                 if (si.hStdOutput == INVALID_HANDLE_VALUE
     167                 :            :                     || si.hStdError == INVALID_HANDLE_VALUE) {
     168                 :            :                         return -1;
     169                 :            :                 }
     170                 :            :         }
     171                 :            :         args = win32argvtos(sh, argv);
     172                 :            : 
     173                 :            :         const char *ext = strrchr(path, '.');
     174                 :            :         char full_path_win_ext[MAX_PATH] = {0};
     175                 :            :         add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext, path);
     176                 :            :         ret = CreateProcess(full_path_win_ext, args, NULL, NULL, 1, 0, NULL, NULL,
     177                 :            :                             &si, &pi);
     178                 :            :         if (fd_stdout != -1) {
     179                 :            :                 close(fd_stdout);
     180                 :            :                 close(fd_stderr);
     181                 :            :         }
     182                 :            :         free(args);
     183                 :            :         if (ret == 0) {
     184                 :            :                 LPVOID lpMsgBuf;
     185                 :            :                 LPVOID lpDisplayBuf;
     186                 :            :                 DWORD dw = GetLastError();
     187                 :            : 
     188                 :            :                 FormatMessage(
     189                 :            :                         FORMAT_MESSAGE_ALLOCATE_BUFFER |
     190                 :            :                         FORMAT_MESSAGE_FROM_SYSTEM |
     191                 :            :                         FORMAT_MESSAGE_IGNORE_INSERTS,
     192                 :            :                         NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
     193                 :            :                         0, NULL);
     194                 :            : 
     195                 :            :                 lpDisplayBuf =
     196                 :            :                         (LPVOID) LocalAlloc(LMEM_ZEROINIT,
     197                 :            :                                             (lstrlen((LPCTSTR) lpMsgBuf)
     198                 :            :                                              + lstrlen((LPCTSTR) __FILE__) + 200)
     199                 :            :                                             * sizeof(TCHAR));
     200                 :            :                 _snprintf((LPTSTR) lpDisplayBuf,
     201                 :            :                           LocalSize(lpDisplayBuf) / sizeof(TCHAR),
     202                 :            :                           TEXT("%s failed with error %d: %s"), __FILE__, dw, lpMsgBuf);
     203                 :            : 
     204                 :            :                 cc_log("can't execute %s; OS returned error: %s",
     205                 :            :                        full_path_win_ext, (char*)lpDisplayBuf);
     206                 :            : 
     207                 :            :                 LocalFree(lpMsgBuf);
     208                 :            :                 LocalFree(lpDisplayBuf);
     209                 :            : 
     210                 :            :                 return -1;
     211                 :            :         }
     212                 :            :         WaitForSingleObject(pi.hProcess, INFINITE);
     213                 :            :         GetExitCodeProcess(pi.hProcess, &exitcode);
     214                 :            :         CloseHandle(pi.hProcess);
     215                 :            :         CloseHandle(pi.hThread);
     216                 :            :         if (!doreturn)
     217                 :            :                 x_exit(exitcode);
     218                 :            :         return exitcode;
     219                 :            : }
     220                 :            : 
     221                 :            : #else
     222                 :            : 
     223                 :            : /*
     224                 :            :   execute a compiler backend, capturing all output to the given paths
     225                 :            :   the full path to the compiler to run is in argv[0]
     226                 :            : */
     227                 :            : int
     228                 :          2 : execute(char **argv, int fd_out, int fd_err)
     229                 :            : {
     230                 :            :         pid_t pid;
     231                 :            :         int status;
     232                 :            : 
     233                 :          2 :         cc_log_argv("Executing ", argv);
     234                 :          2 :         pid = fork();
     235         [ -  + ]:          4 :         if (pid == -1) {
     236                 :          0 :                 fatal("Failed to fork: %s", strerror(errno));
     237                 :            :         }
     238                 :            : 
     239         [ +  + ]:          4 :         if (pid == 0) {
     240                 :            :                 /* Child. */
     241                 :          2 :                 dup2(fd_out, 1);
     242                 :          2 :                 close(fd_out);
     243                 :          2 :                 dup2(fd_err, 2);
     244                 :          2 :                 close(fd_err);
     245                 :          2 :                 x_exit(execv(argv[0], argv));
     246                 :            :         }
     247                 :            : 
     248                 :          2 :         close(fd_out);
     249                 :          2 :         close(fd_err);
     250                 :            : 
     251         [ -  + ]:          2 :         if (waitpid(pid, &status, 0) != pid) {
     252                 :          0 :                 fatal("waitpid failed: %s", strerror(errno));
     253                 :            :         }
     254                 :            : 
     255 [ +  - ][ -  + ]:          2 :         if (WEXITSTATUS(status) == 0 && WIFSIGNALED(status)) {
     256                 :          0 :                 return -1;
     257                 :            :         }
     258                 :            : 
     259                 :          2 :         return WEXITSTATUS(status);
     260                 :            : }
     261                 :            : #endif
     262                 :            : 
     263                 :            : 
     264                 :            : /*
     265                 :            :  * Find an executable by name in $PATH. Exclude any that are links to
     266                 :            :  * exclude_name.
     267                 :            : */
     268                 :            : char *
     269                 :          1 : find_executable(const char *name, const char *exclude_name)
     270                 :            : {
     271                 :            :         char *path;
     272                 :            : 
     273         [ -  + ]:          1 :         if (is_absolute_path(name)) {
     274                 :          0 :                 return x_strdup(name);
     275                 :            :         }
     276                 :            : 
     277                 :          1 :         path = conf->path;
     278         [ +  - ]:          1 :         if (str_eq(path, "")) {
     279                 :          1 :                 path = getenv("PATH");
     280                 :            :         }
     281         [ -  + ]:          1 :         if (!path) {
     282                 :          0 :                 cc_log("No PATH variable");
     283                 :          0 :                 return NULL;
     284                 :            :         }
     285                 :            : 
     286                 :          1 :         return find_executable_in_path(name, exclude_name, path);
     287                 :            : }
     288                 :            : 
     289                 :            : static char *
     290                 :          1 : find_executable_in_path(const char *name, const char *exclude_name, char *path)
     291                 :            : {
     292                 :          1 :         char *tok, *saveptr = NULL;
     293                 :            : 
     294                 :          1 :         path = x_strdup(path);
     295                 :            : 
     296                 :            :         /* search the path looking for the first compiler of the right name
     297                 :            :            that isn't us */
     298         [ +  - ]:          2 :         for (tok = strtok_r(path, PATH_DELIM, &saveptr);
     299                 :            :              tok;
     300                 :          1 :              tok = strtok_r(NULL, PATH_DELIM, &saveptr)) {
     301                 :            : #ifdef _WIN32
     302                 :            :                 char namebuf[MAX_PATH];
     303                 :            :                 int ret = SearchPath(tok, name, NULL,
     304                 :            :                                      sizeof(namebuf), namebuf, NULL);
     305                 :            :                 if (!ret) {
     306                 :            :                         char *exename = format("%s.exe", name);
     307                 :            :                         ret = SearchPath(tok, exename, NULL,
     308                 :            :                                          sizeof(namebuf), namebuf, NULL);
     309                 :            :                         free(exename);
     310                 :            :                 }
     311                 :            :                 (void) exclude_name;
     312                 :            :                 if (ret) {
     313                 :            :                         free(path);
     314                 :            :                         return x_strdup(namebuf);
     315                 :            :                 }
     316                 :            : #else
     317                 :            :                 struct stat st1, st2;
     318                 :          2 :                 char *fname = format("%s/%s", tok, name);
     319                 :            :                 /* look for a normal executable file */
     320   [ +  +  +  -  :          4 :                 if (access(fname, X_OK) == 0 &&
           +  - ][ +  - ]
     321                 :          1 :                     lstat(fname, &st1) == 0 &&
     322                 :          1 :                     stat(fname, &st2) == 0 &&
     323                 :          1 :                     S_ISREG(st2.st_mode)) {
     324         [ -  + ]:          1 :                         if (S_ISLNK(st1.st_mode)) {
     325                 :          0 :                                 char *buf = x_realpath(fname);
     326         [ #  # ]:          0 :                                 if (buf) {
     327                 :          0 :                                         char *p = basename(buf);
     328         [ #  # ]:          0 :                                         if (str_eq(p, exclude_name)) {
     329                 :            :                                                 /* It's a link to "ccache"! */
     330                 :          0 :                                                 free(p);
     331                 :          0 :                                                 free(buf);
     332                 :          0 :                                                 continue;
     333                 :            :                                         }
     334                 :          0 :                                         free(buf);
     335                 :          0 :                                         free(p);
     336                 :            :                                 }
     337                 :            :                         }
     338                 :            : 
     339                 :            :                         /* Found it! */
     340                 :          1 :                         free(path);
     341                 :          1 :                         return fname;
     342                 :            :                 }
     343                 :          1 :                 free(fname);
     344                 :            : #endif
     345                 :            :         }
     346                 :            : 
     347                 :          0 :         free(path);
     348                 :          1 :         return NULL;
     349                 :            : }
     350                 :            : 
     351                 :            : void
     352                 :          3 : print_command(FILE *fp, char **argv)
     353                 :            : {
     354                 :            :         int i;
     355         [ +  + ]:         15 :         for (i = 0; argv[i]; i++) {
     356         [ +  + ]:         12 :                 fprintf(fp, "%s%s",  (i == 0) ? "" : " ", argv[i]);
     357                 :            :         }
     358                 :          3 :         fprintf(fp, "\n");
     359                 :          3 : }

Generated by: LCOV version 1.9