int get_terminal_state(struct steal_pty_state *steal, pid_t target) { struct procstat *procstat; struct kinfo_proc *kp; unsigned int cnt; int err = 0; procstat = procstat_open_sysctl(); kp = procstat_getprocs(procstat, KERN_PROC_PID, target, &cnt); if (kp == NULL || cnt < 1) goto done; if (kp->ki_tdev == NODEV) { error("Child is not connected to a pseudo-TTY. Unable to steal TTY."); err = EINVAL; goto done; } if ((err = find_terminal_emulator(steal))) return err; done: procstat_freeprocs(procstat, kp); procstat_close(procstat); return err; }
int test_procstat(struct tf_test *thiz) { struct procstat *ps; struct kinfo_vmentry *kv; struct kinfo_proc *kp; unsigned cnt, i; ps = procstat_open_sysctl(); thiz->t_assert(ps != NULL); cnt = 0; kp = procstat_getprocs(ps, KERN_PROC_PID, getpid(), &cnt); thiz->t_assert(kp != NULL); thiz->t_pf("getprocs retrieved %u procs\n", cnt); kv = procstat_getvmmap(ps, kp, &cnt); thiz->t_assert(kv != NULL); for (i = 0; i < cnt; i++) { thiz->t_pf("[%u] type: %d, " "start: 0x%"PRIx64", end: 0x%"PRIx64" " "(sz: %"PRIu64"%c), prot: 0x%x\n", i, kv[i].kve_type, kv[i].kve_start, kv[i].kve_end, SZFORMAT(kv[i].kve_end - kv[i].kve_start), kv[i].kve_protection); } procstat_freevmmap(ps, kv); procstat_freeprocs(ps, kp); procstat_close(ps); return (TF_SUCC); }
const char *proc_maps(pid_t pid, size_t *start, size_t *end, int *exe_self) { static struct kinfo_vmentry *freep = NULL; static unsigned int i, cnt; static char *exe_name; /* first, init */ if (freep == NULL) { struct kinfo_proc *ki = kinfo_getproc(pid); if (ki == NULL) { perror("Error in get process info"); exit(6); } freep = procstat_getvmmap(procstat_open_sysctl(), ki, &cnt); exe_name = ki->ki_comm; } while (i < cnt) { struct kinfo_vmentry *kve = &freep[i++]; if ((kve->kve_protection & KVME_PROT_EXEC) && kve->kve_path[0] == '/') { *start = kve->kve_start; *end = kve->kve_end; if (exe_self != NULL) { *exe_self = (strcmp(exe_name, strrchr(kve->kve_path, '/') + 1) == 0); } return kve->kve_path; } } i = 0; free(freep); freep = NULL; return NULL; }
int getdtablecount(void) { struct procstat *procstat; struct kinfo_proc *kipp; struct filestat_list *head; struct filestat *fst; unsigned int fd_count = 0; pid_t pid; unsigned int cnt; procstat = procstat_open_sysctl(); if (procstat == NULL) return 0; pid = getpid(); kipp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt); if (kipp == NULL) return 0; if (cnt != 0) { head = procstat_getfiles(procstat, kipp, 0); if (head == NULL) return 0; fst = STAILQ_LAST(head, filestat, next); fd_count = fst->fs_fd; } procstat_freeprocs(procstat, kipp); return fd_count; }
struct filestat_list* get_procfiles(pid_t pid, struct kinfo_proc **kp, struct procstat **procstat, unsigned int *cnt) { int mflg = 0; // include mmapped files (*procstat) = procstat_open_sysctl(); (*kp) = procstat_getprocs(*procstat, KERN_PROC_PID, pid, cnt); if ((*kp) == NULL || *cnt < 1) return NULL; return procstat_getfiles(*procstat, *kp, mflg); }
// Find the PID of the terminal emulator for `target's terminal. // // We assume that the terminal emulator is the parent of the session // leader. This is true in most cases, although in principle you can // construct situations where it is false. We should fail safe later // on if this turns out to be wrong, however. int find_terminal_emulator(struct steal_pty_state *steal) { struct procstat *procstat; struct kinfo_proc *kp; unsigned int cnt; procstat = procstat_open_sysctl(); kp = procstat_getprocs(procstat, KERN_PROC_PID, steal->target_stat.sid, &cnt); if (kp && cnt > 0) steal->emulator_pid = kp->ki_ppid; procstat_freeprocs(procstat, kp); procstat_close(procstat); return 0; }
void move_process_group(struct ptrace_child *child, pid_t from, pid_t to) { struct procstat *procstat; struct kinfo_proc *kp; unsigned int cnt; int i; int err; procstat = procstat_open_sysctl(); kp = procstat_getprocs(procstat, KERN_PROC_PGRP, from, &cnt); for (i = 0; i < cnt; i++) { debug("Change pgid for pid %d to %d", kp[i].ki_pid, to); err = do_syscall(child, setpgid, kp[i].ki_pid, to, 0, 0, 0, 0); if (err < 0) error(" failed: %s", strerror(-err)); } procstat_freeprocs(procstat, kp); procstat_close(procstat); }
int check_pgroup(pid_t target) { struct procstat *procstat; struct kinfo_proc *kp; pid_t pg; unsigned int cnt; pg = getpgid(target); procstat = procstat_open_sysctl(); kp = procstat_getprocs(procstat, KERN_PROC_PGRP, pg, &cnt); procstat_freeprocs(procstat, kp); procstat_close(procstat); if (cnt > 1) { error("Process %d shares a process group with %d other processes. Unable to attach.\n", target, cnt - 1); return EINVAL; } return 0; }
unsigned int getProcesses(QueryContext& context, struct procstat** pstat, struct kinfo_proc** procs) { std::set<std::string> pids; *pstat = procstat_open_sysctl(); if (*pstat == nullptr) { TLOG << "Problem in procstat_open_sysctl()"; return 0; } unsigned int cnt = 0; if (context.constraints["pid"].exists(EQUALS)) { pids = context.constraints["pid"].getAll(EQUALS); // Generate data for all pids in the vector. // If there are comparison constraints this could apply the operator // before generating the process structure. for (const auto& pid : pids) { *procs = procstat_getprocs(*pstat, KERN_PROC_PID, std::stoi(pid), &cnt); if (*procs == nullptr) { TLOG << "Problem retrieving processes"; procstat_close(*pstat); *pstat = nullptr; return 0; } } } else { // Get all PIDS. *procs = procstat_getprocs(*pstat, KERN_PROC_PROC, 0, &cnt); if (*procs == nullptr) { TLOG << "Problem retrieving processes"; procstat_close(*pstat); *pstat = nullptr; return 0; } } return cnt; }
int gc_vm_tbl_update(_gc_cap struct gc_vm_tbl *vt) { #ifdef GC_USE_LIBPROCSTAT struct procstat *ps; struct kinfo_vmentry *kv; struct kinfo_proc *kp; unsigned cnt, i; ps = procstat_open_sysctl(); if (ps == NULL) return (GC_ERROR); cnt = 0; kp = procstat_getprocs(ps, KERN_PROC_PID, getpid(), &cnt); if (kp == NULL) return (GC_ERROR); gc_debug("getprocs retrieved %u procs", cnt); kv = procstat_getvmmap(ps, kp, &cnt); if (kv == NULL) return (GC_ERROR); gc_debug("getvmmap retrieved %u entries", cnt); if (vt->vt_sz < cnt) return (GC_TOO_SMALL); vt->vt_nent = cnt; for (i = 0; i < vt->vt_nent; i++) { vt->vt_ent[i].ve_start = kv[i].kve_start; vt->vt_ent[i].ve_end = kv[i].kve_end; vt->vt_ent[i].ve_prot = kv[i].kve_protection; vt->vt_ent[i].ve_type = kv[i].kve_type; vt->vt_ent[i].ve_gctype = 0; gc_vm_tbl_track(vt, &vt->vt_ent[i]); } procstat_freevmmap(ps, kv); procstat_freeprocs(ps, kp); procstat_close(ps); return (GC_SUCC); #else /* !GC_USE_LIBPROCSTAT */ return (GC_ERROR); #endif /* GC_USE_LIBPROCSTAT */ }
int check_proc_stopped(pid_t pid, int fd) { struct procstat *procstat; struct kinfo_proc *kp; int state; unsigned int cnt; procstat = procstat_open_sysctl(); kp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt); if (cnt > 0) state = kp->ki_stat; procstat_freeprocs(procstat, kp); procstat_close(procstat); if (cnt < 1) return 1; if (state == SSTOP) return 1; return 0; }
void rb_vm_bugreport(const void *ctx) { #ifdef __linux__ # define PROC_MAPS_NAME "/proc/self/maps" #endif #ifdef PROC_MAPS_NAME enum {other_runtime_info = 1}; #else enum {other_runtime_info = 0}; #endif const rb_vm_t *const vm = GET_VM(); preface_dump(); if (vm) { SDR(); rb_backtrace_print_as_bugreport(); fputs("\n", stderr); } rb_dump_machine_register(ctx); #if HAVE_BACKTRACE || defined(_WIN32) fprintf(stderr, "-- C level backtrace information " "-------------------------------------------\n"); rb_print_backtrace(); fprintf(stderr, "\n"); #endif /* HAVE_BACKTRACE */ if (other_runtime_info || vm) { fprintf(stderr, "-- Other runtime information " "-----------------------------------------------\n\n"); } if (vm) { int i; VALUE name; long len; const int max_name_length = 1024; # define LIMITED_NAME_LENGTH(s) \ (((len = RSTRING_LEN(s)) > max_name_length) ? max_name_length : (int)len) name = vm->progname; fprintf(stderr, "* Loaded script: %.*s\n", LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); fprintf(stderr, "\n"); fprintf(stderr, "* Loaded features:\n\n"); for (i=0; i<RARRAY_LEN(vm->loaded_features); i++) { name = RARRAY_AREF(vm->loaded_features, i); if (RB_TYPE_P(name, T_STRING)) { fprintf(stderr, " %4d %.*s\n", i, LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); } else if (RB_TYPE_P(name, T_CLASS) || RB_TYPE_P(name, T_MODULE)) { const char *const type = RB_TYPE_P(name, T_CLASS) ? "class" : "module"; name = rb_search_class_path(rb_class_real(name)); if (!RB_TYPE_P(name, T_STRING)) { fprintf(stderr, " %4d %s:<unnamed>\n", i, type); continue; } fprintf(stderr, " %4d %s:%.*s\n", i, type, LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); } else { VALUE klass = rb_search_class_path(rb_obj_class(name)); if (!RB_TYPE_P(klass, T_STRING)) { fprintf(stderr, " %4d #<%p:%p>\n", i, (void *)CLASS_OF(name), (void *)name); continue; } fprintf(stderr, " %4d #<%.*s:%p>\n", i, LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass), (void *)name); } } fprintf(stderr, "\n"); } { #ifdef PROC_MAPS_NAME { FILE *fp = fopen(PROC_MAPS_NAME, "r"); if (fp) { fprintf(stderr, "* Process memory map:\n\n"); while (!feof(fp)) { char buff[0x100]; size_t rn = fread(buff, 1, 0x100, fp); if (fwrite(buff, 1, rn, stderr) != rn) break; } fclose(fp); fprintf(stderr, "\n\n"); } } #endif /* __linux__ */ #ifdef HAVE_LIBPROCSTAT # define MIB_KERN_PROC_PID_LEN 4 int mib[MIB_KERN_PROC_PID_LEN]; struct kinfo_proc kp; size_t len = sizeof(struct kinfo_proc); mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); if (sysctl(mib, MIB_KERN_PROC_PID_LEN, &kp, &len, NULL, 0) == -1) { perror("sysctl"); } else { struct procstat *prstat = procstat_open_sysctl(); fprintf(stderr, "* Process memory map:\n\n"); procstat_vm(prstat, &kp); procstat_close(prstat); fprintf(stderr, "\n"); } #endif /* __FreeBSD__ */ } }
int main(int argc, char *argv[]) { int ch, interval, tmp; int i; struct kinfo_proc *p; struct procstat *prstat, *cprstat; long l; pid_t pid; char *dummy; char *nlistf, *memf; const char *xocontainer; int cnt; interval = 0; memf = nlistf = NULL; argc = xo_parse_args(argc, argv); xocontainer = "basic"; while ((ch = getopt(argc, argv, "CHN:M:abcefijklhrsStvw:x")) != -1) { switch (ch) { case 'C': Cflag++; break; case 'H': Hflag++; break; case 'M': memf = optarg; break; case 'N': nlistf = optarg; break; case 'S': Sflag++; xocontainer = "cs"; break; case 'a': aflag++; break; case 'b': bflag++; xocontainer = "binary"; break; case 'c': cflag++; xocontainer = "arguments"; break; case 'e': eflag++; xocontainer = "environment"; break; case 'f': fflag++; xocontainer = "files"; break; case 'i': iflag++; xocontainer = "signals"; break; case 'j': jflag++; xocontainer = "thread_signals"; break; case 'k': kflag++; xocontainer = "kstack"; break; case 'l': lflag++; xocontainer = "rlimit"; break; case 'n': nflag++; break; case 'h': hflag++; break; case 'r': rflag++; xocontainer = "rusage"; break; case 's': sflag++; xocontainer = "credentials"; break; case 't': tflag++; xocontainer = "threads"; break; case 'v': vflag++; xocontainer = "vm"; break; case 'w': l = strtol(optarg, &dummy, 10); if (*dummy != '\0') usage(); if (l < 1 || l > INT_MAX) usage(); interval = l; break; case 'x': xflag++; xocontainer = "auxv"; break; case '?': default: usage(); } } argc -= optind; argv += optind; /* We require that either 0 or 1 mode flags be set. */ tmp = bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + lflag + rflag + sflag + tflag + vflag + xflag + Sflag; if (!(tmp == 0 || tmp == 1)) usage(); /* We allow -k to be specified up to twice, but not more. */ if (kflag > 2) usage(); /* Must specify either the -a flag or a list of pids. */ if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) usage(); /* Only allow -C with -f. */ if (Cflag && !fflag) usage(); if (memf != NULL) prstat = procstat_open_kvm(nlistf, memf); else prstat = procstat_open_sysctl(); if (prstat == NULL) xo_errx(1, "procstat_open()"); do { xo_set_version(PROCSTAT_XO_VERSION); xo_open_container("procstat"); xo_open_container(xocontainer); if (aflag) { p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); if (p == NULL) xo_errx(1, "procstat_getprocs()"); kinfo_proc_sort(p, cnt); for (i = 0; i < cnt; i++) { procstat(prstat, &p[i]); /* Suppress header after first process. */ hflag = 1; xo_flush(); } procstat_freeprocs(prstat, p); } for (i = 0; i < argc; i++) { l = strtol(argv[i], &dummy, 10); if (*dummy == '\0') { if (l < 0) usage(); pid = l; p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt); if (p == NULL) xo_errx(1, "procstat_getprocs()"); if (cnt != 0) procstat(prstat, p); procstat_freeprocs(prstat, p); } else { cprstat = procstat_open_core(argv[i]); if (cprstat == NULL) { warnx("procstat_open()"); continue; } p = procstat_getprocs(cprstat, KERN_PROC_PID, -1, &cnt); if (p == NULL) xo_errx(1, "procstat_getprocs()"); if (cnt != 0) procstat(cprstat, p); procstat_freeprocs(cprstat, p); procstat_close(cprstat); } /* Suppress header after first process. */ hflag = 1; } xo_close_container(xocontainer); xo_close_container("procstat"); xo_finish(); if (interval) sleep(interval); } while (interval); procstat_close(prstat); exit(0); }
/** * \todo This function contains many cases that do not allow for a * recovery. Currently, xbt_abort() is called but we should * much rather die with the specific reason so that it's easier * to find out what's going on. */ XBT_PRIVATE std::vector<VmMap> get_memory_map(pid_t pid) { std::vector<VmMap> ret; #ifdef __linux__ /* Open the actual process's proc maps file and create the memory_map_t */ /* to be returned. */ char* path = bprintf("/proc/%i/maps", (int) pid); FILE *fp = std::fopen(path, "r"); if (fp == nullptr) { std::perror("fopen failed"); xbt_die("Cannot open %s to investigate the memory map of the process.", path); } free(path); setbuf(fp, nullptr); /* Read one line at the time, parse it and add it to the memory map to be returned */ ssize_t read; /* Number of bytes readed */ char* line = nullptr; std::size_t n = 0; /* Amount of bytes to read by xbt_getline */ while ((read = xbt_getline(&line, &n, fp)) != -1) { /** * The lines that we read have this format: (This is just an example) * 00602000-00603000 rw-p 00002000 00:28 1837264 <complete-path-to-file> */ //fprintf(stderr,"%s", line); /* Wipeout the new line character */ line[read - 1] = '\0'; /* Tokenize the line using spaces as delimiters and store each token in lfields array. We expect 5 tokens for 6 fields */ char* lfields[6]; lfields[0] = strtok(line, " "); int i; for (i = 1; i < 6 && lfields[i - 1] != nullptr; i++) { lfields[i] = std::strtok(nullptr, " "); } /* Check to see if we got the expected amount of columns */ if (i < 6) xbt_die("The memory map apparently only supplied less than 6 columns. Recovery impossible."); /* Ok we are good enough to try to get the info we need */ /* First get the start and the end address of the map */ char *tok = std::strtok(lfields[0], "-"); if (tok == nullptr) xbt_die("Start and end address of the map are not concatenated by a hyphen (-). Recovery impossible."); VmMap memreg; char *endptr; memreg.start_addr = std::strtoull(tok, &endptr, 16); /* Make sure that the entire string was an hex number */ if (*endptr != '\0') xbt_abort(); tok = std::strtok(nullptr, "-"); if (tok == nullptr) xbt_abort(); memreg.end_addr = std::strtoull(tok, &endptr, 16); /* Make sure that the entire string was an hex number */ if (*endptr != '\0') xbt_abort(); /* Get the permissions flags */ if (std::strlen(lfields[1]) < 4) xbt_abort(); memreg.prot = 0; for (i = 0; i < 3; i++){ switch(lfields[1][i]){ case 'r': memreg.prot |= PROT_READ; break; case 'w': memreg.prot |= PROT_WRITE; break; case 'x': memreg.prot |= PROT_EXEC; break; default: break; } } if (memreg.prot == 0) memreg.prot |= PROT_NONE; if (lfields[1][3] == 'p') { memreg.flags |= MAP_PRIVATE; } else { memreg.flags |= MAP_SHARED; if (lfields[1][3] != 's') XBT_WARN("The protection is neither 'p' (private) nor 's' (shared) but '%s'. Let's assume shared, as on b0rken win-ubuntu systems.\nFull line: %s\n", lfields[1], line); } /* Get the offset value */ memreg.offset = std::strtoull(lfields[2], &endptr, 16); /* Make sure that the entire string was an hex number */ if (*endptr != '\0') xbt_abort(); /* Get the device major:minor bytes */ tok = std::strtok(lfields[3], ":"); if (tok == nullptr) xbt_abort(); memreg.dev_major = (char) strtoul(tok, &endptr, 16); /* Make sure that the entire string was an hex number */ if (*endptr != '\0') xbt_abort(); tok = std::strtok(nullptr, ":"); if (tok == nullptr) xbt_abort(); memreg.dev_minor = (char) std::strtoul(tok, &endptr, 16); /* Make sure that the entire string was an hex number */ if (*endptr != '\0') xbt_abort(); /* Get the inode number and make sure that the entire string was a long int */ memreg.inode = strtoul(lfields[4], &endptr, 10); if (*endptr != '\0') xbt_abort(); /* And finally get the pathname */ if (lfields[5]) memreg.pathname = lfields[5]; /* Create space for a new map region in the region's array and copy the */ /* parsed stuff from the temporal memreg variable */ XBT_DEBUG("Found region for %s", !memreg.pathname.empty() ? memreg.pathname.c_str() : "(null)"); ret.push_back(std::move(memreg)); } std::free(line); std::fclose(fp); #elif defined __FreeBSD__ struct procstat *prstat; struct kinfo_proc *proc; struct kinfo_vmentry *vmentries; unsigned int cnt; if ((prstat = procstat_open_sysctl()) == NULL) { std::perror("procstat_open_sysctl failed"); xbt_die("Cannot access kernel state information"); } if ((proc = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt)) == NULL) { std::perror("procstat_open_sysctl failed"); xbt_die("Cannot access process information"); } if ((vmentries = procstat_getvmmap(prstat, proc, &cnt)) == NULL) { std::perror("procstat_getvmmap failed"); xbt_die("Cannot access process memory mappings"); } for (unsigned int i = 0; i < cnt; i++) { VmMap memreg; /* Addresses */ memreg.start_addr = vmentries[i].kve_start; memreg.end_addr = vmentries[i].kve_end; /* Permissions */ memreg.prot = PROT_NONE; if (vmentries[i].kve_protection & KVME_PROT_READ) memreg.prot |= PROT_READ; if (vmentries[i].kve_protection & KVME_PROT_WRITE) memreg.prot |= PROT_WRITE; if (vmentries[i].kve_protection & KVME_PROT_EXEC) memreg.prot |= PROT_EXEC; /* Private (copy-on-write) or shared? */ if (vmentries[i].kve_flags & KVME_FLAG_COW) memreg.flags |= MAP_PRIVATE; else memreg.flags |= MAP_SHARED; /* Offset */ memreg.offset = vmentries[i].kve_offset; /* Device : not sure this can be mapped to something outside of Linux? */ memreg.dev_major = 0; memreg.dev_minor = 0; /* Inode */ memreg.inode = vmentries[i].kve_vn_fileid; /* * Path. Linuxize result by giving an anonymous mapping a path from * the previous mapping, provided previous is vnode and has a path, * and mark the stack. */ if (vmentries[i].kve_path[0] != '\0') memreg.pathname = vmentries[i].kve_path; else if (vmentries[i].kve_type == KVME_TYPE_DEFAULT && vmentries[i-1].kve_type == KVME_TYPE_VNODE && vmentries[i-1].kve_path[0] != '\0') memreg.pathname = vmentries[i-1].kve_path; else if (vmentries[i].kve_type == KVME_TYPE_DEFAULT && vmentries[i].kve_flags & KVME_FLAG_GROWS_DOWN) memreg.pathname = "[stack]"; /* * One last dirty modification: remove write permission from shared * libraries private clean pages. This is necessary because simgrid * later identifies mappings based on the permissions that are expected * when running the Linux kernel. */ if (vmentries[i].kve_type == KVME_TYPE_VNODE && ! (vmentries[i].kve_flags & KVME_FLAG_NEEDS_COPY)) memreg.prot &= ~PROT_WRITE; ret.push_back(std::move(memreg)); } procstat_freevmmap(prstat, vmentries); procstat_freeprocs(prstat, proc); procstat_close(prstat); #else xbt_die("Could not get memory map from process %lli", (long long int) pid); #endif return ret; }
int main(int argc, char *argv[]) { int ch, interval, tmp; int i; struct kinfo_proc *p; struct procstat *prstat, *cprstat; long l; pid_t pid; char *dummy; char *nlistf, *memf; int cnt; interval = 0; memf = nlistf = NULL; while ((ch = getopt(argc, argv, "CHLM:N:ORSXabcefijklhrstvw:x")) != -1) { switch (ch) { case 'C': Cflag++; break; case 'L': Lflag++; break; case 'H': Hflag++; break; case 'M': memf = optarg; break; case 'N': nlistf = optarg; break; case 'O': Oflag++; break; case 'R': Rflag++; break; case 'S': Sflag++; break; case 'X': Xflag++; break; case 'a': aflag++; break; case 'b': bflag++; break; case 'c': cflag++; break; case 'e': eflag++; break; case 'f': fflag++; break; case 'i': iflag++; break; case 'j': jflag++; break; case 'k': kflag++; break; case 'l': lflag++; break; case 'n': nflag++; break; case 'h': hflag++; break; case 'r': rflag++; break; case 's': sflag++; break; case 't': tflag++; break; case 'v': vflag++; break; case 'w': l = strtol(optarg, &dummy, 10); if (*dummy != '\0') usage(); if (l < 1 || l > INT_MAX) usage(); interval = l; break; case 'x': xflag++; break; case '?': default: usage(); } } argc -= optind; argv += optind; /* We require that either 0 or 1 mode flags be set. */ tmp = Lflag + Oflag + Rflag + Sflag + bflag + cflag + eflag + fflag + iflag + jflag + (kflag ? 1 : 0) + lflag + rflag + sflag + tflag + vflag + xflag; if (!(tmp == 0 || tmp == 1)) usage(); /* We allow -k to be specified up to twice, but not more. */ if (kflag > 2) usage(); /* Must specify either the -a flag or a list of pids. */ if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0)) usage(); /* Only allow -C with -f. */ if (Cflag && !fflag) usage(); /* Only allow -X with -S and -R. */ if (Xflag && !(Sflag || Rflag)) usage(); if (memf != NULL) prstat = procstat_open_kvm(nlistf, memf); else prstat = procstat_open_sysctl(); if (prstat == NULL) errx(1, "procstat_open()"); do { if (aflag) { p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt); if (p == NULL) errx(1, "procstat_getprocs()"); kinfo_proc_sort(p, cnt); for (i = 0; i < cnt; i++) { procstat(prstat, &p[i]); /* Suppress header after first process. */ hflag = 1; } procstat_freeprocs(prstat, p); } for (i = 0; i < argc; i++) { l = strtol(argv[i], &dummy, 10); if (*dummy == '\0') { if (l < 0) usage(); pid = l; p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt); if (p == NULL) errx(1, "procstat_getprocs()"); if (cnt != 0) procstat(prstat, p); procstat_freeprocs(prstat, p); } else { cprstat = procstat_open_core(argv[i]); if (cprstat == NULL) { warnx("procstat_open()"); continue; } p = procstat_getprocs(cprstat, KERN_PROC_PID, -1, &cnt); if (p == NULL) errx(1, "procstat_getprocs()"); if (cnt != 0) procstat(cprstat, p); procstat_freeprocs(cprstat, p); procstat_close(cprstat); } /* Suppress header after first process. */ hflag = 1; } if (interval) sleep(interval); } while (interval); procstat_close(prstat); exit(0); }