static int update (confuga *C, const char *path, confuga_fid_t fid, confuga_off_t size, int flags) { int rc; int fd = -1; int n; char header[HEADER_LENGTH+1] = ""; int oflags = O_CREAT|O_WRONLY|O_TRUNC|O_SYNC; if (flags & CONFUGA_O_EXCL) oflags |= O_EXCL; fd = open(path, oflags, S_IRUSR|S_IWUSR); CATCHUNIX(fd); n = snprintf(header, sizeof(header), "file:" CONFUGA_FID_PRIFMT ":%0*" PRIxCONFUGA_OFF_T "\n", CONFUGA_FID_PRIARGS(fid), (int)sizeof(confuga_off_t)*2, (confuga_off_t)size); assert((size_t)n == HEADER_LENGTH); rc = full_write(fd, header, HEADER_LENGTH); CATCHUNIX(rc); if ((size_t)rc < HEADER_LENGTH) CATCH(EINVAL); /* FIXME */ debug(D_DEBUG, "write `%s'", header); /* debug chomps final newline */ rc = 0; goto out; out: close(fd); /* -1 is a NOP */ return rc; }
CONFUGA_API int confuga_metadata_lookup (confuga *C, const char *path, char **data, size_t *size) { int rc; int fd = -1; struct stat64 info; ssize_t n; size_t _size; char header[HEADER_LENGTH+1] = ""; confuga_fid_t fid; RESOLVE(path); if (size == NULL) size = &_size; debug(D_CONFUGA, "metadata_lookup(`%s')", unresolved_path); fd = open(path, O_RDONLY); CATCHUNIX(fd); CATCHUNIX(fstat64(fd, &info)); if (S_ISDIR(info.st_mode)) CATCH(EISDIR); else if (!S_ISREG(info.st_mode)) CATCH(EINVAL); n = read(fd, header, HEADER_LENGTH); if (n < (ssize_t)HEADER_LENGTH) CATCH(EINVAL); debug(D_DEBUG, "read `%s'", header); /* debug chomps final newline */ const char *current = header; if (!(strncmp(current, "meta:", strlen("meta:")) == 0)) CATCH(EINVAL); current += 5; /* read hash */ CATCH(confugaF_extract(C, &fid, current, ¤t)); assert(current[0] == ':'); current += 1; /* read size */ char *endptr; *size = strtoull(current, &endptr, 16); assert(*endptr == '\n'); *data = calloc(*size+1, sizeof(char)); if (*data == NULL) CATCH(ENOMEM); n = read(fd, *data, *size); if (n < (ssize_t)*size) CATCH(EINVAL); debug(D_DEBUG, "read `%s'", *data); /* debug chomps final newline */ rc = 0; goto out; out: debug(D_CONFUGA, "= %d (%s)", rc, strerror(rc)); close(fd); /* -1 is a NOP */ return rc; }
CONFUGA_API int confuga_metadata_update (confuga *C, const char *path, const char *data, size_t size) { static const confuga_fid_t fid = {""}; int rc; int fd = -1; int n; char header[HEADER_LENGTH+1] = ""; RESOLVE(path); debug(D_CONFUGA, "metadata_update(`%s')", unresolved_path); fd = open(path, O_CREAT|O_WRONLY|O_TRUNC|O_SYNC, S_IRUSR|S_IWUSR); CATCHUNIX(fd); n = snprintf(header, sizeof(header), "meta:" CONFUGA_FID_PRIFMT ":%0*" PRIxCONFUGA_OFF_T "\n", CONFUGA_FID_PRIARGS(fid), (int)sizeof(confuga_off_t)*2, (confuga_off_t)size); assert((size_t)n == HEADER_LENGTH); rc = full_write(fd, header, HEADER_LENGTH); CATCHUNIX(rc); if ((size_t)rc < HEADER_LENGTH) CATCH(EINVAL); /* FIXME */ debug(D_DEBUG, "write `%s'", header); /* debug chomps final newline */ rc = full_write(fd, data, size); CATCHUNIX(rc); if ((size_t)rc < size) CATCH(EINVAL); /* FIXME */ debug(D_DEBUG, "write `%s'", data); /* debug chomps final newline */ rc = 0; goto out; out: debug(D_CONFUGA, "= %d (%s)", rc, strerror(rc)); close(fd); /* -1 is a NOP */ return rc; }
static int lookup (confuga *C, const char *path, confuga_fid_t *fid, confuga_off_t *size, enum CONFUGA_FILE_TYPE *type) { int rc; int fd = -1; ssize_t n; char header[HEADER_LENGTH+1] = ""; struct stat64 info; fd = open(path, O_RDONLY); CATCHUNIX(fd); CATCHUNIX(fstat64(fd, &info)); if (S_ISDIR(info.st_mode)) CATCH(EISDIR); else if (!S_ISREG(info.st_mode)) CATCH(EINVAL); n = full_read(fd, header, HEADER_LENGTH); if (n < (ssize_t)HEADER_LENGTH) CATCH(EINVAL); debug(D_DEBUG, "read `%s'", header); /* debug chomps final newline */ const char *current = header; if (strncmp(current, "file:", strlen("file:")) == 0) *type = CONFUGA_FILE; else if (strncmp(current, "meta:", strlen("meta:")) == 0) *type = CONFUGA_FILE; else CATCH(EINVAL); current += 5; /* read hash */ int i; for (i = 0; i < (int)sizeof(fid->id); i += 1, current += 2) { char byte[3] = {current[0], current[1], '\0'}; unsigned long value = strtoul(byte, NULL, 16); fid->id[i] = value; } assert(current[0] == ':'); current += 1; /* read size */ if (size) { char *endptr; *size = strtoull(current, &endptr, 16); assert(*endptr == '\n'); } rc = 0; goto out; out: close(fd); return rc; }
static int sn_ticket (confuga *C, const struct confuga_host *host) { static const char SQL[] = "UPDATE Confuga.StorageNode" " SET ticket = ?2" " WHERE hostport = ?1;" ; int rc; sqlite3 *db = C->db; sqlite3_stmt *stmt = NULL; const char *current = SQL; time_t stoptime = STOPTIME_SHORT; char ticket[PATH_MAX]; char path[CHIRP_PATH_MAX]; struct stat info; FILE *stream = NULL; CATCHUNIX(snprintf(ticket, sizeof(ticket), "%s/ticket", C->root)); CATCHUNIX(chirp_reli_ticket_register(host->hostport, ticket, "self", TICKET_DURATION, stoptime)); /* The list permission is necessary because chirp_fs_local_scheduler.c:geturl does a stat. */ CATCHUNIX(snprintf(path, sizeof(path), "%s/file", host->root)); CATCHUNIX(chirp_reli_ticket_modify(host->hostport, ticket, path, "lr", stoptime)); /* Add write permission because a putfile may need retried. */ CATCHUNIX(snprintf(path, sizeof(path), "%s/open", host->root)); CATCHUNIX(chirp_reli_ticket_modify(host->hostport, ticket, path, "pw", stoptime)); CATCHUNIX(snprintf(path, sizeof(path), "%s/ticket", host->root)); stream = fopen(ticket, "r"); CATCHUNIX(stream ? 0 : -1); CATCHUNIX(fstat(fileno(stream), &info)); CATCHUNIX(chirp_reli_putfile(host->hostport, path, stream, S_IRUSR, info.st_size, stoptime)); sqlcatch(sqlite3_prepare_v2(db, current, -1, &stmt, ¤t)); sqlcatch(sqlite3_bind_text(stmt, 1, host->hostport, -1, SQLITE_STATIC)); sqlcatch(sqlite3_bind_blob(stmt, 2, C->ticket, sizeof(C->ticket), SQLITE_STATIC)); sqlcatchcode(sqlite3_step(stmt), SQLITE_DONE); sqlcatch(sqlite3_finalize(stmt); stmt = NULL); rc = 0; goto out; out: if (stream) fclose(stream); sqlite3_finalize(stmt); return rc; }
static int sandbox_create (char sandbox[PATH_MAX], chirp_jobid_t id) { int rc; char path[PATH_MAX] = ""; CATCHUNIX(snprintf(path, PATH_MAX, "/.__job.%" PRICHIRP_JOBID_T ".XXXXXX", id)); if (rc >= PATH_MAX) CATCH(ENAMETOOLONG); CATCHUNIX(chirp_fs_local_resolve(path, sandbox)); CATCHUNIX(mkdtemp(sandbox) ? 0 : -1); debug(D_DEBUG, "created new sandbox `%s'", sandbox); rc = 0; goto out; out: return rc; }
CONFUGA_API int confuga_closedir(confuga_dir *dir) { int rc; DIR *ldir = dir->dir; debug(D_CONFUGA, "closedir(`%s')", dir->path); free(dir); CATCHUNIX(closedir(ldir)); PROLOGUE }
int chirp_sqlite3_row_jsonify(sqlite3_stmt *stmt, buffer_t *B) { int rc; int i, first; CATCHUNIX(buffer_putliteral(B, "{")); for (i = 0, first = 1; i < sqlite3_column_count(stmt); i++, first = 0) { if (!first) CATCHUNIX(buffer_putliteral(B, ",")); CATCHUNIX(buffer_putfstring(B, "\"%s\":", sqlite3_column_name(stmt, i))); chirp_sqlite3_column_jsonify(stmt, i, B); } CATCHUNIX(buffer_putliteral(B, "}")); rc = 0; goto out; out: return rc; }
static int sandbox_delete (const char *sandbox) { int rc; CATCHUNIX(unlink_recursive(sandbox)); rc = 0; goto out; out: return rc; }
static int kill_kindly (pid_t pid) { int rc; /* N.B. There is no point in waiting for `pid' because one of its children * may be ignoring the kinder termination signals. We have to go through * the whole thing. However, if we get ESRCH (or any other error), this is * indication no process matches the group -pid. */ CATCHUNIX(kill(-pid, SIGTERM)); usleep(50); CATCHUNIX(kill(-pid, SIGQUIT)); usleep(50); CATCHUNIX(kill(-pid, SIGKILL)); usleep(50); rc = 0; goto out; out: return rc; }
int chirp_sqlite3_column_jsonify(sqlite3_stmt *stmt, int n, buffer_t *B) { int rc; switch (sqlite3_column_type(stmt, n)) { case SQLITE_NULL: CATCHUNIX(buffer_putliteral(B, "null")); break; case SQLITE_INTEGER: CATCHUNIX(buffer_putfstring(B, "%" PRId64, (int64_t) sqlite3_column_int64(stmt, n))); break; case SQLITE_FLOAT: CATCHUNIX(buffer_putfstring(B, "%.*e", DBL_DIG, sqlite3_column_double(stmt, n))); break; case SQLITE_TEXT: CATCHUNIX(buffer_putliteral(B, "\"")); CATCHUNIX(jsonA_escapestring(B, (const char *)sqlite3_column_text(stmt, n))); CATCHUNIX(buffer_putliteral(B, "\"")); break; default: abort(); } rc = 0; goto out; out: return rc; }
static INT64_T chirp_fs_confuga_open (const char *path, INT64_T flags, INT64_T mode) { int rc; char *data = NULL; int fd = getfd(); strncpy(open_files[fd].path, path, sizeof(open_files[fd].path)-1); switch (flags & O_ACCMODE) { case O_RDONLY: if (strncmp(path_basename(path), ".__", 3) == 0) { size_t len; buffer_init(&open_files[fd].f.metadata); CATCH(confuga_metadata_lookup(C, path, &data, &len)); CATCHUNIX(buffer_putlstring(&open_files[fd].f.metadata, data, len)); open_files[fd].type = CHIRP_FS_CONFUGA_META_READ; } else { confuga_fid_t fid; CATCH_CONFUGA(confuga_lookup(C, path, &fid, NULL)); CATCH_CONFUGA(confuga_replica_open(C, fid, &open_files[fd].f.replica, STOPTIME)); open_files[fd].type = CHIRP_FS_CONFUGA_REPL_READ; } break; case O_WRONLY: if (strncmp(path_basename(path), ".__", 3) == 0) { buffer_init(&open_files[fd].f.metadata); open_files[fd].type = CHIRP_FS_CONFUGA_META_WRITE; } else { CATCH_CONFUGA(confuga_file_create(C, &open_files[fd].f.file.file, STOPTIME)); open_files[fd].f.file.size = 0; open_files[fd].f.file.flags = 0; if (flags & O_EXCL) open_files[fd].f.file.flags |= CONFUGA_O_EXCL; open_files[fd].type = CHIRP_FS_CONFUGA_FILE_WRITE; } break; case O_RDWR: CATCH(EINVAL); default: assert(0); } rc = 0; goto out; out: free(data); if (rc) return (errno = rc, -1); else return fd; /* N.B. return fd on success */ }
static int resolve (confuga *C, const char *path, char resolved[CONFUGA_PATH_MAX]) { int rc; char collapse[CONFUGA_PATH_MAX]; char absolute[CONFUGA_PATH_MAX]; path_collapse(path, collapse, 1); CATCHUNIX(snprintf(absolute, sizeof(absolute), "%s/root/%s", C->root, collapse)); if ((size_t)rc >= CONFUGA_PATH_MAX) CATCH(ENAMETOOLONG); path_collapse(absolute, resolved, 1); rc = 0; goto out; out: return rc; }
static int do_stat (confuga *C, const char *path, struct confuga_stat *info, int (*statf) (const char *, struct stat64 *)) { int rc; struct stat64 linfo; enum CONFUGA_FILE_TYPE type; RESOLVE(path) CATCHUNIX(statf(path, &linfo)); if (S_ISREG(linfo.st_mode)) { CATCH(lookup(C, path, &info->fid, &info->size, &type)); } else { info->size = linfo.st_size; } info->ino = linfo.st_ino; info->mode = linfo.st_mode; info->uid = linfo.st_uid; info->gid = linfo.st_gid; info->nlink = linfo.st_nlink; info->atime = linfo.st_atime; info->mtime = linfo.st_mtime; info->ctime = linfo.st_ctime; PROLOGUE }
static INT64_T chirp_fs_confuga_pwrite(int fd, const void *buffer, INT64_T length, INT64_T offset) { int rc; size_t n; SETUP_FILE if (length < 0 || offset < 0) CATCH(EINVAL); switch (open_files[fd].type) { case CHIRP_FS_CONFUGA_FILE_WRITE: { if ((confuga_off_t)offset != open_files[fd].f.file.size) CATCH(EINVAL); /* do not allow random writes */ CATCH_CONFUGA(confuga_file_write(open_files[fd].f.file.file, buffer, length, &n, STOPTIME)); open_files[fd].f.file.size += n; break; } case CHIRP_FS_CONFUGA_META_WRITE: if ((size_t)offset != buffer_pos(&open_files[fd].f.metadata)) CATCH(EINVAL); /* do not allow random writes */ CATCHUNIX(buffer_putlstring(&open_files[fd].f.metadata, buffer, length)); n = length; break; default: CATCH(EBADF); } rc = 0; goto out; out: if (rc) { return (errno = rc, -1); } else { return n; /* N.B. return n on success */ } }
static int execute (const char *cmd, const char * const env[], int in[2], int out[2], int err[2]) { int rc; int i; CATCHUNIX(close(in[1])); CATCHUNIX(close(out[0])); CATCHUNIX(close(err[0])); CATCHUNIX(dup2(in[0], STDIN_FILENO)); CATCHUNIX(dup2(out[1], STDOUT_FILENO)); CATCHUNIX(dup2(err[1], STDERR_FILENO)); CATCHUNIX(close(in[0])); CATCHUNIX(close(out[1])); CATCHUNIX(close(err[1])); for(i = 0; env[i]; i++) { CATCHUNIX(putenv((char *)env[i])); } CATCHUNIX(execlp("sh", "sh", "-c", cmd, NULL)); rc = 0; goto out; out: fatal("shellcode execute failure: %s", strerror(errno)); abort(); }
int main (int argc, char *argv[]) { int rc; (void)testmergesort; if (strcmp(argv[1], "assert") == 0) { int fd; struct stat buf; size_t n; uint64_t i1, i2; CATCHUNIX(fd = open(argv[2], O_RDONLY)); CATCHUNIX(fstat(fd, &buf)); assert(buf.st_size % sizeof(uint64_t) == 0); FILE *input = fdopen(fd, "r"); CATCHUNIX(input == NULL ? -1 : 0); CATCHUNIX(setvbuf(input, malloc(1LL<<20), _IOFBF, (1LL<<20))); i1 = 0; while (fread(&i2, sizeof(i2), 1, input) > 0) { if (i2 < i1) { fprintf(stdout, "for bytes %zu:%zu: not sorted!\n", n, n+1); exit(EXIT_FAILURE); } i1 = i2; n += 1; } assert(feof(input)); fprintf(stdout, "sorted!\n"); } else if (strcmp(argv[1], "isort") == 0) { int fd; struct stat buf; /* sort isort <output> <input> */ CATCHUNIX(fd = open(argv[3], O_RDONLY)); CATCHUNIX(fstat(fd, &buf)); void *input = mmap(NULL, (size_t)buf.st_size, PROT_READ, MAP_SHARED, fd, 0); CATCHUNIX(input == MAP_FAILED ? -1 : 0); CATCHUNIX(close(fd)); CATCHUNIX(fd = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)); CATCHUNIX(ftruncate(fd, buf.st_size)); void *output = mmap(NULL, (size_t)buf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); CATCHUNIX(output == MAP_FAILED ? -1 : 0); CATCHUNIX(close(fd)); memcpy(output, input, (size_t)buf.st_size); qsort(output, buf.st_size/sizeof(uint64_t), sizeof(uint64_t), compare); } else if (strcmp(argv[1], "split") == 0) { int fd; struct stat buf; size_t count; /* sort split <input> <output1> <output2> */ CATCHUNIX(fd = open(argv[2], O_RDONLY)); CATCHUNIX(fstat(fd, &buf)); assert(buf.st_size % sizeof(uint64_t) == 0); assert(buf.st_size/2 % sizeof(uint64_t) == 0); FILE *input = fdopen(fd, "r"); CATCHUNIX(input == NULL ? -1 : 0); CATCHUNIX(setvbuf(input, malloc(1LL<<20), _IOFBF, (1LL<<20))); FILE *output1 = fopen(argv[3], "w"); CATCHUNIX(output1 == NULL ? -1 : 0); CATCHUNIX(setvbuf(output1, malloc(1LL<<20), _IOFBF, (1LL<<20))); for (count = 0; count < buf.st_size/sizeof(uint64_t)/2; count++) { uint64_t i; size_t n; n = fread(&i, sizeof(i), 1, input); CATCHUNIX(n == 0 && (errno = ferror(input)) ? -1 : 0); assert(n == 1); n = fwrite(&i, sizeof(i), 1, output1); CATCHUNIX(n == 0 && (errno = ferror(output1)) ? -1 : 0); } fclose(output1); FILE *output2 = fopen(argv[4], "w"); CATCHUNIX(output2 == NULL ? -1 : 0); CATCHUNIX(setvbuf(output2, malloc(1LL<<20), _IOFBF, (1LL<<20))); for (count = 0; count < buf.st_size/sizeof(uint64_t)/2; count++) { uint64_t i; size_t n; n = fread(&i, sizeof(i), 1, input); CATCHUNIX(n == 0 && (errno = ferror(input)) ? -1 : 0); assert(n == 1); n = fwrite(&i, sizeof(i), 1, output2); CATCHUNIX(n == 0 && (errno = ferror(output2)) ? -1 : 0); } fclose(output2); fclose(input); } else if (strcmp(argv[1], "merge") == 0) { int fd; struct stat buf1, buf2; /* sort merge <output> <input1> <input2> */ CATCHUNIX(fd = open(argv[3], O_RDONLY)); CATCHUNIX(fstat(fd, &buf1)); assert(buf1.st_size % sizeof(uint64_t) == 0); FILE *input1 = fdopen(fd, "r"); CATCHUNIX(input1 == NULL ? -1 : 0); CATCHUNIX(setvbuf(input1, malloc(1LL<<20), _IOFBF, (1LL<<20))); CATCHUNIX(fd = open(argv[4], O_RDONLY)); CATCHUNIX(fstat(fd, &buf2)); assert(buf2.st_size % sizeof(uint64_t) == 0); FILE *input2 = fdopen(fd, "r"); CATCHUNIX(input2 == NULL ? -1 : 0); CATCHUNIX(setvbuf(input2, malloc(1LL<<20), _IOFBF, (1LL<<20))); CATCHUNIX(fd = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)); assert((buf1.st_size+buf2.st_size) % sizeof(uint64_t) == 0); FILE *output = fdopen(fd, "w"); CATCHUNIX(output == NULL ? -1 : 0); CATCHUNIX(setvbuf(output, malloc(1LL<<20), _IOFBF, (1LL<<20))); { uint64_t i1, i2; size_t n; n = fread(&i1, sizeof(i1), 1, input1); CATCHUNIX(n == 0 && (errno = ferror(input1)) ? -1 : 0); n = fread(&i2, sizeof(i2), 1, input2); CATCHUNIX(n == 0 && (errno = ferror(input2)) ? -1 : 0); while (1) { if (i1 <= i2) { n = fwrite(&i1, sizeof(i1), 1, output); CATCHUNIX(n == 0 && (errno = ferror(output)) ? -1 : 0); n = fread(&i1, sizeof(i1), 1, input1); CATCHUNIX(n == 0 && (errno = ferror(input1)) ? -1 : 0); if (n == 0) { while (1) { n = fread(&i2, sizeof(i2), 1, input2); CATCHUNIX(n == 0 && (errno = ferror(input2)) ? -1 : 0); if (n == 1) { n = fwrite(&i2, sizeof(i2), 1, output); CATCHUNIX(n == 0 && (errno = ferror(output)) ? -1 : 0); } else { break; } } break; } } else { n = fwrite(&i2, sizeof(i2), 1, output); CATCHUNIX(n == 0 && (errno = ferror(output)) ? -1 : 0); n = fread(&i2, sizeof(i2), 1, input2); CATCHUNIX(n == 0 && (errno = ferror(input2)) ? -1 : 0); if (n == 0) { while (1) { n = fread(&i1, sizeof(i1), 1, input1); CATCHUNIX(n == 0 && (errno = ferror(input1)) ? -1 : 0); if (n == 1) { n = fwrite(&i1, sizeof(i1), 1, output); CATCHUNIX(n == 0 && (errno = ferror(output)) ? -1 : 0); } else { break; } } break; } } } assert(feof(input1) && feof(input2)); fclose(input1); fclose(input2); fclose(output); } } else { exit(EXIT_FAILURE); } return 0; }
static int interpolate (chirp_jobid_t id, char task_path[CHIRP_PATH_MAX], char serv_path[CHIRP_PATH_MAX]) { int rc; char *mark; for (mark = serv_path; (mark = strchr(mark, '%')); ) { switch (mark[1]) { case 'g': case 'h': case 's': { /* replace with hash of task_path */ unsigned char digest[SHA1_DIGEST_LENGTH]; if (mark[1] == 'h') CATCHUNIX(sha1_file(task_path, digest) ? 0 : -1); else if (mark[1] == 'g') sqlite3_randomness(SHA1_DIGEST_LENGTH, digest); else if (mark[1] == 's') { struct stat64 buf; CATCHUNIX(stat64(task_path, &buf)); if (buf.st_size <= MAX_SIZE_HASH) { CATCHUNIX(sha1_file(task_path, digest) ? 0 : -1); } else { sqlite3_randomness(SHA1_DIGEST_LENGTH, digest); } } if (strlen(serv_path)+sizeof(digest)*2 < CHIRP_PATH_MAX) { size_t i; memmove(mark+sizeof(digest)*2, mark+2, strlen(mark+2)+1); for (i = 0; i < sizeof(digest); i++) { char hex[3]; CATCHUNIX(snprintf(hex, sizeof(hex), "%02X", (unsigned int)digest[i])); assert(rc == 2); mark[i*2] = hex[0]; mark[i*2+1] = hex[1]; } mark += sizeof(digest)*2; } else { CATCH(ENAMETOOLONG); } break; } case 'j': { char str[64]; CATCHUNIX(snprintf(str, sizeof(str), "%" PRICHIRP_JOBID_T, id)); assert((size_t)rc < sizeof(str)); if (strlen(serv_path)+strlen(str) < CHIRP_PATH_MAX) { memmove(mark+strlen(str), mark+2, strlen(mark+2)+1); memcpy(mark, str, strlen(str)); mark += strlen(str); } else { CATCH(ENAMETOOLONG); } break; } default: mark += 1; /* ignore */ break; } } rc = 0; goto out; out: return rc; }
static int bindfile (sqlite3 *db, chirp_jobid_t id, const char *subject, const char *sandbox, struct url_binding **urlsp, const char *task_path, const char *serv_path, const char *binding, const char *type, enum BINDSTATE mode) { static const char SQL[] = "UPDATE JobFile" " SET serv_path = ?, size = ?" " WHERE id = ? AND task_path = ? AND type = 'OUTPUT'"; int rc; sqlite3_stmt *stmt = NULL; const char *current = SQL; char task_path_resolved[CHIRP_PATH_MAX] = ""; char serv_path_interpolated[CHIRP_PATH_MAX] = ""; char serv_path_resolved[CHIRP_PATH_MAX] = ""; char task_path_dir[CHIRP_PATH_MAX] = ""; /* directory containing task_path_resolved */ CATCHUNIX(snprintf(task_path_resolved, sizeof(task_path_resolved), "%s/%s", sandbox, task_path)); if ((size_t)rc >= sizeof(task_path_resolved)) CATCH(ENAMETOOLONG); path_dirname(task_path_resolved, task_path_dir); if (strcmp(binding, "URL") == 0) { if (strcmp(type, "INPUT") != 0) CATCH(EINVAL); if (mode == BOOTSTRAP) { debug(D_DEBUG, "binding `%s' for future URL fetch `%s'", task_path, serv_path); CATCHUNIX(create_dir(task_path_dir, S_IRWXU) ? 0 : -1); struct url_binding *url = malloc(sizeof(struct url_binding)); CATCHUNIX(url ? 0 : -1); memset(url, 0, sizeof(struct url_binding)); strncpy(url->path, "", sizeof(url->path)); url->url = NULL; url->next = *urlsp; *urlsp = url; CATCHUNIX(snprintf(url->path, sizeof(url->path), "%s", task_path)); CATCHUNIX((url->url = strdup(serv_path)) ? 0 : -1); } rc = 0; goto out; } strncpy(serv_path_interpolated, serv_path, sizeof(serv_path_interpolated)-1); if (mode == STRAPBOOT && strcmp(type, "OUTPUT") == 0) CATCH(interpolate(id, task_path_resolved, serv_path_interpolated)); serv_path = serv_path_interpolated; CATCH(chirp_fs_local_resolve(serv_path, serv_path_resolved)); if (mode == BOOTSTRAP) { debug(D_DEBUG, "binding `%s' as `%s'", task_path, serv_path); CATCHUNIX(create_dir(task_path_dir, S_IRWXU) ? 0 : -1); if (strcmp(type, "INPUT") == 0) { if (strcmp(binding, "LINK") == 0) { CATCHUNIX(link(serv_path_resolved, task_path_resolved)); } else if (strcmp(binding, "COPY") == 0) { CATCHUNIX(copy_file_to_file(serv_path_resolved, task_path_resolved)); } else assert(0); CATCHUNIX(chmod(serv_path_resolved, S_IRWXU)); } } else if (mode == STRAPBOOT) { if (strcmp(type, "OUTPUT") == 0) { struct stat info; debug(D_DEBUG, "binding output file `%s' as `%s'", task_path, serv_path); if (strcmp(binding, "LINK") == 0) { CATCHUNIXIGNORE(unlink(serv_path_resolved), ENOENT); /* ignore error/success */ CATCHUNIX(link(task_path_resolved, serv_path_resolved)); } else if (strcmp(binding, "COPY") == 0) { CATCHUNIXIGNORE(unlink(serv_path_resolved), ENOENT); CATCHUNIX(copy_file_to_file(task_path_resolved, serv_path_resolved)); } if (stat(serv_path_resolved, &info) == 0) { sqlcatch(sqlite3_prepare_v2(db, current, -1, &stmt, ¤t)); sqlcatch(sqlite3_bind_text(stmt, 1, serv_path, -1, SQLITE_STATIC)); sqlcatch(sqlite3_bind_int64(stmt, 2, info.st_size)); sqlcatch(sqlite3_bind_int64(stmt, 3, (sqlite3_int64)id)); sqlcatch(sqlite3_bind_text(stmt, 4, task_path, -1, SQLITE_STATIC)); sqlcatchcode(sqlite3_step(stmt), SQLITE_DONE); sqlcatch(sqlite3_finalize(stmt); stmt = NULL); } } } else assert(0);
int shellcode(const char *cmd, const char * const env[], const char *input, size_t len, buffer_t *Bout, buffer_t *Berr, int *status) { int rc; int in[2] = {-1, -1}; int out[2] = {-1, -1}; int err[2] = {-1, -1}; pid_t child = 0; const char * const _env[] = {NULL}; struct timeval start, stop; gettimeofday(&start, NULL); if (env == NULL) env = _env; CATCHUNIX(pipe(in)); CATCHUNIX(pipe(out)); CATCHUNIX(pipe(err)); CATCHUNIX(child = fork()); if(child == 0) { return execute(cmd, env, in, out, err); } CATCHUNIX(close(in[0])); in[0] = -1; CATCHUNIX(close(out[1])); out[1] = -1; CATCHUNIX(close(err[1])); err[1] = -1; CATCHUNIX(fcntl(in[1], F_GETFL)); CATCHUNIX(fcntl(in[1], F_SETFL, rc|O_NONBLOCK)); CATCHUNIX(fcntl(out[0], F_GETFL)); CATCHUNIX(fcntl(out[0], F_SETFL, rc|O_NONBLOCK)); CATCHUNIX(fcntl(err[0], F_GETFL)); CATCHUNIX(fcntl(err[0], F_SETFL, rc|O_NONBLOCK)); while (1) { char b[1<<16]; pid_t w; ssize_t result; CATCHUNIX(w = waitpid(child, status, WNOHANG)); if (len) { result = write(in[1], input, len); if (result == -1 && errno != EAGAIN && errno != EINTR) { CATCH(errno); } else if (result > 0) { input += result; len -= (size_t)result; } } else if (in[1] >= 0) { close(in[1]); in[1] = -1; } result = read(out[0], b, sizeof(b)); if (result == -1 && errno != EAGAIN && errno != EINTR) { CATCH(errno); } else if (result > 0 && Bout) { buffer_putlstring(Bout, b, (size_t)result); } result = read(err[0], b, sizeof(b)); if (result == -1 && errno != EAGAIN && errno != EINTR) { CATCH(errno); } else if (result > 0 && Berr) { buffer_putlstring(Berr, b, (size_t)result); } if (w == child) break; } child = 0; rc = 0; goto out; out: if (child > 0) { kill(child, SIGKILL); waitpid(child, NULL, 0); } if (in[0] >= 0) close(in[0]); if (in[1] >= 0) close(in[1]); if (out[0] >= 0) close(out[0]); if (out[1] >= 0) close(out[1]); if (err[0] >= 0) close(err[0]); if (err[1] >= 0) close(err[1]); gettimeofday(&stop, NULL); debug(D_DEBUG, "shellcode finished in %.2fs", (double)(stop.tv_sec-start.tv_sec) + (stop.tv_usec-start.tv_usec)*1e-6); return RCUNIX(rc); }