libc

my libc
git clone git://git.evenfri.pw/libc.git
Log | Files | Refs | README

execvp.c (1798B)


      1 /*
      2  * execvp.c - execute a file, searching PATH
      3  * Copyright (C) 2026. All rights reserved.
      4  */
      5 
      6 #include "libc.h"
      7 
      8 char **environ;
      9 
     10 int execvp(const char *file, char *const argv[]) {
     11   static char *empty_env[] = { NULL };
     12   char **env = (environ != NULL) ? environ : empty_env;
     13 
     14   if (file == NULL || *file == '\0') {
     15     errno = ENOENT;
     16     return -1;
     17   }
     18 
     19   if (strchr(file, '/') != NULL) {
     20     return execve(file, argv, env);
     21   }
     22 
     23   const char *path_env = NULL;
     24   for (char **ep = env; *ep != NULL; ++ep) {
     25     if (ep[0][0] == 'P' && ep[0][1] == 'A' &&
     26         ep[0][2] == 'T' && ep[0][3] == 'H' && ep[0][4] == '=') {
     27       path_env = *ep + 5;
     28       break;
     29     }
     30   }
     31 
     32   if (path_env == NULL) {
     33     path_env = "/bin:/usr/bin";
     34   }
     35 
     36   char path_buf[1024];
     37   size_t file_len = strlen(file);
     38   int saved_errno = ENOENT;
     39 
     40   if (file_len >= sizeof(path_buf)) {
     41     errno = ENAMETOOLONG;
     42     return -1;
     43   }
     44 
     45   const char *p = path_env;
     46   for (;;) {
     47     const char *start = p;
     48     while (*p != '\0' && *p != ':') {
     49       p++;
     50     }
     51 
     52     size_t dir_len = (size_t)(p - start);
     53     size_t needed = file_len + 1;
     54 
     55     if (dir_len != 0) {
     56       if (dir_len > sizeof(path_buf) - needed - 1) {
     57         saved_errno = ENAMETOOLONG;
     58         goto next_path;
     59       }
     60       needed += dir_len + 1;
     61     }
     62 
     63     if (needed <= sizeof(path_buf)) {
     64       if (dir_len == 0) {
     65         memcpy(path_buf, file, file_len + 1);
     66       } else {
     67         memcpy(path_buf, start, dir_len);
     68         path_buf[dir_len] = '/';
     69         memcpy(path_buf + dir_len + 1, file, file_len + 1);
     70       }
     71 
     72       if (execve(path_buf, argv, env) == -1) {
     73         saved_errno = errno;
     74       }
     75     } else {
     76       saved_errno = ENAMETOOLONG;
     77     }
     78 
     79 next_path:
     80     if (*p == '\0') {
     81       break;
     82     }
     83     p++;
     84   }
     85 
     86   errno = saved_errno;
     87   return -1;
     88 }