/* * $QNXLicenseC: * Copyright 2007, QNX Software Systems. All Rights Reserved. * * You must obtain a written license from and pay applicable license fees to QNX * Software Systems before you may reproduce, modify or distribute this software, * or any work that includes all or part of this software. Free development * licenses are available for evaluation and non-commercial purposes. For more * information visit http://licensing.qnx.com or email licensing@qnx.com. * * This file may contain contributions from others. Please review this entire * file for other proprietary rights or license notices, as well as the QNX * Development Suite License Guide at http://licensing.qnx.com/license-guide/ * for other information. * $ */ #include "pidin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char *opts = "d:klM:n:f:F:ho:p:P:"; void dspinfo(pid_t pid, char *pidname, int flags, const char *fmt, const char *mem_format); void piddspinfo(int fd, char *pidname, pid_t pid, int flags, const char *fmt, const char *mem_format); int find_netdir(char *nodename, char *buf, size_t bufsize, int flag); char* tail(char *name); char *node = ""; static char *format = "%a %b %N %p %J %B"; static int exit_on_warning = 0; static struct shorthand { char *handle; char *format; char *mem_format; } shorthands[] = { // these need to be in reverse lexigraphical order for lookup to work { "users", "%a %N %U %V %W %X %Y %Z" }, // users { "ttimes", "%a %b %N %J %t %y %z" }, // ttimes { "times", "%a %N %L %t %u %v %w %x" }, // times { "timers", "%a %b %N %R" }, // pidin timers { "threads", "%a %N %h %J %B" }, // pidin threads { "syspage", 0, "Page" }, // syspage { "signals", "%a %b %N %S %s" }, // signals { "session","%L %a %P %e %N" }, // session { "sched", "%a %b %N %p %l %H %J", }, // scheduling { "rmasks", "%a %b %N %i" }, // runmasks { "regs", "%a %b %N %r" }, // registers { "rc", 0, "rc" }, // remote connections { "pmem", "%a %b %N %p %J %c %d %m", }, // memory (process only) { "net", 0, "net" }, // node info on network { "memory", "%a %b %N %p %J %c %d %m", " %M @%> %? %< %=" }, // memory { "irqs", "%a %b %N %Q" }, // interrupts { "channels", "%a %b %N %[" }, // channels { "info", 0, "system" }, // flags { "flags", "%a %N %f" }, // flags { "fds", "%a %N %o" }, // fd { "family", "%a %N %L %P %e %G %C" }, // family { "extsched", NULL, "ExtSchedulers" }, // ext_schedulers { "environment", "%a %N %E" }, // environment { "arguments", "%a %A" }, // arguments { 0, 0 } }; static char *normalize_format(const char *f); static struct format *get_format(FILE * fp, const char **f); static struct shorthand *lookup_shorthand(const char *f); void dspsys(const char *type, const char *argv); int main(int argc, char *argv[]) { int c; int p = 1; char *pidname = NULL; int flags = 0; const char *f; int loopdelay = 10; int loop = 0; int pri = 0; const char * mem = 0; if(argc == 2) { // // By long QSSL tradition, the QNX process info utility must // have easter eggs. // if(strcmp(argv[1], "tsk") == 0) { printf("Boy, you've been using QNX for a loooong time!\n"); exit(0); } if(strcmp(argv[1], "toomuch") == 0) { printf("Oh, wow. What OS are you tripping with man?\n"); exit(0); } if(strcmp(argv[1], "sin") == 0) { printf("Since we're without sin, we're casting the first stone.\n"); exit(0); } if(strcmp(argv[1], "english") == 0) { printf("Can't even spell pidgin english properly?\n"); exit(0); } if(strcmp(argv[1], "pie") == 0) { printf("Mmmm, pudding pie. Them's good eating.\n"); exit(0); } } while ((c = getopt(argc, argv, opts)) != -1) switch (c) { case 'd': loopdelay = strtoul(optarg, 0, 0); break; case 'h': execlp("use", "use", argv[0], NULL); exit(EXIT_FAILURE); break; case 'f': format = normalize_format(optarg); if(format == NULL) { error_exit(1, "\nno memory for format\n"); } break; case 'F': format = optarg; break; case 'k': exit_on_warning = 1; break; case 'l': loop++; break; case 'M': mem = optarg; break; case 'o': pri = strtoul(optarg, 0, 0); break; case 'p': flags = DONT_RECURSE; /* * fall through */ case 'P': if(*optarg >= '0' && *optarg <= '9') { p = atoi(optarg); } else { pidname = optarg; } break; case 'n': node = optarg; break; case '?': //getopt already reported the error exit(1); default: error_exit(1, "invalid option '%c'\n", c); break; } if (pri) { struct sched_param p; p.sched_priority = pri; if (SchedSet(0, 0, SCHED_NOCHANGE, &p) == -1) error_exit(1, "sched_setprio: %s\n", strerror(errno)); } do { do { const char *g; const char *mf = 0; struct shorthand *s = 0; if (optind < argc && !(s = lookup_shorthand(argv[optind]))) { error_exit(1, "%s invalid shorthand\n", argv[optind]); } if (!s) { f = g = format; } else if(s->format) { f = g = s->format; mf = s->mem_format; } else { dspsys(s->mem_format, argv[optind]); if (loop) delay(loopdelay * 100); continue; } if (mem) { mf = mem; } while (*f) { struct format *format; if (!(format = get_format(stdout, &f))) break; if (format->flags & THREAD_UNIQUE) flags |= DO_THREADS; if (format->flags & MULTI_LINE) continue; format_title_string(stdout, format, format->title); } fputc('\n', stdout); dspinfo(p, pidname, flags, g, mf); if (loop) delay(loopdelay * 100); } while (loop); } while (++optind < argc); return EXIT_SUCCESS; } /* node = "", local node * flag = 0, find the root of "node" (default: /net/node) * flag = 1, find the network mountpoint of node (default: /net/node/net) */ int find_netdir(char *node, char *buf, size_t bufsize, int flag) { int len, fd; if (*node == 0) { *buf = '/'; *(buf + 1) = 0; len = 1; if (flag) len = netmgr_ndtostr(ND2S_DIR_SHOW | ND2S_NAME_HIDE, ND_LOCAL_NODE, buf, bufsize); return len; } if (*node == '/') { len = snprintf(buf, bufsize, "%s/", node); } else { if ((len = netmgr_ndtostr(ND2S_DIR_SHOW | ND2S_NAME_HIDE, ND_LOCAL_NODE, buf, bufsize)) == -1) return -1; len--; len += snprintf(&buf[len], bufsize - len, "%s/", node); } if (flag) { char *netmgr; netmgr_ndtostr_t msg; if (!(netmgr = alloca(len + 12))) return -1; sprintf(netmgr, "%s/dev/netmgr", buf); if ((fd = open(netmgr, O_RDONLY)) == -1) return -1; msg.i.hdr.type = _IO_MSG; msg.i.hdr.combine_len = sizeof msg.i; msg.i.hdr.mgrid = _IOMGR_NETMGR; msg.i.hdr.subtype = _NETMGR_NDTOSTR; msg.i.len = bufsize - len; msg.i.flags = ND2S_DIR_SHOW | ND2S_NAME_HIDE; msg.i.nd = ND_LOCAL_NODE; if (MsgSend(fd, &msg.i, sizeof(msg.i), &buf[len], bufsize - len) == -1) return -1; close(fd); len = strlen(buf); } return len; } char* tail(char *name) { register char *p; p = name + strlen(name); while(p > name && *p != '/' && *p != '\\' ) --p; return( (*p == '/' || *p == '\\') ? p + 1 : p ); } void dsprc(DIR *dp) { int len, fd, coid, nd; struct _server_info qinfo, sinfo; char noderoot[PATH_MAX + 1], nodename[20]; if ((len = find_netdir(node, noderoot, PATH_MAX, 0)) == -1) error_exit(1, "can't find node %s: %s\n", node, strerror(errno)); strcat(noderoot, "dev/netmgr"); if ((fd = open(noderoot, O_RDONLY)) == -1) error_exit(1, "can't open %s: %s\n", noderoot, strerror(errno)); if (ConnectServerInfo(0, fd, &qinfo) == -1) error_exit(1, "can't find server info for %s: %s\n", noderoot, strerror(errno)); close(fd); printf(" From Pid Arguments\n"); for (coid = 0; (coid = ConnectServerInfo(qinfo.pid, coid, &sinfo)) >= 0; coid++) { if (sinfo.chid != -1) continue; if ((nd = netmgr_remote_nd(qinfo.nd, sinfo.nd)) == -1 || (len = netmgr_ndtostr(ND2S_DIR_SHOW | ND2S_NAME_SHOW | ND2S_LOCAL_STR | ND2S_QOS_HIDE, nd, noderoot, PATH_MAX)) == -1) continue; nodename[16] = 0; netmgr_ndtostr(ND2S_DIR_HIDE | ND2S_LOCAL_STR, nd, nodename, 15); snprintf(&noderoot[len - 1], PATH_MAX - len, "proc/%d/as", sinfo.pid); if ((fd = open(noderoot, O_RDWR)) == -1) continue; printf("%-15s %-10d ", nodename, sinfo.pid); piddspinfo(fd, 0, sinfo.pid, 0, "%A", 0); close(fd); } return; } void dspsched(void) { struct sched_query query; if (!SchedCtl(SCHED_QUERY_SCHED_EXT, &query, sizeof(query))) { switch (query.extsched) { case SCHED_EXT_APS: { sched_aps_info aps_info; sched_aps_partition_info aps_pinfo; sched_aps_partition_stats *aps_pstats; uint64_t round[2]; int n; char notify[32], security[16]; APS_INIT_DATA(&aps_info); APS_INIT_DATA(&aps_pinfo); if (SchedCtl(SCHED_APS_QUERY_PARMS, &aps_info, sizeof(aps_info))) error_exit(!0, "Unable to query APS - %s\n", strerror(errno)); if ((aps_pstats = alloca(aps_info.num_partitions * sizeof(sched_aps_partition_stats))) == NULL) error_exit(!0, "Unable to query APS statistics - %s\n", strerror(ENOMEM)); aps_pstats=(sched_aps_partition_stats*)calloc(aps_info.num_partitions, sizeof(sched_aps_partition_stats)); if (!aps_pstats) error_exit(!0, "Unable to allocate memory\n", strerror(ENOMEM)); APS_INIT_DATA(&aps_pstats[0]); aps_pstats->id = APS_SYSTEM_PARTITION_ID; if (SchedCtl(SCHED_APS_PARTITION_STATS, aps_pstats, aps_info.num_partitions * sizeof(sched_aps_partition_stats))) error_exit(!0, "Unable to query APS statistics - %s\n", strerror(errno)); round[0] = aps_info.windowsize_cycles / 2 / 100, round[1] = aps_info.cycles_per_ms / 2; printf("APS scheduler"); printf(", %d partitions", aps_info.num_partitions); printf(", window %d ms", (int)(aps_info.windowsize_cycles / aps_info.cycles_per_ms)); if (aps_info.sec_flags == SCHED_APS_SEC_OFF) strcpy(security, "off"); else if (aps_info.sec_flags & SCHED_APS_SEC_PARTITIONS_LOCKED) strcpy(security, "LOCKED"); else if (aps_info.sec_flags == SCHED_APS_SEC_BASIC) strcpy(security, "basic"); else if (aps_info.sec_flags == SCHED_APS_SEC_FLEXIBLE) strcpy(security, "flexible"); else if (aps_info.sec_flags == SCHED_APS_SEC_RECOMMENDED) strcpy(security, "recommended"); else sprintf(security, "bits %04X", aps_info.sec_flags); printf(", security %s", security); printf("\n"); for (n = 0; n < aps_info.num_partitions; ++n) { if (SchedCtl(SCHED_APS_QUERY_PARTITION, (aps_pinfo.id = n, &aps_pinfo), sizeof(aps_pinfo))) error_exit(!0, "Unable to query APS partition - %s\n", strerror(errno)); sprintf(notify, (aps_pinfo.notify_pid != -1) ? "%d/%d" : "", aps_pinfo.notify_pid, aps_pinfo.notify_tid); printf("%-*.*s %3d%% (%3d%%) %3dms (%3dms)%c %s\n", APS_PARTITION_NAME_LENGTH, APS_PARTITION_NAME_LENGTH, aps_pinfo.name, aps_pinfo.budget_percent, (int)((aps_pstats[n].run_time_cycles + round[0]) * 100 / aps_info.windowsize_cycles), (int)(aps_pinfo.critical_budget_cycles / aps_info.cycles_per_ms), (int)((aps_pstats[n].critical_time_cycles + round[1]) / aps_info.cycles_per_ms), (aps_pstats[n].stats_flags & SCHED_APS_PSTATS_IS_BANKRUPT_NOW) ? '!' : ' ', notify); } } break; } } } int confstr_get(int fd, int name, int *value, char *str) { /* Copied from confstr lib file with added fd allowing * retrieval of information from existing connection. */ sys_conf_t msg; iov_t iov[2]; msg.i.type = _SYS_CONF; msg.i.subtype = _SYS_SUB_GET; msg.i.cmd = _CONF_STR; msg.i.name = name; msg.i.value = *value; SETIOV(iov + 0, &msg.o, sizeof(msg.o)); SETIOV(iov + 1, str, *value); if (MsgSendvnc(fd, (iov_t *)&msg.i, -sizeof (msg.i), iov, 2) == -1) { return(-1); } *value = msg.o.value; return (msg.o.match); } void dspsys(const char *type, const char *argv) { char buffer[PATH_MAX + 1]; int fd; procfs_sysinfo *sysinfo; struct stat64 st; unsigned int size; uint64_t stat_size; uint64_t total; char *size_sym; char *total_sym; time_t boot_time; struct cpuinfo_entry *cpu; int i; char nodepath[PATH_MAX + 1], *n; DIR *dp; struct dirent *dent; dp = 0; dent = 0; n = "."; switch(*type) { case 's': case 'n': if (*type == 'n' && !*node) { /* 'pidin net' show info for everyone in /net */ if ((i = find_netdir("", nodepath, PATH_MAX, 1)) == -1) error_exit(1, "can't find node %s: %s\n", node, strerror(errno)); /* make sure the network manager is running, otherwise, we jsut * got a "/" */ if ((fd = open("/dev/netmgr", O_RDONLY)) == -1) error_exit(1, "Network manager is not running.\n"); close(fd); if ((dp = opendir(nodepath)) == NULL) error_exit(1, "can't opendir %s: %s\n", nodepath, strerror(errno)); if (!(dent = readdir(dp))) { closedir(dp); return; } n = dent->d_name; printf(" ND Node CPU Release FreeMem BootTime\n"); } else { /* 'pidin -n node info' or 'pidin -n node net' generate same result */ if ((i = find_netdir(node, nodepath, PATH_MAX, 0)) == -1) error_exit(1, "can't find node %s: %s\n", node, strerror(errno)); } break; case 'r': dsprc(dp); return; case 'P': dspsyspage(strchr(argv,'=')); return; case 'E': if (*node != '\0') error_exit(!0, "can only query 'extsched' on local node\n"); dspsched(); return; default: error_exit(1, "invalid option\n"); } do { snprintf(buffer, PATH_MAX, "%s%s/proc", nodepath, n); if (dent) { if (strlen(dent->d_name) > 15) dent->d_name[15] = 0; printf(" %-4d %-15s ", (int)dent->d_ino, dent->d_name); } if ((fd = open64(buffer, O_RDONLY)) == -1) { if (dp) { printf("%s\n", strerror(errno)); goto next; } error_exit(1, "couldn't open %s: %s\n", buffer, strerror(errno)); } if ((sysinfo = load_syspage(fd, 0)) == NULL) { if (dp) { printf("%s\n", strerror(errno)); goto next; } error_exit(!0, "couldn't load syspage info for %s: %s\n", buffer, strerror(errno)); } if (fstat64(fd, &st) == -1) error_exit(1, "couldn't get stat info for %s: %s\n", buffer, strerror(errno)); stat_size = st.st_size; total = get_total_mem(sysinfo); boot_time = _SYSPAGE_ENTRY(sysinfo, qtime)->boot_time; if (dent) { printf("%2d ", sysinfo->num_cpu); } else { printf("CPU:"); } switch(sysinfo->type) { case SYSPAGE_X86: printf("X86 "); break; case SYSPAGE_PPC: printf("PPC "); break; case SYSPAGE_MIPS: printf("MIPS "); break; case SYSPAGE_ARM: printf("ARM "); break; case SYSPAGE_SH: printf("SH "); break; default: printf("Unknown(%d) ", sysinfo->type); break; } size = PATH_MAX; if (confstr_get(fd,_CS_RELEASE,&size, buffer) == -1) { error_exit(1, "couldn't retrieve release info for %s: %s\n", buffer, strerror(errno)); } if (dent) { printf(" %-8s",buffer); } else { printf("Release:%-7s", buffer); } size = normalize_data_size(stat_size, &size_sym); total = normalize_data_size(total, &total_sym); strftime(buffer, sizeof buffer, "%b %d %T %Z %Y", localtime(&boot_time)); if (dent) { char sizebuf[14]; snprintf(sizebuf, 14, "%u%sb/%u%sb", size, size_sym, (unsigned)total, total_sym); printf("%-14s", sizebuf); printf("%s", buffer); } else { printf("FreeMem:%u%sb/%u%sb ", size, size_sym, (unsigned)total, total_sym); printf("BootTime:%s", buffer); } printf("\n"); if (!dent) { for(i = 1, cpu = _SYSPAGE_ENTRY(sysinfo, cpuinfo); i <= sysinfo->num_cpu; i++, cpu++) { printf("Processor%d: ", i); if(sysinfo->type == SYSPAGE_PPC){ printf("%x ", cpu->cpu); } else{ printf("%u ", cpu->cpu); } printf("%s ", &_SYSPAGE_ENTRY(sysinfo, strings)->data[cpu->name]); printf("%dMHz ", cpu->speed); if(cpu->flags & CPU_FLAG_FPU) { printf("FPU "); } if(!(cpu->flags & CPU_FLAG_MMU)) { printf("Physical "); } printf("\n"); } } free(sysinfo); close(fd); next: if (dent && (dent = readdir(dp))) n = dent->d_name; } while (dent); if (dp) closedir(dp); } /* Structure used for sorting process information. This is currently * set up to sort on a pid type key */ typedef struct sortentry{ pid_t pid; pid_t key; } sortentry_t; static int sortkey(const void *a, const void *b) { const sortentry_t *as = (const sortentry_t *)a; const sortentry_t *bs = (const sortentry_t *)b; return(as->key - bs->key ); } static int sortpid(const void *a, const void *b) { const sortentry_t *as = (const sortentry_t *)a; const sortentry_t *bs = (const sortentry_t *)b; return(as->pid - bs->pid); } static int getinfo(char *procname, struct shared_info *info_p) { int ret, fd; if ((fd = open64(procname, O_RDONLY)) == -1) { if(errno != ENOENT) { warning_exit(1, 0, "couldn't open %s: %s\n", procname, strerror(errno)); } return(1); } memset(info_p, 0, sizeof(*info_p)); ret = fill_info(info_p, fd); close(fd); return(ret); } static int * getpidlist(char *nodepath, const char *fmt) { char buf[50]; struct dirent *dirent; DIR *dir; int entries = 0; pid_t *pid_list; int i, cur = 0; sortentry_t *sort_list; int pidsort = 0; char keyid = 'a'; snprintf(buf, 50, "%sproc", nodepath); if (!(dir = opendir(buf))) { error_exit(1, "couldn't open %s: %s\n", buf, strerror(errno)); } /* Find number of entries. */ while (dirent = readdir(dir)) { entries++; } /* Add one entry for terminator value. */ pid_list = malloc(sizeof(pid_t)*(entries + 1)); if (pid_list == NULL) { closedir(dir); return(NULL); } sort_list = (sortentry_t *)malloc(sizeof(sortentry_t)*(entries)); if (sort_list == NULL) { free(pid_list); closedir(dir); return(NULL); } rewinddir(dir); if (fmt != NULL) { /* Find first character identifier in output format to determine * which key should be used as primary for sorting. */ char *firstid = strchr(fmt, '%'); if (firstid != NULL) { keyid = *(firstid+1); } } while (dirent = readdir(dir)) { pid_list[cur] = atoi(dirent->d_name); /* Only analyze numeric entries. 0 indicates all ASCII... */ /* Potential problem here with numeric + ASCII, but these * should never occur in the proc dir. */ if (pid_list[cur] != 0) { struct shared_info info; snprintf(buf, 50, "%sproc/%d/as", nodepath, pid_list[cur]); if (getinfo(buf, &info) == 0) { sort_list[cur].pid = pid_list[cur]; /* Bit of a nuisance having to fill all of these in, but * there aren't really many that are likely to be useful * for grouping other than sessions and process groups. */ switch(keyid) { case 'L': /* Session ID. */ sort_list[cur].key = info.info->sid; break; case 'P': /* Process group. */ sort_list[cur].key = info.info->pgrp; break; default: /* Sort on pid only.*/ sort_list[cur].key = info.info->pid; pidsort = 1; break; } /* Include pid in list to be displayed... */ cur++; } if (cur >= entries) { /* Fall out if more entries found than allocated. * No need to produce error since the output is only a sample * at a given point in time anyway. */ break; } } } closedir(dir); /* Sort on primary key. */ qsort (sort_list, cur, sizeof(sortentry_t), sortkey); /* Now perform secondary sort based on pid (if necessary). */ if (!pidsort) { i = 0; while (i < cur) { int ns = 0; pid_t curkey = sort_list[i].key; while ((sort_list[i+ns].key == curkey) && (i+ns < cur)) { ns++; } qsort(&sort_list[i], ns, sizeof(sortentry_t), sortpid); i+=ns; } } /* Copy sorted pids int pidlist for return to caller. */ for (i = 0; i < cur; i++) { pid_list[i] = sort_list[i].pid; } /* End of array = 0. */ pid_list[cur] = 0; free (sort_list); return(pid_list); } void dspinfo(pid_t pid, char *pidname, int flags, const char *fmt, const char *mi_fmt) { char buffer[50], nodepath[50]; struct dirent *dirent; DIR *dir; int fd, len; pid_t *pid_list; if ((len = find_netdir(node, nodepath, 50, 0)) == -1) error_exit(1, "could't find node %s: %s\n", node); if (flags & DONT_RECURSE && pidname == NULL) { snprintf(buffer, 50, "%sproc/%d/as", nodepath, pid); if ((fd = open64(buffer, O_RDONLY)) == -1) error_exit(1, "couldn't open %s: %s\n", buffer, strerror(errno)); piddspinfo(fd, NULL, pid, flags | DONT_RECURSE, fmt, mi_fmt); close(fd); return; } snprintf(buffer, 50, "%sproc", nodepath); /* Try and get sorted list of pids. */ pid_list = getpidlist(nodepath, fmt); if (pid_list != NULL) { int *pid_e = pid_list; while (*pid_e != 0) { snprintf(buffer, 50, "%sproc/%d/as", nodepath, *pid_e); if ((fd = open64(buffer, O_RDONLY)) != -1) { piddspinfo(fd, pidname, *pid_e, flags | DONT_RECURSE, fmt, mi_fmt); close(fd); } else if(errno != ENOENT) { warning_exit(1, 0, "couldn't open %s: %s\n", buffer, strerror(errno)); } pid_e++; } /* pid_list was malloc'ed... */ free(pid_list); return; } /* Sorted list unavailable (e.g. no memory...). Get unsorted entries. */ if (!(dir = opendir(buffer))) error_exit(1, "couldn't open %s: %s\n", buffer, strerror(errno)); while (dirent = readdir(dir)) { int fd; /* skip over "/proc/self" entry */ if(!isdigit(dirent->d_name[0])) continue; snprintf(buffer, 50, "%sproc/%s/as", nodepath, dirent->d_name); if ((fd = open64(buffer, O_RDONLY)) != -1) { piddspinfo(fd, pidname, atoi(dirent->d_name), flags | DONT_RECURSE, fmt, mi_fmt); close(fd); } else if(errno != ENOENT) { warning_exit(1, 0, "couldn't open %s: %s\n", buffer, strerror(errno)); } } closedir(dir); } void piddspinfo(int fd, char *pidname, pid_t pid, int flags, const char *fmt, const char *mf) { int tid, lasttid; const char *f; struct shared_info info; int special = 0; info.name = 0; info.mem = 0; info.info = 0; info.irqs = 0; info.channels = 0; info.num_channels = 0; info.num_irqs = 0; info.timers = 0; info.num_timers = 0; info.coids = 0; info.num_coids = 0; info.tls = 0; info.text = info.data = info.stack = 0; info.memobjects = 0; info.num_memobjects = 0; info.flags = 0; info.gprs = 0; if (fill_info(&info, fd)) { return; } if(pidname) { fill_name(&info, fd); if(!info.name) { return; } if(!(f = strrchr(info.name->path, '/'))) { f = info.name->path; } while(*f && *f == '/') { f++; } if(strcmp(tail((char*) f), pidname) != 0) { return; } } if (mf) { info.flags |= SEPARATE_MEMORY; } for (lasttid = tid = 1; lasttid >= tid; lasttid = ++tid) { f = fmt; if (!(info.info->flags & _NTO_PF_ZOMBIE)) { if (fill_status(1, &info, &tid, fd) || tid < lasttid) break; } if (info.memobjects) { int i; struct memobjects *mo; for(mo = info.memobjects, i = 0;i < info.num_memobjects; mo++, i++) { free(mo->name); } free(info.memobjects); info.memobjects = 0; info.num_memobjects = 0; } info.text = info.data = info.stack = 0; while (*f) { struct format *format; if (!(format = get_format(stdout, &f))) break; info.status = 0; if (format->flags & MULTI_LINE) { special++; continue; } /* if we can do it as a zombie or this isn't a zombie ... */ if (!(format->flags & ZOMBIE_INVALID) || !(info.info->flags & _NTO_PF_ZOMBIE)) { if (format->print(stdout, pid, &tid, format, fd, &info)) break; } else { if (format->flags & NA) { format_data_string(stdout, format, (info.info->flags & _NTO_PF_ZOMBIE) ? "(Zombie)" : na); } else { format_data_string(stdout, format, spaces); } } } fprintf(stdout, "\n"); if (special) { f = fmt; while (*f) { struct format *format; if (!(format = get_format(0, &f))) break; if ((format->flags & MULTI_LINE) && !(format->flags & PROCESS_ONLY) && format->print(stdout, pid, &tid, format, fd, &info)) break; } } if (info.info->flags & _NTO_PF_ZOMBIE) break; if (!(flags & DO_THREADS)) break; } if (special) { fpos_t p1, p2; fgetpos(stdout, &p1); f = fmt; while (*f) { struct format *format; if (!(format = get_format(0, &f))) break; if ((format->flags & (MULTI_LINE | PROCESS_ONLY)) == (MULTI_LINE | PROCESS_ONLY) && format->print(stdout, pid, &tid, format, fd, &info)) break; } fgetpos(stdout, &p2); //Avoid putting two newlines when there is no extra output if(memcmp(&p1, &p2, sizeof(p1)) != 0) { fprintf(stdout, "\n"); } } if (mf) { int i; for (i = info.num_memobjects; i; i--) { f = mf; while(*f) { struct format *format; if (!(format = get_format(stdout, &f))) break; format->print(stdout, pid, &tid, format, fd, &info); } info.next_memobject++; fprintf(stdout, "\n"); } } // need to clean up resources if (info.mem) free(info.mem); if (info.tls) free(info.tls); if (info.irqs) free(info.irqs); if (info.gprs) free(info.gprs); if (info.timers) free(info.timers); if (info.memobjects) { int i; struct memobjects *mo; for(mo = info.memobjects, i = 0;i < info.num_memobjects; mo++, i++) { free(mo->name); } free(info.memobjects); info.memobjects = 0; } if (info.coids) { int i; for(i = 0; i < info.num_coids; i++) { if(info.coids[i].name) { free(info.coids[i].name); } } free(info.coids); info.coids = 0; info.num_coids = 0; } } static char * normalize_format(const char *f) { const char *p; char *r, *s; if (!(r = malloc(strlen(f) * 3 + 1))) return 0; for (s = r, p = f; *p; p++) *s++ = '%', *s++ = *p, *s++ = ' '; *s = 0; return r; } // note this returns a pointer to static storage static struct format * get_format(FILE * fp, const char **f) { static struct format r; const char *p = *f; int w, c; while (*p && *p != '%') { if (fp) fputc(*p, fp); p++; } if (!*p || !*++p) return *f = p, (struct format *) 0; // trailing % is ignored w = strtol(p, (char **)&p, 10); c = *p++; if (formats[c].letter != c) { error_exit(1, "Format letter '%c'(%#x) <=> '%c'(%#x) is invalid.\n", c, c, formats[c].letter, formats[c].letter); } if (!formats[c].print) return errno = EINVAL, (struct format *) -1; r.width = w ? w : formats[c].width; r.title = formats[c].title; r.print = formats[c].print; r.flags = formats[c].flags; if (r.width < 0) r.flags |= DATA_LEFT_JUSTIFIED, r.width *= -1; r.letter = c; *f = p; return &r; } static struct shorthand * lookup_shorthand(const char *f) { struct shorthand *s, *match; int len; for (len =0; f[len] && isalnum(f[len]); len++ ); for (match = 0, s = shorthands; s->handle; s++) { if (!strnicmp(s->handle, f, len)) { if (match) { match = 0; break; } match = s; } } return match; } void error_exit(int printmsg, const char *fmt,...) { extern char *__progname; if (printmsg) { va_list arglist; fprintf(stderr, "%s: ", __progname); va_start(arglist, fmt); vfprintf(stderr, fmt, arglist); va_end(arglist); } exit(EXIT_FAILURE); } void warning_exit(int printmsg, int expectwarn, const char *fmt,...) { if (printmsg) { va_list arglist; va_start(arglist, fmt); vfprintf(stderr, fmt, arglist); va_end(arglist); } if (!expectwarn && exit_on_warning) exit(EXIT_FAILURE); } __SRCVERSION("pidin.c $Rev: 153052 $");