/* * Initialization. Works as follows: * * we have a DBusConnection* (say, obtained with dbus_bus_get) * we call dbus_connection_set_watch_functions * libdbus calls back add_watch(watch:0x2341090, data), this watch is for writing * we call toggled_watch, but it finds that watch is not to be enabled yet * libdbus calls back add_watch(watch:0x23410e0, data), this watch is for reading * we call toggled_watch, it adds watch's fd to glib main loop with POLLIN * (note: these watches are different objects, but they have the same fd) * we call dbus_connection_set_timeout_functions * we call dbus_connection_register_object_path * * Note: if user will later call dbus_bus_request_name(conn, ...): * libdbus calls back add_timeout() * libdbus calls back remove_timeout() * note - no callback to timeout_toggled()! * (therefore there is no code yet in timeout_toggled (see above), it's not used) */ void attach_dbus_conn_to_glib_main_loop(DBusConnection* conn, const char* object_path, DBusHandlerResult (*message_received_func)(DBusConnection *conn, DBusMessage *msg, void* data) ) { if (g_dbus_conn) error_msg_and_die("Internal bug: can't connect to more than one dbus"); g_dbus_conn = conn; //do we need this? why? //log("dbus_connection_set_dispatch_status_function"); // dbus_connection_set_dispatch_status_function(conn, // dispatch, /* void dispatch(DBusConnection *conn, DBusDispatchStatus new_status, void* data) */ // NULL, /* data */ // NULL /* free_data_function */ // ) log_debug("dbus_connection_set_watch_functions"); if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggled_watch, NULL, /* data */ NULL /* free_data_function */ ) ) { die_out_of_memory(); } log_debug("dbus_connection_set_timeout_functions"); if (!dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, timeout_toggled, NULL, /* data */ NULL /* free_data_function */ ) ) { die_out_of_memory(); } if (object_path && message_received_func) { /* Table */ const DBusObjectPathVTable vtable = { /* .unregister_function = */ unregister_vtable, /* .message_function = */ message_received_func, }; log_debug("dbus_connection_register_object_path"); if (!dbus_connection_register_object_path(conn, object_path, &vtable, NULL /* data */ ) ) { die_out_of_memory(); } } }
/* helpers */ static DBusMessage* new_signal_msg(const char* member, const char* peer) { /* path, interface, member name */ DBusMessage* msg = dbus_message_new_signal(ABRTD_DBUS_PATH, ABRTD_DBUS_IFACE, member); if (!msg) die_out_of_memory(); /* Send unicast dbus signal if peer is known */ if (peer && !dbus_message_set_destination(msg, peer)) die_out_of_memory(); return msg; }
void *xreallocarray(void *ptr, size_t nmemb, size_t size) { size_t bytes = nmemb * size; if ((nmemb | size) >= HALF_SIZE_T && size && bytes / size != nmemb) die_out_of_memory(); void *p = realloc(ptr, bytes); if (!p) die_out_of_memory(); return p; }
// Die if we can't resize previously allocated memory. (This returns a pointer // to the new memory, which may or may not be the same as the old memory. // It'll copy the contents to a new chunk and free the old one if necessary.) void* xrealloc(void *ptr, size_t size) { ptr = realloc(ptr, size); if (ptr == NULL && size != 0) die_out_of_memory(); return ptr; }
// Die if we can't allocate size bytes of memory. void* xmalloc(size_t size) { void *ptr = malloc(size); if (ptr == NULL && size != 0) die_out_of_memory(); return ptr; }
static void ureport_add_str(struct json_object *ur, const char *key, const char *s) { struct json_object *jstring = json_object_new_string(s); if (!jstring) die_out_of_memory(); json_object_object_add(ur, key, jstring); }
char *xstrdup(const char *str) { char *p = strdup(str); if (!p) die_out_of_memory(); return p; }
void *xcalloc(size_t nmemb, size_t size) { void *p = calloc(nmemb, size); if (!p) die_out_of_memory(); return p; }
void *xmalloc(size_t size) { void *p = malloc(size); if (!p) die_out_of_memory(); return p; }
void store_string(DBusMessageIter* iter, const char* val) { /* dbus daemon will simply close our connection if we send broken utf8. * Therefore we must never do that. */ const char *sanitized = sanitize_utf8(val, /*ctrl:*/ 0); if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, sanitized ? &sanitized : &val)) die_out_of_memory(); free((char*)sanitized); }
// Die if we can't copy a string to freshly allocated memory. char* xstrdup(const char *s) { char *t; if (s == NULL) return NULL; t = strdup(s); if (t == NULL) die_out_of_memory(); return t; }
static void reallocate_qual(const unsigned int n) { unsigned p; qualbits_t *qp; for (p = 0; p < SUPPORTED_PERSONALITIES; p++) { qp = qual_vec[p] = realloc(qual_vec[p], n * sizeof(qualbits_t)); if (!qp) die_out_of_memory(); memset(&qp[num_quals], 0, (n - num_quals) * sizeof(qualbits_t)); } num_quals = n; }
/* * Add a path to the set we're tracing. * Specifying NULL will delete all paths. */ static void storepath(const char *path) { unsigned i; if (pathmatch(path)) return; /* already in table */ i = num_selected++; paths_selected = realloc(paths_selected, num_selected * sizeof(paths_selected[0])); if (!paths_selected) die_out_of_memory(); paths_selected[i] = path; }
char *new_json_attachment(const char *bthash, const char *type, const char *data) { struct json_object *attachment = json_object_new_object(); if (!attachment) die_out_of_memory(); ureport_add_str(attachment, "bthash", bthash); ureport_add_str(attachment, "type", type); ureport_add_str(attachment, "data", data); char *result = xstrdup(json_object_to_json_string(attachment)); json_object_put(attachment); return result; }
void count_syscall(struct tcb *tcp, struct timeval *tv) { if (!SCNO_IN_RANGE(tcp->scno)) return; if (!counts) { counts = calloc(nsyscalls, sizeof(*counts)); if (!counts) die_out_of_memory(); } counts[tcp->scno].calls++; if (tcp->u_error) counts[tcp->scno].errors++; tv_sub(tv, tv, &tcp->etime); if (tv_cmp(tv, &tcp->dtime) > 0) { static struct timeval one_tick; if (one_tick.tv_usec == 0) { /* Initialize it. */ struct itimerval it; memset(&it, 0, sizeof it); it.it_interval.tv_usec = 1; setitimer(ITIMER_REAL, &it, NULL); getitimer(ITIMER_REAL, &it); one_tick = it.it_interval; } if (tv_nz(&tcp->dtime)) *tv = tcp->dtime; else if (tv_cmp(tv, &one_tick) > 0) { if (tv_cmp(&shortest, &one_tick) < 0) *tv = shortest; else *tv = one_tick; } } if (tv_cmp(tv, &shortest) < 0) shortest = *tv; tv_add(&counts[tcp->scno].time, &counts[tcp->scno].time, tv); }
/* Callback: "a message is received to a registered object path" */ static DBusHandlerResult message_received(DBusConnection* conn, DBusMessage* msg, void* data) { const char* member = dbus_message_get_member(msg); VERB1 log("%s(method:'%s')", __func__, member); set_client_name(dbus_message_get_sender(msg)); DBusMessage* reply = dbus_message_new_method_return(msg); int r = -1; if (strcmp(member, "DeleteDebugDump") == 0) r = handle_DeleteDebugDump(msg, reply); // NB: C++ binding also handles "Introspect" method, which returns a string. // It was sending "dummy" introspection answer whick looks like this: // "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" // "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" // "<node>\n" // "</node>\n" // Apart from a warning from abrt-gui, just sending error back works as well. // NB2: we may want to handle "Disconnected" here too. if (r < 0) { /* handle_XXX experienced an error (and did not send any reply) */ dbus_message_unref(reply); if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) { /* Create and send error reply */ reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "not supported"); if (!reply) die_out_of_memory(); send_flush_and_unref(reply); } } set_client_name(NULL); return DBUS_HANDLER_RESULT_HANDLED; }
char* xvasprintf(const char *format, va_list p) { int r; char *string_ptr; #if 1 // GNU extension r = vasprintf(&string_ptr, format, p); #else // Bloat for systems that haven't got the GNU extension. va_list p2; va_copy(p2, p); r = vsnprintf(NULL, 0, format, p); string_ptr = xmalloc(r+1); r = vsnprintf(string_ptr, r+1, format, p2); va_end(p2); #endif if (r < 0) die_out_of_memory(); return string_ptr; }
/* * Return true if syscall accesses a selected path * (or if no paths have been specified for tracing). */ int pathtrace_match(struct tcb *tcp) { const struct_sysent *s; if (selected[0] == NULL) return 1; s = tcp->s_ent; if (!(s->sys_flags & (TRACE_FILE | TRACE_DESC))) return 0; /* * Check for special cases where we need to do something * other than test arg[0]. */ if (s->sys_func == sys_dup2 || s->sys_func == sys_dup3 || s->sys_func == sys_sendfile || s->sys_func == sys_sendfile64 || s->sys_func == sys_tee) { /* fd, fd */ return fdmatch(tcp, tcp->u_arg[0]) || fdmatch(tcp, tcp->u_arg[1]); } if (s->sys_func == sys_inotify_add_watch || s->sys_func == sys_faccessat || s->sys_func == sys_fchmodat || s->sys_func == sys_futimesat || s->sys_func == sys_mkdirat || s->sys_func == sys_unlinkat || s->sys_func == sys_newfstatat || s->sys_func == sys_mknodat || s->sys_func == sys_openat || s->sys_func == sys_readlinkat || s->sys_func == sys_utimensat || s->sys_func == sys_fchownat || s->sys_func == sys_pipe2) { /* fd, path */ return fdmatch(tcp, tcp->u_arg[0]) || upathmatch(tcp, tcp->u_arg[1]); } if (s->sys_func == sys_link || s->sys_func == sys_mount) { /* path, path */ return upathmatch(tcp, tcp->u_arg[0]) || upathmatch(tcp, tcp->u_arg[1]); } if (s->sys_func == sys_quotactl) { /* x, path */ return upathmatch(tcp, tcp->u_arg[1]); } if (s->sys_func == sys_renameat || s->sys_func == sys_linkat) { /* fd, path, fd, path */ return fdmatch(tcp, tcp->u_arg[0]) || fdmatch(tcp, tcp->u_arg[2]) || upathmatch(tcp, tcp->u_arg[1]) || upathmatch(tcp, tcp->u_arg[3]); } if ( s->sys_func == sys_old_mmap || #if defined(S390) s->sys_func == sys_old_mmap_pgoff || #endif s->sys_func == sys_mmap || s->sys_func == sys_mmap_pgoff || s->sys_func == sys_mmap_4koff ) { /* x, x, x, x, fd */ return fdmatch(tcp, tcp->u_arg[4]); } if (s->sys_func == sys_symlinkat) { /* path, fd, path */ return fdmatch(tcp, tcp->u_arg[1]) || upathmatch(tcp, tcp->u_arg[0]) || upathmatch(tcp, tcp->u_arg[2]); } if (s->sys_func == sys_splice) { /* fd, x, fd, x, x */ return fdmatch(tcp, tcp->u_arg[0]) || fdmatch(tcp, tcp->u_arg[2]); } if (s->sys_func == sys_epoll_ctl) { /* x, x, fd, x */ return fdmatch(tcp, tcp->u_arg[2]); } if (s->sys_func == sys_select || s->sys_func == sys_oldselect || s->sys_func == sys_pselect6) { int i, j; unsigned nfds; long *args, oldargs[5]; unsigned fdsize; fd_set *fds; if (s->sys_func == sys_oldselect) { if (umoven(tcp, tcp->u_arg[0], sizeof oldargs, (char*) oldargs) < 0) { fprintf(stderr, "umoven() failed\n"); return 0; } args = oldargs; } else args = tcp->u_arg; nfds = args[0]; /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */ if (args[0] > 1024*1024) nfds = 1024*1024; if (args[0] < 0) nfds = 0; fdsize = ((((nfds + 7) / 8) + sizeof(long) - 1) & -sizeof(long)); fds = malloc(fdsize); if (!fds) die_out_of_memory(); for (i = 1; i <= 3; ++i) { if (args[i] == 0) continue; if (umoven(tcp, args[i], fdsize, (char *) fds) < 0) { fprintf(stderr, "umoven() failed\n"); continue; } for (j = 0; j < nfds; ++j) if (FD_ISSET(j, fds) && fdmatch(tcp, j)) { free(fds); return 1; } } free(fds); return 0; } if (s->sys_func == sys_poll || s->sys_func == sys_ppoll) { struct pollfd fds; unsigned nfds; unsigned long start, cur, end; start = tcp->u_arg[0]; nfds = tcp->u_arg[1]; end = start + sizeof(fds) * nfds; if (nfds == 0 || end < start) return 0; for (cur = start; cur < end; cur += sizeof(fds)) if ((umoven(tcp, cur, sizeof fds, (char *) &fds) == 0) && fdmatch(tcp, fds.fd)) return 1; return 0; } if (s->sys_func == printargs || s->sys_func == sys_pipe || s->sys_func == sys_pipe2 || s->sys_func == sys_eventfd2 || s->sys_func == sys_eventfd || s->sys_func == sys_inotify_init1 || s->sys_func == sys_timerfd_create || s->sys_func == sys_timerfd_settime || s->sys_func == sys_timerfd_gettime || s->sys_func == sys_epoll_create || strcmp(s->sys_name, "fanotify_init") == 0) { /* * These have TRACE_FILE or TRACE_DESCRIPTOR set, but they * don't have any file descriptor or path args to test. */ return 0; } /* * Our fallback position for calls that haven't already * been handled is to just check arg[0]. */ if (s->sys_flags & TRACE_FILE) return upathmatch(tcp, tcp->u_arg[0]); if (s->sys_flags & TRACE_DESC) return fdmatch(tcp, tcp->u_arg[0]); return 0; }
void store_uint64(DBusMessageIter* iter, uint64_t val) { if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &val)) die_out_of_memory(); }
//void store_bool(DBusMessageIter* iter, bool val) //{ // dbus_bool_t db = val; // if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &db)) // die_out_of_memory(); //} void store_int32(DBusMessageIter* iter, int32_t val) { if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &val)) die_out_of_memory(); }
static void call_summary_pers(FILE *outf) { int i, j; int call_cum, error_cum; struct timeval tv_cum, dtv; double percent; const char *dashes = "-------------------------"; char error_str[16]; int *sorted_count = calloc(sizeof(int), nsyscalls); if (!sorted_count) die_out_of_memory(); call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0; if (overhead.tv_sec == -1) { tv_mul(&overhead, &shortest, 8); tv_div(&overhead, &overhead, 10); } for (i = 0; i < nsyscalls; i++) { sorted_count[i] = i; if (counts == NULL || counts[i].calls == 0) continue; tv_mul(&dtv, &overhead, counts[i].calls); tv_sub(&counts[i].time, &counts[i].time, &dtv); call_cum += counts[i].calls; error_cum += counts[i].errors; tv_add(&tv_cum, &tv_cum, &counts[i].time); } if (counts && sortfun) qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun); fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n", "% time", "seconds", "usecs/call", "calls", "errors", "syscall"); fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n", dashes, dashes, dashes, dashes, dashes, dashes); if (counts) { for (i = 0; i < nsyscalls; i++) { j = sorted_count[i]; if (counts[j].calls == 0) continue; tv_div(&dtv, &counts[j].time, counts[j].calls); if (counts[j].errors) sprintf(error_str, "%d", counts[j].errors); else error_str[0] = '\0'; percent = (100.0 * tv_float(&counts[j].time) / tv_float(&tv_cum)); fprintf(outf, "%6.2f %11.6f %11ld %9d %9.9s %s\n", percent, tv_float(&counts[j].time), (long) (1000000 * dtv.tv_sec + dtv.tv_usec), counts[j].calls, error_str, sysent[j].sys_name); } } free(sorted_count); fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n", dashes, dashes, dashes, dashes, dashes, dashes); if (error_cum) sprintf(error_str, "%d", error_cum); else error_str[0] = '\0'; fprintf(outf, "%6.6s %11.6f %11.11s %9d %9.9s %s\n", "100.00", tv_float(&tv_cum), "", call_cum, error_str, "total"); }
void qualify(const char *s) { const struct qual_options *opt; char *copy; const char *p; int not; unsigned int i; if (num_quals == 0) reallocate_qual(MIN_QUALS); opt = &qual_options[0]; for (i = 0; (p = qual_options[i].option_name); i++) { unsigned int len = strlen(p); if (strncmp(s, p, len) == 0 && s[len] == '=') { opt = &qual_options[i]; s += len + 1; break; } } not = 0; if (*s == '!') { not = 1; s++; } if (strcmp(s, "none") == 0) { not = 1 - not; s = "all"; } if (strcmp(s, "all") == 0) { for (i = 0; i < num_quals; i++) { qualify_one(i, opt->bitflag, not, -1); } return; } for (i = 0; i < num_quals; i++) { qualify_one(i, opt->bitflag, !not, -1); } copy = strdup(s); if (!copy) die_out_of_memory(); for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) { int n; if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) { unsigned pers; for (pers = 0; pers < SUPPORTED_PERSONALITIES; pers++) { for (i = 0; i < nsyscall_vec[pers]; i++) if (sysent_vec[pers][i].sys_flags & n) qualify_one(i, opt->bitflag, not, pers); } continue; } if (opt->qualify(p, opt->bitflag, not)) { error_msg_and_die("invalid %s '%s'", opt->argument_name, p); } } free(copy); return; }
/* * Return true if syscall accesses a selected path * (or if no paths have been specified for tracing). */ int pathtrace_match(struct tcb *tcp) { const struct_sysent *s; s = tcp->s_ent; if (!(s->sys_flags & (TRACE_FILE | TRACE_DESC | TRACE_NETWORK))) return 0; /* * Check for special cases where we need to do something * other than test arg[0]. */ if (s->sys_func == sys_dup2 || s->sys_func == sys_dup3 || s->sys_func == sys_sendfile || s->sys_func == sys_sendfile64 || s->sys_func == sys_tee) { /* fd, fd */ return fdmatch(tcp, tcp->u_arg[0]) || fdmatch(tcp, tcp->u_arg[1]); } if (s->sys_func == sys_inotify_add_watch || s->sys_func == sys_faccessat || s->sys_func == sys_fchmodat || s->sys_func == sys_futimesat || s->sys_func == sys_unlinkat || s->sys_func == sys_newfstatat || s->sys_func == sys_mknodat || s->sys_func == sys_openat || s->sys_func == sys_readlinkat || s->sys_func == sys_utimensat || s->sys_func == sys_fchownat || s->sys_func == sys_pipe2) { /* fd, path */ return fdmatch(tcp, tcp->u_arg[0]) || upathmatch(tcp, tcp->u_arg[1]); } if (s->sys_func == sys_link || s->sys_func == sys_mount) { /* path, path */ return upathmatch(tcp, tcp->u_arg[0]) || upathmatch(tcp, tcp->u_arg[1]); } if (s->sys_func == sys_quotactl) { /* x, path */ return upathmatch(tcp, tcp->u_arg[1]); } if (s->sys_func == sys_renameat || s->sys_func == sys_renameat2 || s->sys_func == sys_linkat) { /* fd, path, fd, path */ return fdmatch(tcp, tcp->u_arg[0]) || fdmatch(tcp, tcp->u_arg[2]) || upathmatch(tcp, tcp->u_arg[1]) || upathmatch(tcp, tcp->u_arg[3]); } if ( s->sys_func == sys_old_mmap || #if defined(S390) s->sys_func == sys_old_mmap_pgoff || #endif s->sys_func == sys_mmap || s->sys_func == sys_mmap_pgoff || s->sys_func == sys_mmap_4koff ) { /* x, x, x, x, fd */ return fdmatch(tcp, tcp->u_arg[4]); } if (s->sys_func == sys_symlinkat) { /* path, fd, path */ return fdmatch(tcp, tcp->u_arg[1]) || upathmatch(tcp, tcp->u_arg[0]) || upathmatch(tcp, tcp->u_arg[2]); } if (s->sys_func == sys_splice) { /* fd, x, fd, x, x */ return fdmatch(tcp, tcp->u_arg[0]) || fdmatch(tcp, tcp->u_arg[2]); } if (s->sys_func == sys_epoll_ctl) { /* x, x, fd, x */ return fdmatch(tcp, tcp->u_arg[2]); } if (s->sys_func == sys_fanotify_mark) { /* x, x, x, fd, path */ return fdmatch(tcp, tcp->u_arg[3]) || upathmatch(tcp, tcp->u_arg[4]); } if (s->sys_func == sys_select || s->sys_func == sys_oldselect || s->sys_func == sys_pselect6) { int i, j; int nfds; long *args, oldargs[5]; unsigned fdsize; fd_set *fds; args = tcp->u_arg; if (s->sys_func == sys_oldselect) { if (umoven(tcp, tcp->u_arg[0], sizeof oldargs, oldargs) < 0) { fprintf(stderr, "umoven() failed\n"); return 0; } args = oldargs; } /* Kernel truncates arg[0] to int, we do the same. */ nfds = (int) args[0]; /* Kernel rejects negative nfds, so we don't parse it either. */ if (nfds <= 0) return 0; /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */ if (nfds > 1024*1024) nfds = 1024*1024; fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize; fds = malloc(fdsize); if (!fds) die_out_of_memory(); for (i = 1; i <= 3; ++i) { if (args[i] == 0) continue; if (umoven(tcp, args[i], fdsize, fds) < 0) { fprintf(stderr, "umoven() failed\n"); continue; } for (j = 0;; j++) { j = next_set_bit(fds, j, nfds); if (j < 0) break; if (fdmatch(tcp, j)) { free(fds); return 1; } } } free(fds); return 0; } if (s->sys_func == sys_poll || s->sys_func == sys_ppoll) { struct pollfd fds; unsigned nfds; unsigned long start, cur, end; start = tcp->u_arg[0]; nfds = tcp->u_arg[1]; end = start + sizeof(fds) * nfds; if (nfds == 0 || end < start) return 0; for (cur = start; cur < end; cur += sizeof(fds)) if ((umoven(tcp, cur, sizeof fds, &fds) == 0) && fdmatch(tcp, fds.fd)) return 1; return 0; } if (s->sys_func == printargs || s->sys_func == sys_pipe || s->sys_func == sys_pipe2 || s->sys_func == sys_eventfd2 || s->sys_func == sys_eventfd || s->sys_func == sys_inotify_init1 || s->sys_func == sys_timerfd_create || s->sys_func == sys_timerfd_settime || s->sys_func == sys_timerfd_gettime || s->sys_func == sys_epoll_create || s->sys_func == sys_socket || s->sys_func == sys_socketpair || s->sys_func == sys_fanotify_init) { /* * These have TRACE_FILE or TRACE_DESCRIPTOR or TRACE_NETWORK set, * but they don't have any file descriptor or path args to test. */ return 0; } /* * Our fallback position for calls that haven't already * been handled is to just check arg[0]. */ if (s->sys_flags & TRACE_FILE) return upathmatch(tcp, tcp->u_arg[0]); if (s->sys_flags & (TRACE_DESC | TRACE_NETWORK)) return fdmatch(tcp, tcp->u_arg[0]); return 0; }
static int decode_select(struct tcb *tcp, long *args, enum bitness_t bitness) { int i, j; unsigned nfds, fdsize; fd_set *fds; const char *sep; long arg; fdsize = args[0]; /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */ if (args[0] > 1024*1024) fdsize = 1024*1024; if (args[0] < 0) fdsize = 0; fdsize = (((fdsize + 7) / 8) + sizeof(long)-1) & -sizeof(long); if (entering(tcp)) { fds = malloc(fdsize); if (!fds) die_out_of_memory(); nfds = args[0]; tprintf("%d", nfds); for (i = 0; i < 3; i++) { arg = args[i+1]; if (arg == 0) { tprints(", NULL"); continue; } if (!verbose(tcp)) { tprintf(", %#lx", arg); continue; } if (umoven(tcp, arg, fdsize, (char *) fds) < 0) { tprints(", [?]"); continue; } tprints(", ["); for (j = 0, sep = ""; j < nfds; j++) { if (FD_ISSET(j, fds)) { tprints(sep); printfd(tcp, j); sep = " "; } } tprints("]"); } free(fds); tprints(", "); printtv_bitness(tcp, args[4], bitness, 0); } else { static char outstr[1024]; char *outptr; #define end_outstr (outstr + sizeof(outstr)) const char *sep; if (syserror(tcp)) return 0; nfds = tcp->u_rval; if (nfds == 0) { tcp->auxstr = "Timeout"; return RVAL_STR; } fds = malloc(fdsize); if (!fds) die_out_of_memory(); outptr = outstr; sep = ""; for (i = 0; i < 3; i++) { int first = 1; arg = args[i+1]; if (!arg || umoven(tcp, arg, fdsize, (char *) fds) < 0) continue; for (j = 0; j < args[0]; j++) { if (FD_ISSET(j, fds)) { /* +2 chars needed at the end: ']',NUL */ if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) { if (first) { outptr += sprintf(outptr, "%s%s [%u", sep, i == 0 ? "in" : i == 1 ? "out" : "except", j ); first = 0; sep = ", "; } else { outptr += sprintf(outptr, " %u", j); } } nfds--; } } if (outptr != outstr) *outptr++ = ']'; if (nfds == 0) break; } free(fds); /* This contains no useful information on SunOS. */ if (args[4]) { if (outptr < end_outstr - (10 + TIMEVAL_TEXT_BUFSIZE)) { outptr += sprintf(outptr, "%sleft ", sep); outptr = sprinttv(outptr, tcp, args[4], bitness, /*special:*/ 0); } } *outptr = '\0'; tcp->auxstr = outstr; return RVAL_STR; #undef end_outstr } return 0; }
void xsetenv(const char *key, const char *value) { if (setenv(key, value, 1)) die_out_of_memory(); }
static int decode_select(struct tcb *tcp, long *args, enum bitness_t bitness) { int i, j; int nfds, fdsize; fd_set *fds = NULL; const char *sep; long arg; /* Kernel truncates arg[0] to int, we do the same. */ nfds = (int) args[0]; /* Kernel rejects negative nfds, so we don't parse it either. */ if (nfds < 0) nfds = 0; /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */ if (nfds > 1024*1024) nfds = 1024*1024; /* * We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below. * Instead of args[0], use nfds for fd count, fdsize for array lengths. */ fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize; if (entering(tcp)) { tprintf("%d", (int) args[0]); if (verbose(tcp) && fdsize > 0) { fds = malloc(fdsize); if (!fds) die_out_of_memory(); } for (i = 0; i < 3; i++) { arg = args[i+1]; if (arg == 0) { tprints(", NULL"); continue; } if (!fds) { tprintf(", %#lx", arg); continue; } if (umoven(tcp, arg, fdsize, fds) < 0) { tprints(", [?]"); continue; } tprints(", ["); for (j = 0, sep = "";; j++) { j = next_set_bit(fds, j, nfds); if (j < 0) break; tprints(sep); printfd(tcp, j); sep = " "; } tprints("]"); } free(fds); tprints(", "); printtv_bitness(tcp, args[4], bitness, 0); } else { static char outstr[1024]; char *outptr; #define end_outstr (outstr + sizeof(outstr)) int ready_fds; if (syserror(tcp)) return 0; ready_fds = tcp->u_rval; if (ready_fds == 0) { tcp->auxstr = "Timeout"; return RVAL_STR; } fds = malloc(fdsize); if (!fds) die_out_of_memory(); outptr = outstr; sep = ""; for (i = 0; i < 3 && ready_fds > 0; i++) { int first = 1; arg = args[i+1]; if (!arg || umoven(tcp, arg, fdsize, fds) < 0) continue; for (j = 0;; j++) { j = next_set_bit(fds, j, nfds); if (j < 0) break; /* +2 chars needed at the end: ']',NUL */ if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) { if (first) { outptr += sprintf(outptr, "%s%s [%u", sep, i == 0 ? "in" : i == 1 ? "out" : "except", j ); first = 0; sep = ", "; } else { outptr += sprintf(outptr, " %u", j); } } if (--ready_fds == 0) break; } if (outptr != outstr) *outptr++ = ']'; } free(fds); /* This contains no useful information on SunOS. */ if (args[4]) { if (outptr < end_outstr - (10 + TIMEVAL_TEXT_BUFSIZE)) { outptr += sprintf(outptr, "%sleft ", sep); outptr = sprinttv(outptr, tcp, args[4], bitness, /*special:*/ 0); } } *outptr = '\0'; tcp->auxstr = outstr; return RVAL_STR; #undef end_outstr } return 0; }