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 }