kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

build_host_posix.c (11845B)


      1 #include "env_build.h"
      2 
      3 #include "dist_host.h"
      4 
      5 #include <dirent.h>
      6 #include <errno.h>
      7 #include <fcntl.h>
      8 #include <signal.h>
      9 #include <stdint.h>
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 #include <sys/select.h>
     14 #include <sys/socket.h>
     15 #include <sys/stat.h>
     16 #include <sys/un.h>
     17 #include <sys/wait.h>
     18 #include <unistd.h>
     19 
     20 #define DRIVER_BUILD_FRAME_MAX 65536u
     21 
     22 struct KitBuildListener {
     23   int fd;
     24   char path[sizeof(((struct sockaddr_un*)0)->sun_path)];
     25 };
     26 
     27 struct KitBuildConn {
     28   int fd;
     29 };
     30 
     31 static int db_path_copy(char* out, size_t cap, KitSlice s) {
     32   if (!out || cap == 0u || !s.s || s.len + 1u > cap) return 1;
     33   memcpy(out, s.s, s.len);
     34   out[s.len] = '\0';
     35   return 0;
     36 }
     37 
     38 static int db_remove_tree(const char* path) {
     39   struct stat st;
     40   if (lstat(path, &st) != 0) return errno == ENOENT ? 0 : 1;
     41   if (S_ISDIR(st.st_mode)) {
     42     DIR* d = opendir(path);
     43     struct dirent* ent;
     44     if (!d) return 1;
     45     while ((ent = readdir(d)) != NULL) {
     46       char child[KIT_BUILD_PATH_MAX];
     47       const char* name = ent->d_name;
     48       size_t np = strlen(path), nn = strlen(name);
     49       if ((name[0] == '.' && name[1] == '\0') ||
     50           (name[0] == '.' && name[1] == '.' && name[2] == '\0'))
     51         continue;
     52       if (np + 1u + nn + 1u > sizeof child) {
     53         closedir(d);
     54         return 1;
     55       }
     56       memcpy(child, path, np);
     57       child[np] = '/';
     58       memcpy(child + np + 1u, name, nn + 1u);
     59       if (db_remove_tree(child) != 0) {
     60         closedir(d);
     61         return 1;
     62       }
     63     }
     64     closedir(d);
     65     return rmdir(path) == 0 ? 0 : 1;
     66   }
     67   return unlink(path) == 0 ? 0 : 1;
     68 }
     69 
     70 static int db_store_rename(void* user, KitSlice from, KitSlice to) {
     71   char f[KIT_BUILD_PATH_MAX], t[KIT_BUILD_PATH_MAX];
     72   (void)user;
     73   if (db_path_copy(f, sizeof f, from) || db_path_copy(t, sizeof t, to))
     74     return 1;
     75   return rename(f, t) == 0 ? 0 : 1;
     76 }
     77 
     78 static int db_store_remove(void* user, KitSlice path, int recursive) {
     79   char p[KIT_BUILD_PATH_MAX];
     80   (void)user;
     81   if (db_path_copy(p, sizeof p, path)) return 1;
     82   if (recursive) return db_remove_tree(p);
     83   return unlink(p) == 0 || rmdir(p) == 0 || errno == ENOENT ? 0 : 1;
     84 }
     85 
     86 static int db_store_make_temp_dir(void* user, KitSlice parent, char* out,
     87                                   size_t cap) {
     88   char p[KIT_BUILD_PATH_MAX];
     89   size_t n;
     90   (void)user;
     91   if (!out || cap == 0u || db_path_copy(p, sizeof p, parent)) return 1;
     92   n = strlen(p);
     93   if (n + sizeof("/tmp.XXXXXX") > cap) return 1;
     94   memcpy(out, p, n);
     95   out[n++] = '/';
     96   memcpy(out + n, "tmp.XXXXXX", sizeof("tmp.XXXXXX"));
     97   return mkdtemp(out) ? 0 : 1;
     98 }
     99 
    100 static int db_store_sync_path(void* user, KitSlice path) {
    101   char p[KIT_BUILD_PATH_MAX];
    102   int fd;
    103   int rc = 0;
    104   (void)user;
    105   if (db_path_copy(p, sizeof p, path)) return 1;
    106   fd = open(p, O_RDONLY);
    107   if (fd < 0) return 0;
    108   if (fsync(fd) != 0) rc = 1;
    109   close(fd);
    110   return rc;
    111 }
    112 
    113 static int db_store_list_dir(void* user, KitSlice path, KitBuildDirFn cb,
    114                              void* cb_user) {
    115   char p[KIT_BUILD_PATH_MAX];
    116   DIR* d;
    117   struct dirent* ent;
    118   (void)user;
    119   if (!cb || db_path_copy(p, sizeof p, path)) return 1;
    120   d = opendir(p);
    121   if (!d) return 1;
    122   while ((ent = readdir(d)) != NULL) {
    123     const char* name = ent->d_name;
    124     if ((name[0] == '.' && name[1] == '\0') ||
    125         (name[0] == '.' && name[1] == '.' && name[2] == '\0'))
    126       continue;
    127     if (cb(cb_user, kit_slice_cstr(name))) {
    128       closedir(d);
    129       return 1;
    130     }
    131   }
    132   closedir(d);
    133   return 0;
    134 }
    135 
    136 static char* db_slice_dup(DriverEnv* env, KitSlice s) {
    137   char* out = (char*)driver_alloc(env, s.len + 1u);
    138   if (!out) return NULL;
    139   if (s.len) memcpy(out, s.s, s.len);
    140   out[s.len] = '\0';
    141   return out;
    142 }
    143 
    144 static int db_full_write(int fd, const uint8_t* p, size_t n) {
    145   size_t off = 0;
    146   while (off < n) {
    147     ssize_t w = write(fd, p + off, n - off);
    148     if (w > 0) {
    149       off += (size_t)w;
    150     } else if (w < 0 && errno == EINTR) {
    151       continue;
    152     } else {
    153       return 1;
    154     }
    155   }
    156   return 0;
    157 }
    158 
    159 static int db_full_read(int fd, uint8_t* p, size_t n) {
    160   size_t off = 0;
    161   while (off < n) {
    162     ssize_t r = read(fd, p + off, n - off);
    163     if (r > 0) {
    164       off += (size_t)r;
    165     } else if (r < 0 && errno == EINTR) {
    166       continue;
    167     } else {
    168       return 1;
    169     }
    170   }
    171   return 0;
    172 }
    173 
    174 static int db_transport_listen(void* user, char* name_out, size_t cap,
    175                                KitBuildListener** out) {
    176   DriverBuildHost* bh = (DriverBuildHost*)user;
    177   KitBuildListener* l = NULL;
    178   struct sockaddr_un sa;
    179   int fd = -1;
    180   if (!bh || !bh->env || !name_out || cap == 0u || !out) return 1;
    181   *out = NULL;
    182   l = (KitBuildListener*)driver_alloc_zeroed(bh->env, sizeof *l);
    183   if (!l) return 1;
    184   fd = socket(AF_UNIX, SOCK_STREAM, 0);
    185   if (fd < 0) goto err;
    186   snprintf(l->path, sizeof l->path, "/tmp/kit-build-%ld-%llu.sock",
    187            (long)getpid(), (unsigned long long)bh->next_endpoint++);
    188   memset(&sa, 0, sizeof sa);
    189   sa.sun_family = AF_UNIX;
    190   snprintf(sa.sun_path, sizeof sa.sun_path, "%s", l->path);
    191   (void)unlink(l->path);
    192   if (bind(fd, (struct sockaddr*)&sa, sizeof sa) != 0 ||
    193       listen(fd, 1) != 0)
    194     goto err;
    195   if (strlen(l->path) + 1u > cap) goto err;
    196   memcpy(name_out, l->path, strlen(l->path) + 1u);
    197   l->fd = fd;
    198   *out = l;
    199   return 0;
    200 
    201 err:
    202   if (fd >= 0) close(fd);
    203   if (l) {
    204     if (l->path[0]) unlink(l->path);
    205     driver_free(bh->env, l, sizeof *l);
    206   }
    207   return 1;
    208 }
    209 
    210 static int db_transport_accept(void* user, KitBuildListener* lst,
    211                                KitBuildConn** out) {
    212   DriverBuildHost* bh = (DriverBuildHost*)user;
    213   KitBuildConn* c;
    214   int fd;
    215   if (!bh || !lst || !out) return 1;
    216   *out = NULL;
    217   do {
    218     fd = accept(lst->fd, NULL, NULL);
    219   } while (fd < 0 && errno == EINTR);
    220   if (fd < 0) return 1;
    221   c = (KitBuildConn*)driver_alloc_zeroed(bh->env, sizeof *c);
    222   if (!c) {
    223     close(fd);
    224     return 1;
    225   }
    226   c->fd = fd;
    227   *out = c;
    228   return 0;
    229 }
    230 
    231 static int db_transport_try_accept(void* user, KitBuildListener* lst,
    232                                    KitBuildConn** out, int* ready) {
    233   DriverBuildHost* bh = (DriverBuildHost*)user;
    234   KitBuildConn* c;
    235   fd_set fds;
    236   struct timeval tv;
    237   int r;
    238   int fd;
    239   if (!bh || !lst || !out || !ready) return 1;
    240   *out = NULL;
    241   *ready = 0;
    242   /* Darwin's FD_ZERO expands to the non-C11 __builtin_bzero.  Initialize the
    243    * public fd_set object directly so the hosted adapter remains bootstrapable
    244    * by a strict C11 compiler. */
    245   memset(&fds, 0, sizeof fds);
    246   FD_SET(lst->fd, &fds);
    247   tv.tv_sec = 0;
    248   tv.tv_usec = 10000;
    249   do {
    250     r = select(lst->fd + 1, &fds, NULL, NULL, &tv);
    251   } while (r < 0 && errno == EINTR);
    252   if (r < 0) return 1;
    253   if (r == 0) return 0;
    254   do {
    255     fd = accept(lst->fd, NULL, NULL);
    256   } while (fd < 0 && errno == EINTR);
    257   if (fd < 0) return 1;
    258   c = (KitBuildConn*)driver_alloc_zeroed(bh->env, sizeof *c);
    259   if (!c) {
    260     close(fd);
    261     return 1;
    262   }
    263   c->fd = fd;
    264   *out = c;
    265   *ready = 1;
    266   return 0;
    267 }
    268 
    269 static void db_transport_close_listener(void* user, KitBuildListener* lst) {
    270   DriverBuildHost* bh = (DriverBuildHost*)user;
    271   if (!bh || !lst) return;
    272   if (lst->fd >= 0) close(lst->fd);
    273   if (lst->path[0]) unlink(lst->path);
    274   driver_free(bh->env, lst, sizeof *lst);
    275 }
    276 
    277 static int db_transport_dial(void* user, KitSlice endpoint, KitBuildConn** out) {
    278   DriverBuildHost* bh = (DriverBuildHost*)user;
    279   KitBuildConn* c = NULL;
    280   char path[sizeof(((struct sockaddr_un*)0)->sun_path)];
    281   struct sockaddr_un sa;
    282   int fd = -1;
    283   if (!bh || !bh->env || !out || db_path_copy(path, sizeof path, endpoint))
    284     return 1;
    285   *out = NULL;
    286   fd = socket(AF_UNIX, SOCK_STREAM, 0);
    287   if (fd < 0) return 1;
    288   memset(&sa, 0, sizeof sa);
    289   sa.sun_family = AF_UNIX;
    290   snprintf(sa.sun_path, sizeof sa.sun_path, "%s", path);
    291   if (connect(fd, (struct sockaddr*)&sa, sizeof sa) != 0) {
    292     close(fd);
    293     return 1;
    294   }
    295   c = (KitBuildConn*)driver_alloc_zeroed(bh->env, sizeof *c);
    296   if (!c) {
    297     close(fd);
    298     return 1;
    299   }
    300   c->fd = fd;
    301   *out = c;
    302   return 0;
    303 }
    304 
    305 static int db_transport_read(void* user, KitBuildConn* conn, uint8_t* buf,
    306                              size_t cap, size_t* n) {
    307   uint8_t hdr[4];
    308   uint32_t len;
    309   (void)user;
    310   if (!conn || !buf || !n) return 1;
    311   if (db_full_read(conn->fd, hdr, sizeof hdr) != 0) return 1;
    312   len = (uint32_t)hdr[0] | ((uint32_t)hdr[1] << 8) |
    313         ((uint32_t)hdr[2] << 16) | ((uint32_t)hdr[3] << 24);
    314   if (len > cap || len > DRIVER_BUILD_FRAME_MAX) return 1;
    315   if (db_full_read(conn->fd, buf, len) != 0) return 1;
    316   *n = len;
    317   return 0;
    318 }
    319 
    320 static int db_transport_write(void* user, KitBuildConn* conn,
    321                               const uint8_t* buf, size_t n) {
    322   uint8_t hdr[4];
    323   (void)user;
    324   if (!conn || (!buf && n) || n > DRIVER_BUILD_FRAME_MAX) return 1;
    325   hdr[0] = (uint8_t)(n & 0xffu);
    326   hdr[1] = (uint8_t)((n >> 8) & 0xffu);
    327   hdr[2] = (uint8_t)((n >> 16) & 0xffu);
    328   hdr[3] = (uint8_t)((n >> 24) & 0xffu);
    329   return db_full_write(conn->fd, hdr, sizeof hdr) ||
    330          db_full_write(conn->fd, buf, n);
    331 }
    332 
    333 static void db_transport_close(void* user, KitBuildConn* conn) {
    334   DriverBuildHost* bh = (DriverBuildHost*)user;
    335   if (!bh || !conn) return;
    336   if (conn->fd >= 0) close(conn->fd);
    337   driver_free(bh->env, conn, sizeof *conn);
    338 }
    339 
    340 static int db_fetch_url(void* user, KitSlice url, KitSlice dest) {
    341   DriverBuildHost* bh = (DriverBuildHost*)user;
    342   char* url_s;
    343   char* dest_s;
    344   int rc;
    345   if (!bh || !bh->env) return 1;
    346   url_s = db_slice_dup(bh->env, url);
    347   dest_s = db_slice_dup(bh->env, dest);
    348   if (!url_s || !dest_s) {
    349     if (url_s) driver_free(bh->env, url_s, strlen(url_s) + 1u);
    350     if (dest_s) driver_free(bh->env, dest_s, strlen(dest_s) + 1u);
    351     return 1;
    352   }
    353   rc = driver_fetch_url(url_s, dest_s);
    354   driver_free(bh->env, url_s, strlen(url_s) + 1u);
    355   driver_free(bh->env, dest_s, strlen(dest_s) + 1u);
    356   return rc;
    357 }
    358 
    359 int driver_build_host_init(DriverBuildHost* out, DriverEnv* env) {
    360   if (!out || !env) return 1;
    361   memset(out, 0, sizeof *out);
    362   out->env = env;
    363   out->cas_host = driver_cas_host(env);
    364   out->store_io.rename = db_store_rename;
    365   out->store_io.remove = db_store_remove;
    366   out->store_io.make_temp_dir = db_store_make_temp_dir;
    367   out->store_io.sync_path = db_store_sync_path;
    368   out->store_io.list_dir = db_store_list_dir;
    369   out->store_io.user = out;
    370   out->exec = driver_exec(env);
    371   out->transport.listen = db_transport_listen;
    372   out->transport.accept = db_transport_accept;
    373   out->transport.try_accept = db_transport_try_accept;
    374   out->transport.close_listener = db_transport_close_listener;
    375   out->transport.dial = db_transport_dial;
    376   out->transport.read_frame = db_transport_read;
    377   out->transport.write_frame = db_transport_write;
    378   out->transport.close = db_transport_close;
    379   out->transport.user = out;
    380   out->fetch.fetch_url = db_fetch_url;
    381   out->fetch.user = out;
    382   out->host.cas_host = &out->cas_host;
    383   out->host.store_io = &out->store_io;
    384   out->host.exec = &out->exec;
    385   out->host.transport = &out->transport;
    386   out->host.fetch = &out->fetch;
    387   out->next_endpoint = 1;
    388   return 0;
    389 }
    390 
    391 void driver_build_host_fini(DriverBuildHost* host) { (void)host; }
    392 
    393 char* driver_build_host_abs_path(DriverEnv* env, const char* path,
    394                                  size_t* out_size) {
    395   char cwd[KIT_BUILD_PATH_MAX];
    396   char* out;
    397   size_t nc, np, total;
    398   if (!env || !path) return NULL;
    399   if (path[0] == '/') {
    400     np = strlen(path);
    401     out = (char*)driver_alloc(env, np + 1u);
    402     if (!out) return NULL;
    403     memcpy(out, path, np + 1u);
    404     if (out_size) *out_size = np + 1u;
    405     return out;
    406   }
    407   if (!getcwd(cwd, sizeof cwd)) return NULL;
    408   nc = strlen(cwd);
    409   np = strlen(path);
    410   total = nc + 1u + np + 1u;
    411   out = (char*)driver_alloc(env, total);
    412   if (!out) return NULL;
    413   memcpy(out, cwd, nc);
    414   out[nc] = '/';
    415   memcpy(out + nc + 1u, path, np + 1u);
    416   if (out_size) *out_size = total;
    417   return out;
    418 }