static void build_path(const char *dir, int pid, const char *ext, char *path) { assert(path); int len = sprintf(path, "%s/diagonal%d.%s", dir, (int)pid, ext); if (len < 0) diag_fatal("fail to build path"); if (PATH_LENGTH <= len) diag_fatal("exceed PATH_LENGTH"); }
hash_table * hash_table_new(hash_func hash_f, hash_comp hash_c, hash_free hash_fr) { hash_table *hash_t; hash_t = (struct _hash_table *) diag_malloc(sizeof(hash_table)); if (hash_t == NULL) diag_fatal("Unable to allocate memory\n"); hash_t->size = HASH_TABLE_MIN_SIZE; hash_t->nnodes = 0; if (hash_f) hash_t->hash_func = default_hash_func; else hash_t->hash_func = hash_f; if (hash_c) hash_t->hash_comp = default_compare_func; else hash_t->hash_comp = hash_c; hash_t->hash_free = hash_fr; hash_t->nodes = (hash_node **) diag_malloc(sizeof(hash_node *) * hash_t->size); if (hash_t->nodes == NULL) { diag_free(hash_t); diag_fatal("Unable to allocate memory\n"); } memset(hash_t->nodes, 0, sizeof(hash_node *) * hash_t->size); return hash_t; }
intptr_t diag_list_ref(const struct diag_pair *list, size_t i) { if (!list) diag_fatal("list is null"); while (i-- > 0) { list = (const struct diag_pair *)list->cdr; if (!list) diag_fatal("exceed list length"); } return list->car; }
void diag_process_wait(struct diag_process *process) { assert(process); int status; pid_t pid = waitpid((pid_t)process->pid, &status, #ifdef WCONTINUED WCONTINUED| #endif WUNTRACED); if (pid == (pid_t)0) { assert(0); } else if (pid == (pid_t)-1) { perror(NULL); diag_fatal("failed to wait process: %d", (int)process->pid); } if (WIFEXITED(status)) { process->status = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { process->status = -1; } else if (WIFSTOPPED(status)) { #ifdef WIFCONTINUED } else if (WIFCONTINUED(status)) { #endif } }
long hash_table_replace(hash_table * hash_t, void *key, void *value) { hash_node **node; hash_node *pnode; long hash_val; node = hash_table_lookup_node(hash_t, key); if (node) (*node)->value = value; else { *node = (hash_node *) diag_malloc(sizeof(hash_node)); if (*node == NULL) diag_fatal("Unable to allocate memory\n"); (*node)->key = key; (*node)->value = value; hash_val = (*hash_t->hash_func) ((*node)->key, hash_t->size); (*node)->next = hash_t->nodes[hash_val]; hash_t->nodes[hash_val] = (*node); hash_t->nnodes++; pnode = *node; hash_table_resize(hash_t); } return (long) pnode; }
/* * TODO: n should exceed MAXIMUM_WAIT_OBJECTS * http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx */ int diag_wait_agent(int n, const intptr_t *agents, int *code) { assert(n > 0); assert(agents); if (n > MAXIMUM_WAIT_OBJECTS) { diag_error("number of agents exceeds MAXIMUM_WAIT_OBJECTS"); return -1; } DWORD r = WaitForMultipleObjects((DWORD)n, (const HANDLE *)agents, FALSE, INFINITE); assert(r != WAIT_TIMEOUT); if (r == WAIT_FAILED) { diag_error("failed to wait agent: %x", (unsigned int)GetLastError()); return -1; } assert(WAIT_OBJECT_0 == 0); if (WAIT_OBJECT_0 + (DWORD)n <= r) { diag_fatal("failed to wait agent"); } DWORD i = r - WAIT_OBJECT_0; intptr_t p = agents[i]; if (code) { DWORD c = 0; if (GetExitCodeProcess((HANDLE)p, &c) == 0) { diag_fatal("failed to get exit code: %x", (unsigned int)GetLastError()); } *code = (int)c; } if (CloseHandle((HANDLE)p) == 0) { diag_error("failed to close handle"); } return (int)i; }
struct diag_command *diag_command_new(char **argv, const char *dir, const char *in, const char *out, const char *err) { struct diag_command *command = diag_malloc(sizeof(*command)); size_t argc; for (argc = 0; argv[argc]; argc++) ; command->argv = diag_calloc(argc + 1, sizeof(char *)); size_t i; for (i = 0; i < argc; i++) { command->argv[i] = diag_strdup(argv[i]); } command->argv[argc] = NULL; /* NULL-terminated */ command->file = argv[0]; if (dir) { command->dir = diag_strdup(dir); } else { command->dir = diag_malloc(PATH_LENGTH); char *p; #if defined(_WIN32) && defined(__MINGW32__) p = _getcwd(command->dir, PATH_LENGTH); #elif defined(HAVE_UNISTD_H) p = getcwd(command->dir, PATH_LENGTH); #endif if (!p) { perror(NULL); diag_fatal("failed to get current working directory"); } } if (in) { command->in = diag_strdup(in); } else { command->in = NULL; } if (out) { command->out = diag_strdup(out); } else { command->out = NULL; } if (err) { command->err = diag_strdup(err); } else { command->err = NULL; } return command; }
intptr_t diag_run_agent(char **argv) { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; STARTUPINFO si; GetStartupInfo(&si); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); char *line = diag_get_command_line(argv); BOOL b = CreateProcess(NULL, line, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); if (!b) { diag_fatal("could not create process: %s: 0x%x", line, (unsigned int)GetLastError()); } /* We do not want WaitForInputIdle() because there is no interaction between the parent process and this child */ diag_free(line); CloseHandle(pi.hThread); return (intptr_t)pi.hProcess; }
long hash_table_insert(hash_table * hash_t, void *key, void *value) { hash_node **node; hash_node *pnode; node = hash_table_lookup_node(hash_t, key); if (!*node) { *node = (hash_node *) diag_malloc(sizeof(hash_node)); if (*node == NULL) diag_fatal("Unable to allocate memory\n"); (*node)->key = key; (*node)->value = value; (*node)->next = NULL; hash_t->nnodes++; pnode = *node; hash_table_resize(hash_t); } return (long) pnode; }
int main(int argc, char *argv[]) { int c; int n = 0; int r = EXIT_FAILURE; char *in = NULL; diag_init(); while ( (c = getopt(argc, argv, "+Vhi:n:")) >=0) { switch (c) { case 'V': diag_print_version(); exit(EXIT_SUCCESS); break; case 'h': usage(); exit(EXIT_SUCCESS); break; case 'i': in = optarg; break; case 'n': n = atoi(optarg); if (n < 0) { diag_fatal("non-negative integer expected, but %d", n); } else if (n == 0) { exit(EXIT_SUCCESS); } break; case ':': case '?': usage(); exit(EXIT_FAILURE); break; } } if (!argv[optind]) { usage(); exit(EXIT_FAILURE); } if (n == 0) { diag_fatal("please specify the number with the -n option"); } char *tfin = NULL; if (!in) { struct diag_temporary_file *tf = diag_temporary_file_new(); if (!tf) { return EXIT_FAILURE; } tfin = diag_strdup(tf->path); struct diag_port *ip = diag_port_new_stdin(); assert(ip); ssize_t s = diag_port_copy(ip, tf->port); diag_port_destroy(ip); diag_temporary_file_destroy(tf); if (s < 0) { assert(tfin); diag_remove(tfin); diag_free(tfin); return EXIT_FAILURE; } } int i = 0; char *file = in ? in : tfin; struct diag_command *cmd; run: cmd = diag_command_new(argv + optind, NULL, file, NULL, NULL); if (!cmd) { goto done; } struct diag_process *p = diag_run_program(cmd); if (!p) { goto done; } diag_process_wait(p); int status = p->status; diag_process_destroy(p); if (status != 0) { r = status; goto done; } assert(cmd->err); diag_remove(cmd->err); if (i) { diag_remove(file); diag_free(file); } else if (tfin) { diag_remove(tfin); diag_free(tfin); tfin = NULL; } if (++i < n) { file = diag_strdup(cmd->out); diag_command_destroy(cmd); goto run; } struct diag_port *ip = diag_port_new_path(cmd->out, "rb"); if (!ip) { goto done; } struct diag_port *op = diag_port_new_stdout(); assert(op); ssize_t s = diag_port_copy(ip, op); diag_port_destroy(op); diag_port_destroy(ip); if (s < 0) { goto done; } diag_remove(cmd->out); r = EXIT_SUCCESS; done: diag_command_destroy(cmd); if (tfin) { diag_remove(tfin); diag_free(tfin); } return r; }