/* Report an error to the user and return EXECUTION_FAILURE. */ int mpibash_report_mpi_error (int mpierr) { char errstr[MPI_MAX_ERROR_STRING]; int errstrlen; MPI_Error_string(mpierr, errstr, &errstrlen); builtin_error("%s", errstr); return EXECUTION_FAILURE; }
int b_history(t_context *context, t_list *args) { size_t arg_count; arg_count = ft_lstsize(args); if (arg_count > 3) return (builtin_error(HISTORY_BUILTIN, ERR_TOO_MANY_ARGS, 0)); if (arg_count == 1) return (history_display(context, 0, 0)); return (BUILTIN_SUCCESS); }
int b_pid(t_context *context, t_list *args) { size_t arg_count; UNUSED(context); arg_count = ft_lstsize(args); if (arg_count > 1) return (builtin_error(PID_BUILTIN, ERR_TOO_MANY_ARGS, 0)); ft_putnbr(getpid()); ft_putchar('\n'); return (BUILTIN_SUCCESS); }
int b_exit(t_context *context, t_list *args) { size_t arg_count; int exit_code; arg_count = ft_lstsize(args); if (arg_count > 2) return (builtin_error(EXIT_BUILTIN, ERR_TOO_MANY_ARGS, 0)); exit_code = EXIT_SUCCESS; if (arg_count == 2) exit_code = ft_atoi(token_value(args, 2)); shell_exit(context, exit_code); return (BUILTIN_SUCCESS); }
int b_unsetenv(t_context *context, t_list *args) { size_t arg_count; size_t i; arg_count = ft_lstsize(args); if (arg_count == 1) return (builtin_error(UNSETENV_BUILTIN, ERR_TOO_FEW_ARGS, 0)); i = 1; while (i < arg_count) { environ_remove(context, token_value(args, i + 1)); ++i; } return (BUILTIN_SUCCESS); }
// Given an appropriate format and an ffi_type, create a prefixed type from // value and store in *result, which should be freed by the caller. char * encode_primitive_type(const char *format, ffi_type *type, void *value) { char *result; switch (type->size) { case 1: asprintf(&result, format, *(uint8_t *) value); break; case 2: asprintf(&result, format, *(uint16_t *) value); break; case 4: asprintf(&result, format, *(uint32_t *) value, *(float *) value); break; case 8: asprintf(&result, format, *(uint64_t *) value, *(double *) value); break; case 16: asprintf(&result, format, *(long double *) value); break; default: builtin_error("cannot handle size %lu", type->size); return NULL; } return result; }
/* Look up a user-provided callback function. */ int mpibash_find_callback_function (WORD_LIST *list, SHELL_VAR **user_func) { char *funcname; /* Name of the user-defined function. */ /* If no argument was provided, nullify the callback function. */ if (list == NULL) { *user_func = NULL; return EXECUTION_SUCCESS; } /* Get the callback function. */ funcname = list->word->word; list = list->next; no_args(list); *user_func = find_function(funcname); if (*user_func == NULL) { builtin_error(_("function %s not found"), funcname); return EXECUTION_FAILURE; } return EXECUTION_SUCCESS; }
// Usage: // // dlopen [-N] [-t] [-d] [-g] [-n] [library] [RTLD_NODELETE|RTLD_GLOBAL|...] [...] // static int open_dynamic_library(WORD_LIST *list) { char varname[1024]; char value[1024]; uint32_t flags; void *handle; int opt; reset_internal_getopt(); flags = RTLD_LAZY; handle = NULL; // Options can either be specified as bash-like flags, or as a list. The // bash-like flags look like this: // // $ dlopen -tg libc.so // while ((opt = internal_getopt(list, "lNtdgn")) != -1) { switch (opt) { // RTLD_LAZY and RTLD_NOW are mutually exclusive. case 'l': flags = (flags & ~RTLD_NOW) | RTLD_LAZY; break; case 'N': flags = (flags & ~RTLD_LAZY) | RTLD_NOW; break; case 't': flags |= RTLD_NOLOAD; break; case 'd': flags |= RTLD_DEEPBIND; break; case 'g': flags |= RTLD_GLOBAL; break; case 'n': flags |= RTLD_NODELETE; break; default: builtin_usage(); return EX_USAGE; } } // Skip past any options. if ((list = loptend) == NULL) { builtin_usage(); return 1; } // Check and decode parameters, which can be specified as strings. // // $ dlopen libc.so RTLD_LAZY RTLD_NODELETE // // or, as an integer // // $ dlopen libc.so 0x10101 // if (list->next) { WORD_LIST *flaglist = list->next; // Caller wants more control over flags, so reset and decode the flags // specified. for (flags = 0; flaglist; flaglist = flaglist->next) { flags |= rtld_flags_decode(flaglist->word->word); } } // Now list->word is the library name. if (!(handle = dlopen(list->word->word, flags))) { builtin_error("dlopen(\"%s\", %#x) failed, %s", list->word->word, flags, dlerror()); return 1; } // Print the handle, although this is not usable unless being used interactively. printf("%p\n", handle); snprintf(varname, sizeof varname, "DLHANDLES[\"%s\"]", basename(list->word->word)); snprintf(value, sizeof value, "%p", handle); // Make the handle available programmatically. if (assign_array_element(varname, value, 4) == NULL) { builtin_error("failed to append element to $DLHANDLES array"); return 1; } return 0; }
// Usage: // // dlcall $RTLD_DEFAULT "printf" "hello %s %u %c" $USER 123 int:10 // static int call_foreign_function(WORD_LIST *list) { unsigned nargs; int opt; ffi_cif cif; ffi_type **argtypes; ffi_type *rettype; void **values; void *handle; void *func; char *prefix; char *format; char *resultname; nargs = 0; argtypes = NULL; values = NULL; format = NULL; prefix = NULL; rettype = &ffi_type_void; resultname = "DLRETVAL"; reset_internal_getopt(); // $ dlcall [-a abi] [-r type] [-n name] while ((opt = internal_getopt(list, "a:r:n:")) != -1) { switch (opt) { case 'a': builtin_warning("FIXME: only abi %u is currently supported", FFI_DEFAULT_ABI); return 1; break; case 'r': if (decode_type_prefix(prefix = list_optarg, NULL, &rettype, NULL, &format) != true) { builtin_warning("failed to parse return type"); return 1; } break; case 'n': resultname = list_optarg; break; default: builtin_usage(); return 1; } } // Skip past any options. if ((list = loptend) == NULL || list->next == NULL) { builtin_usage(); return 1; } if (check_parse_ulong(list->word->word, (void *) &handle) == 0) { builtin_warning("handle %s %p is not well-formed", list->word->word, handle); return 1; } if (!(func = dlsym(handle, list->next->word->word))) { builtin_warning("failed to resolve symbol %s, %s", list->next->word->word, dlerror()); return 1; } // Skip to optional parameters list = list->next->next; while (list) { argtypes = realloc(argtypes, (nargs + 1) * sizeof(ffi_type *)); values = realloc(values, (nargs + 1) * sizeof(void *)); if (decode_primitive_type(list->word->word, &values[nargs], &argtypes[nargs]) != true) { builtin_error("failed to decode type from parameter %s", list->word->word); goto error; } nargs++; list = list->next; } if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, rettype, argtypes) == FFI_OK) { char *retval; void *rc = alloca(rettype->size); // Do the call. ffi_call(&cif, func, rc, values); // Print the result. if (format) { switch (rettype->size) { case 1: asprintf(&retval, format, *(uint8_t *) rc); break; case 2: asprintf(&retval, format, *(uint16_t *) rc); break; case 4: asprintf(&retval, format, *(uint32_t *) rc, *(float *) rc); break; case 8: asprintf(&retval, format, *(uint64_t *) rc, *(double *) rc); break; case 16: asprintf(&retval, format, *(long double *) rc); break; default: builtin_error("cannot handle size %lu", rettype->size); abort(); } fprintf(stderr, "%s\n", retval); bind_variable(resultname, retval, 0); free(retval); } } for (unsigned i = 0; i < nargs; i++) free(values[i]); free(values); free(argtypes); return 0; error: for (unsigned i = 0; i < nargs; i++) free(values[i]); free(values); free(argtypes); return 1; }
/************************** *** CLIENT LISTENING THREAD **************************/ void* client_thread(void *socket) { // Get the socket int socket_fd = *((int*)socket); // Redirect SIGUSR signal sigset_t mask; sigset_t fdmask; // Handle SIGUSR1 sigemptyset(&fdmask); sigaddset(&fdmask, SIGUSR1); // We need to block SIGUSR2 and SIGINT to they are handled by main thread sigemptyset(&mask); sigaddset(&mask, SIGUSR2); sigaddset(&mask, SIGINT); // Block SIGUSR1/2 SIGINT if(pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) { if(close(socket_fd) < 0) { ERROR("Can't close client socket", strerror(errno)); } ERROR("Can't block signal in client thread", strerror(errno)); pthread_mutex_lock(&client_count_mutex); --client_count; pthread_mutex_unlock(&client_count_mutex); return NULL; } // Block SIGUSR1 if(pthread_sigmask(SIG_BLOCK, &fdmask, NULL) < 0) { if(close(socket_fd) < 0) { ERROR("Can't close client socket", strerror(errno)); } ERROR("Can't block signal in client thread", strerror(errno)); pthread_mutex_lock(&client_count_mutex); --client_count; pthread_mutex_unlock(&client_count_mutex); return NULL; } // Redirect SIGUSR1 to fd int sigusr_fd = signalfd(-1, &fdmask, 0); if(sigusr_fd < 0) { if(close(socket_fd) < 0) { ERROR("Can't close client socket", strerror(errno)); } ERROR("Can't redirect signal in client thread", strerror(errno)); pthread_mutex_lock(&client_count_mutex); --client_count; pthread_mutex_unlock(&client_count_mutex); return NULL; } // Message management char message[MAX_BUF]; char *saved_decomp; // Buffering management int buffering = FALSE; char message_buffer[MAX_BUF]; // Sockets set fd_set in_desc; // Timeout setting struct timeval timeout_set; timeout_set.tv_sec = TIMEOUT_V; timeout_set.tv_usec = 1000 * TIMEOUT_V; int listening = TRUE; int usrquit = FALSE; while(listening) { // Setting the file desciptors set FD_ZERO(&in_desc); FD_SET(sigusr_fd, &in_desc); FD_SET(socket_fd, &in_desc); int max = sigusr_fd; if(sigusr_fd < socket_fd) max = socket_fd; // Select the socket to watch if(select(max + 1, &in_desc , NULL , NULL , &timeout_set) < 0 && (errno != EINTR)) { ERROR("Error while selecting client sockets", strerror(errno)); if(close(socket_fd) < 0) { ERROR("Can't close client socket", strerror(errno)); } pthread_mutex_lock(&client_count_mutex); --client_count; pthread_mutex_unlock(&client_count_mutex); return NULL; } // If received SIGUSR1 if(FD_ISSET(sigusr_fd, &in_desc)) { struct signalfd_siginfo si; ssize_t length; // Read signal if((length = read(sigusr_fd, &si, sizeof(si))) < 0) { ERROR("Error while reading sigusr1 file descriptor", strerror(errno)); } if (length != sizeof(si)) { ERROR("Error while reading sigusr1 file descriptor", strerror(errno)); } // Handle signal if (si.ssi_signo == SIGUSR1) { // Stop listening and get out of loop char message[17] = "Server shutdown\n\0"; send_to(socket_fd, message); listening = FALSE; usrquit = TRUE; break; } else { ERROR("Error, received an unhandled signal", "UNKNOWN SIGNAL"); } } // If client socket changed state if(FD_ISSET(socket_fd, &in_desc)) { size_t length; memset(message, 0, sizeof(message)); if((length = read(socket_fd, &message, MAX_BUF)) > 0) { // Manage command buffering if(message[length - 1] != '\n') { if(!buffering) message_buffer[0] = '\0'; // Fill buffer buffering = TRUE; strncat(message_buffer, message, length); continue; } else if(buffering) { // Get all buffer value buffering = FALSE; strncat(message_buffer, message, length); strncpy(message, message_buffer, strlen(message_buffer)); } // Manage multiple command per line char *saved_decomp; char *decomp_command = strtok_r(message, "\n", &saved_decomp); while(decomp_command) { // Get command char *saved_ptr; char *command = strtok_r(decomp_command, " ", &saved_ptr); // Get function int (*function) (void*, void*) = NULL; { int i; for(i = 0; bltins[i].cmd; ++i) { if(strcmp(bltins[i].cmd, command) == 0) { function = bltins[i].function; break; } } } if(function != NULL) { void *state = NULL; size_t arguments_count = 1; size_t arguments_remai = 1; size_t argc = 0; // Init arguments structure struct args_s *arguments_s = malloc(sizeof(struct args_s)); arguments_s->socket = socket_fd; arguments_s->args = malloc(sizeof(char*) * arguments_count); // Get arguments char *parameters = strtok_r(NULL, "", &saved_ptr); while(parameters) { char *argument = strtok_r(parameters, " ", &saved_ptr); // Dynamic allocation if(arguments_remai-- == 0) { arguments_remai = arguments_count; arguments_count *= 2; arguments_s->args = realloc(arguments_s->args, sizeof(char*) * arguments_count); } // Add argument arguments_s->args[argc] = malloc(sizeof(char) * strlen(argument) + 1); arguments_s->args[argc][0] = '\0'; strncpy(arguments_s->args[argc], argument, strlen(argument)); arguments_s->args[argc][strlen(argument)] = '\0'; ++argc; parameters = strtok_r(NULL, "", &saved_ptr); } // End the args array with NULL if(arguments_remai) { arguments_s->args[argc] = NULL; } else { arguments_s->args = realloc(arguments_s->args, sizeof(char*) * argc + 1); arguments_s->args[argc] = NULL; } // Call function INFO("Client command:"); INFO(command); listening = function(arguments_s, state); // Free memory { int i; for(i = 0; arguments_s->args[i]; ++i) { free(arguments_s->args[i]); } free(arguments_s->args); free(arguments_s); } } else { // Wrong command, log server and avert client WARNING("Client asked for an unknown command", command); struct args_s *arguments_s = malloc(sizeof(struct args_s)); arguments_s->socket = socket_fd; builtin_error(arguments_s , NULL); free(arguments_s); } char *get_back_command = strtok_r(NULL, "", &saved_decomp); decomp_command = strtok_r(get_back_command, "\n", &saved_decomp); } } else if(length == 0) { // Client disconnected listening = FALSE; } else { // Error while reading ERROR("Error while reading socket", strerror(errno)); } } } // Close connection socket if(close(socket_fd) < 0) { ERROR("Can't close client socket", strerror(errno)); } // Close binded signale file descriptor if(close(sigusr_fd) < 0) { ERROR("Can't close client sigusr file descriptor", strerror(errno)); } INFO("Client thread disconnected"); pthread_mutex_lock(&client_count_mutex); --client_count; pthread_mutex_unlock(&client_count_mutex); if(!usrquit) { union sigval sv; sv.sival_int = socket_fd; if(sigqueue(getpid(), SIGUSR2, sv) < 0) { ERROR("Can't send signal to main thread", strerror(errno)); } } return NULL; } // void* client_thread(void*)
/* change working directory * ----------------------------------------------------------------------- */ int builtin_cd(int argc, char **argv) { int c; int ok = 0; int symbolic = 1; const char *arg; unsigned long len; unsigned long n; stralloc newcwd; /* check options, -L for symlink, -P for physical path */ while((c = shell_getopt(argc, argv, "LP")) > 0) { switch(c) { case 'L': symbolic = 1; break; case 'P': symbolic = 0; break; default: builtin_invopt(argv); return 1; } } arg = argv[shell_optind]; stralloc_init(&newcwd); /* empty argument means chdir(HOME) */ if(arg == NULL) { arg = var_value("HOME", &len); if(arg[0] == '\0') { sh_msg("HOME variable not set!"); return 1; } } len = str_len(arg); /* when it isn't an absolute path we have to check CDPATH */ if(arg[0] != '/') { char path[PATH_MAX + 1]; const char *cdpath; /* loop through colon-separated CDPATH variable */ cdpath = var_value("CDPATH", NULL); do { /* too much, too much :) */ if((n = str_chr(cdpath, ':')) + len + 1 > PATH_MAX) { /* set error code and print the longer string in the error msg */ errno = ENAMETOOLONG; return builtin_errmsgn(argv, (n > len ? cdpath : arg), (n > len ? n : len), strerror(errno)); } /* copy path prefix from cdpath if present */ if(n) { byte_copy(path, n, cdpath); cdpath += n; path[n++] = '/'; } /* copy the argument and canonicalize */ str_copy(&path[n], arg); ok = shell_realpath(path, &newcwd, symbolic, &sh->cwd); /* skip the colon */ if(*cdpath == ':') cdpath++; } while(*cdpath && !ok); } /* absolute path */ else { /* last cdpath length set to 0, because we're not using cdpath here */ n = 0; ok = shell_canonicalize(arg, &newcwd, symbolic); } stralloc_nul(&newcwd); /* try to chdir() if everything's ok */ if(ok && chdir(newcwd.s) == 0) { /* print path if prefix was taken from cdpath */ if(n) { buffer_putsa(fd_out->w, &newcwd); buffer_putnlflush(fd_out->w); } /* set the path */ stralloc_move(&sh->cwd, &newcwd); /* if the path has symlinks then set sh->cwdsym */ sh->cwdsym = (ok > 1); return 0; } /* we failed */ builtin_error(argv, newcwd.s); stralloc_free(&newcwd); return 1; }
// Usage: // // dlcall "printf" "hello %s %u %c" $USER 123 int:10 // static int call_foreign_function(WORD_LIST *list) { unsigned nargs; unsigned i; int opt; ffi_cif cif; ffi_type **argtypes; ffi_type *rettype; void **values; void *handle; void *func; char *prefix; char *format; char *resultname; nargs = 0; argtypes = NULL; values = NULL; format = NULL; prefix = NULL; rettype = &ffi_type_void; resultname = "DLRETVAL"; handle = RTLD_DEFAULT; reset_internal_getopt(); // $ dlcall [-a abi] [-r type] [-n name] [-h handle] symbol args... while ((opt = internal_getopt(list, "h:a:r:n:")) != -1) { switch (opt) { case 'a': builtin_warning("FIXME: only abi %u is currently supported", FFI_DEFAULT_ABI); return 1; break; case 'r': if (decode_type_prefix(prefix = list_optarg, NULL, &rettype, NULL, &format) != true) { builtin_warning("failed to parse return type"); return 1; } break; case 'n': resultname = list_optarg; break; case 'h': if (check_parse_ulong(list_optarg, (void *) &handle) == 0) { builtin_warning("handle %s %p is not well-formed", list_optarg, handle); return EXECUTION_FAILURE; } break; default: builtin_usage(); return EX_USAGE; } } // Skip past any options. if ((list = loptend) == NULL) { builtin_usage(); return EX_USAGE; } if (!(func = dlsym(handle, list->word->word))) { builtin_warning("failed to resolve symbol %s, %s", list->word->word, dlerror()); return 1; } // Skip to optional parameters list = list->next; while (list) { argtypes = realloc(argtypes, (nargs + 1) * sizeof(ffi_type *)); values = realloc(values, (nargs + 1) * sizeof(void *)); if (decode_primitive_type(list->word->word, &values[nargs], &argtypes[nargs]) != true) { builtin_error("failed to decode type from parameter %s", list->word->word); goto error; } nargs++; list = list->next; } if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, rettype, argtypes) == FFI_OK) { char *retval; void *rc = alloca(rettype->size); // Do the call. ffi_call(&cif, func, rc, values); // Decode the result. if (format) { retval = encode_primitive_type(format, rettype, rc); // If this is an interactive shell, print the output. if (interactive_shell) { fprintf(stderr, "%s\n", retval); } // Save the result to the requested location. bind_variable(resultname, retval, 0); // Bash maintains it's own copy of this string, so we can throw it away. free(retval); } } for (i = 0; i < nargs; i++) free(values[i]); free(values); free(argtypes); return 0; error: for (i = 0; i < nargs; i++) free(values[i]); free(values); free(argtypes); return 1; }
/* sets or displays current hostname * ----------------------------------------------------------------------- */ int builtin_hostname(int argc, char **argv) { int c; int force = 0; /* check options */ while((c = shell_getopt(argc, argv, "f")) > 0) { switch(c) { case 'f': force = 1; break; default: builtin_invopt(argv); return 1; } } /* if there is an argument we set it as new hostname */ if(argv[shell_optind]) { unsigned long n; n = str_len(argv[shell_optind]); /* unless force is set and if the new hostname is the same as the current then do not update it */ if(!force && n == sh_hostname.len && !byte_diff(sh_hostname.s, n, argv[shell_optind])) return 0; #ifdef HAVE_SETHOSTNAME /* set the supplied hostname */ #if !defined(__CYGWIN__) && !defined(__MINGW32__) if(sethostname(argv[shell_optind], n)) #else errno = ENOSYS; #endif { /* report any error */ builtin_error(argv, "sethostname"); return 1; } #endif /* on success update internal hostname */ stralloc_copyb(&sh_hostname, argv[shell_optind], n); } /* if there is no argument we display the current hostname */ else { /* force re-get of hostname by clearing it now */ if(force) stralloc_zero(&sh_hostname); /* get hostname if it isn't there */ if(sh_hostname.len == 0) shell_gethostname(&sh_hostname); /* report errors */ if(sh_hostname.len == 0) { builtin_error(argv, "gethostname"); return 1; } /* finally output the hostname */ buffer_putsa(fd_out->w, &sh_hostname); buffer_putnlflush(fd_out->w); } return 0; }
static int generate_native_callback(WORD_LIST *list) { int nargs; void *callback; ffi_cif *cif; ffi_closure *closure; ffi_type **argtypes; ffi_type *rettype; char **proto; char *resultname = "DLRETVAL"; char opt; reset_internal_getopt(); // $ dlcall [-a abi] [-r type] [-n name] while ((opt = internal_getopt(list, "a:r:n:")) != -1) { switch (opt) { case 'n': resultname = list_optarg; break; default: builtin_usage(); return EX_USAGE; } } // Skip past any options. if ((list = loptend) == NULL || !list->next) { builtin_usage(); return EX_USAGE; } closure = ffi_closure_alloc(sizeof(ffi_closure), &callback); cif = malloc(sizeof(ffi_cif)); argtypes = NULL; proto = malloc(sizeof(char *)); proto[0] = strdup(list->word->word); nargs = 0; list = list->next; // Second parameter must be the return type if (decode_type_prefix(list->word->word, NULL, &rettype, NULL, NULL) != true) { builtin_warning("couldnt parse the return type %s", list->word->word); return EXECUTION_FAILURE; } // Skip past return type list = list->next; while (list) { argtypes = realloc(argtypes, (nargs + 1) * sizeof(ffi_type *)); proto = realloc(proto, (nargs + 1 + 1) * sizeof(char *)); if (decode_type_prefix(list->word->word, NULL, &argtypes[nargs], NULL, &proto[nargs+1]) != true) { builtin_error("failed to decode type from parameter %s", list->word->word); goto error; } list = list->next; nargs++; } if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, nargs, rettype, argtypes) == FFI_OK) { // Initialize the closure. if (ffi_prep_closure_loc(closure, cif, execute_bash_trampoline, proto, callback) == FFI_OK) { char retval[1024]; snprintf(retval, sizeof retval, "pointer:%p", callback); fprintf(stderr, "%s\n", retval); bind_variable(resultname, retval, 0); } } //free(argtypes); return 0; error: //free(argtypes); return 1; }