📄 top.c
字号:
/* * top.c - show top CPU processes * * Copyright (c) 1992 Branko Lankester * Copyright (c) 1992 Roger Binns * Copyright (c) 1997 Michael K. Johnson * * Snarfed and HEAVILY modified in december 1992 for procps * by Michael K. Johnson, johnsonm@sunsite.unc.edu. * * Modified Michael K. Johnson's ps to make it a top program. * Also borrowed elements of Roger Binns kmem based top program. * Changes made by Robert J. Nation (nation@rocket.sanders.lockheed.com) * 1/93 * * Modified by Michael K. Johnson to be more efficient in cpu use * 2/21/93 * * Changed top line to use uptime for the load average. Also * added SIGTSTP handling. J. Cowley, 19 Mar 1993. * * Modified quite a bit by Michael Shields (mjshield@nyx.cs.du.edu) * 1994/04/02. Secure mode added. "d" option added. Argument parsing * improved. Switched order of tick display to user, system, nice, idle, * because it makes more sense that way. Style regularized (to K&R, * more or less). Cleaned up much throughout. Added cumulative mode. * Help screen improved. * * Fixed kill buglet brought to my attention by Rob Hooft. * Problem was mixing of stdio and read()/write(). Added * getnum() to solve problem. * 12/30/93 Michael K. Johnson * * Added toggling output of idle processes via 'i' key. * 3/29/94 Gregory K. Nickonov * * Fixed buglet where rawmode wasn't getting restored. * Added defaults for signal to send and nice value to use. * 5/4/94 Jon Tombs. * * Modified 1994/04/25 Michael Shields <mjshield@nyx.cs.du.edu> * Merged previous changes to 0.8 into 0.95. * Allowed the use of symbolic names (e.g., "HUP") for signal input. * Rewrote getnum() into getstr(), getint(), getsig(), etc. * * Modified 1995 Helmut Geyer <Helmut.Geyer@iwr.uni-heidelberg.de> * added kmem top functionality (configurable fields) * configurable order of process display * Added options for dis/enabling uptime, statistics, and memory info. * fixed minor bugs for ELF systems (e.g. SIZE, RSS fields) * * Modified 1996/05/18 Helmut Geyer <Helmut.Geyer@iwr.uni-heidelberg.de> * Use of new interface and general cleanup. The code should be far more * readable than before. * * Modified 1996/06/25 Zygo Blaxell <zblaxell@ultratech.net> * Added field scaling code for programs that run more than two hours or * take up more than 100 megs. We have lots of both on our production line. * * Modified 1998/02/21 Kirk Bauer <kirk@kaybee.org> * Added the 'u' option to display only a selected user... plus it will * take into account that not all 20 top processes are actually shown, * so it can fit more onto the screen. I think this may help the * 'don't show idle' mode, but I'm not sure. * * Modified 1997/07/27 & 1999/01/27 Tim Janik <timj@gtk.org> * added `-p' option to display specific process ids. * process sorting is by default disabled in this case. * added `N' and `A' keys to sort the tasks Numerically by pid or * sort them by Age (newest first). * * Modified 1999/10/22 Tim Janik <timj@gtk.org> * miscellaneous minor fixes, including "usage: ..." output for * unrecognized options. * * Modified 2000/02/07 Jakub Jelinek <jakub@redhat.com> * Only load System.map when we are going to display WCHAN. * Show possible error messages from that load using SHOWMESSAGE. * * Modified 2000/07/10 Michael K. Johnson <johnsonm@redhat.com> * Integrated a patch to display SMP information. */#include <errno.h>#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <libintl.h>#include <time.h>#include <sys/ioctl.h>#include <pwd.h>#include <termcap.h>#include <termios.h>#include <signal.h>#include <sys/time.h>#include <sys/resource.h>#include <ctype.h>#include <setjmp.h>#include <stdarg.h>#include <sys/param.h>#include "proc/sysinfo.h"#include "proc/procps.h"#include "proc/whattime.h"#include "proc/signals.h"#include "proc/version.h"#include "proc/readproc.h"#include "proc/status.h"#include "proc/devname.h"/* these should be in the readproc.h header or in the procps.h header */typedef int (*cmp_t)(void*,void*);extern void reset_sort_options (void);extern int parse_sort_opt(char* opt);extern void register_sort_function (int dir, cmp_t func);#define PUTP(x) (tputs(x,1,putchar))#define BAD_INPUT -30#include "top.h" /* new header for top specific things */static int *cpu_mapping;static int nr_cpu;/*####################################################################### *#### Startup routines: parse_options, get_options, ############## *#### setup_terminal and main ############## *####################################################################### */ /* * parse the options string as read from the config file(s). * if top is in secure mode, disallow changing of the delay time between * screen updates. */void parse_options(char *Options, int secure){ int i; for (i = 0; i < strlen(Options); i++) { switch (Options[i]) { case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!secure) Sleeptime = (float) Options[i] - '0'; break; case 'S': Cumulative = 1; headers[22][1] = 'C'; break; case 's': Secure = 1; break; case 'i': Noidle = 1; break; case 'm': show_memory = 0; header_lines -= 2; break; case 'M': sort_type = S_MEM; reset_sort_options(); register_sort_function( -1, (cmp_t)mem_sort); break; case 'l': show_loadav = 0; header_lines -= 1; break; case 'P': sort_type = S_PCPU; reset_sort_options(); register_sort_function( -1, (cmp_t)pcpu_sort); break; case 'N': sort_type = S_NONE; reset_sort_options(); break; case 'A': sort_type = S_AGE; reset_sort_options(); register_sort_function( -1, (cmp_t)age_sort); break; case 't': show_stats = 0; header_lines -= 2; break; case 'T': sort_type = S_TIME; reset_sort_options(); register_sort_function( -1, (cmp_t)time_sort); break; case 'c': show_cmd = 0; break; case '\n': break; case 'I': Irixmode = 0; break; default: fprintf(stderr, "Wrong configuration option %c\n", i); exit(1); break; } }}/* * Read the configuration file(s). There are two files, once SYS_TOPRC * which should only contain the secure switch and a sleeptime * value iff ordinary users are to use top in secure mode only. * * The other file is $HOME/RCFILE. * The configuration file should contain two lines (any of which may be * empty). The first line specifies the fields that are to be displayed * in the order you want them to. Uppercase letters specify fields * displayed by default, lowercase letters specify fields not shown by * default. The order of the letters in this line corresponds to the * order of the displayed fileds. * * all Options but 'q' can be read from this config file * The delay time option syntax differs from the commandline syntax: * only integer values between 2 and 9 seconds are recognized * (this is for standard configuration, so I think this should do). * * usually this file is not edited by hand, but written from top using * the 'W' command. */void get_options(void){ FILE *fp; char *pt; char rcfile[MAXNAMELEN]; char Options[256] = ""; int i; nr_cpu = sysconf (_SC_NPROCESSORS_ONLN); cpu_mapping = (int *) xmalloc (sizeof (int) * nr_cpu); /* read cpuname */ for (i=0; i< nr_cpu; i++) cpu_mapping[i]=i; header_lines = 6 + nr_cpu; strcpy(rcfile, SYS_TOPRC); fp = fopen(rcfile, "r"); if (fp != NULL) { fgets(Options, 254, fp); fclose(fp); } parse_options(Options, 0); strcpy(Options, ""); if (getenv("HOME")) { strcpy(rcfile, getenv("HOME")); strcat(rcfile, "/"); } strcat(rcfile, RCFILE); fp = fopen(rcfile, "r"); if (fp == NULL) { strcpy(Fields, DEFAULT_SHOW); } else { if (fgets(Fields, 254, fp) != NULL) { pt = strchr(Fields, '\n'); if (pt) *pt = 0; } fgets(Options, 254, fp); fclose(fp); } parse_options(Options, getuid()? Secure : 0);}/* * Set up the terminal attributes. */void setup_terminal(void){ char *termtype; struct termios newtty; if (!Batch) termtype = getenv("TERM"); else termtype = "dumb"; if (!termtype) { /* In theory, $TERM should never not be set, but in practice, some gettys don't. Fortunately, vt100 is nearly always correct (or pretty close). */ termtype = "VT100"; /* fprintf(stderr, PROGNAME ": $TERM not set\n"); */ /* exit(1); */ } /* * Get termcap entries and window size. */ if(tgetent(NULL, termtype) != 1) { fprintf(stderr, PROGNAME ": Unknown terminal \"%s\" in $TERM\n", termtype); exit(1); } cm = tgetstr("cm", 0); top_clrtobot = tgetstr("cd", 0); cl = tgetstr("cl", 0); top_clrtoeol = tgetstr("ce", 0); ho = tgetstr("ho", 0); md = tgetstr("md", 0); mr = tgetstr("mr", 0); me = tgetstr("me", 0); if (Batch) return; /* the rest doesn't apply to batch mode */ if (tcgetattr(0, &Savetty) == -1) { perror(PROGNAME ": tcgetattr() failed"); error_end(errno); } newtty = Savetty; newtty.c_lflag &= ~ICANON; newtty.c_lflag &= ~ECHO; newtty.c_cc[VMIN] = 1; newtty.c_cc[VTIME] = 0; if (tcsetattr(0, TCSAFLUSH, &newtty) == -1) { printf("cannot put tty into raw mode\n"); error_end(1); } tcgetattr(0, &Rawtty);}int main(int argc, char **argv){ /* For select(2). */ struct timeval tv; fd_set in; /* For parsing arguments. */ char *cp; /* The key read in. */ char c; struct sigaction sact; setlocale(LC_ALL, ""); get_options(); /* set to PCPU sorting */ register_sort_function( -1, (cmp_t)pcpu_sort); /* * Parse arguments. */ argv++; while (*argv) { cp = *argv++; while (*cp) { switch (*cp) { case 'd': if (cp[1]) { if (sscanf(++cp, "%f", &Sleeptime) != 1) { fprintf(stderr, PROGNAME ": Bad delay time `%s'\n", cp); exit(1); } goto breakargv; } else if (*argv) { /* last char in an argv, use next as arg */ if (sscanf(cp = *argv++, "%f", &Sleeptime) != 1) { fprintf(stderr, PROGNAME ": Bad delay time `%s'\n", cp); exit(1); } goto breakargv; } else { fprintf(stderr, "-d requires an argument\n"); exit(1); } break; case 'n': if (cp[1]) { if (sscanf(++cp, "%d", &Loops) != 1) { fprintf(stderr, PROGNAME ": Bad value `%s'\n", cp); exit(1); } goto breakargv; } else if (*argv) { /* last char in an argv, use next as arg */ if (sscanf(cp = *argv++, "%d", &Loops) != 1) { fprintf(stderr, PROGNAME ": Bad value `%s'\n", cp); exit(1); } goto breakargv; } break; case 'q': if (!getuid()) /* set priority to -10 in order to stay above kswapd */ if (setpriority(PRIO_PROCESS, getpid(), -10)) { /* We check this just for paranoia. It's not fatal, and shouldn't happen. */ perror(PROGNAME ": setpriority() failed"); } Sleeptime = 0; break; case 'p': if (monpids_index >= monpids_max) { fprintf(stderr, PROGNAME ": More than %u process ids specified\n", monpids_max); exit(1); } if (cp[1]) { if (sscanf(++cp, "%d", &monpids[monpids_index]) != 1 || monpids[monpids_index] < 0 || monpids[monpids_index] > 65535) { fprintf(stderr, PROGNAME ": Bad process id `%s'\n", cp); exit(1); } } else if (*argv) { /* last char in an argv, use next as arg */ if (sscanf(cp = *argv++, "%d", &monpids[monpids_index]) != 1 || monpids[monpids_index] < 0 || monpids[monpids_index] > 65535) { fprintf(stderr, PROGNAME ": Bad process id `%s'\n", cp); exit(1); } } else { fprintf(stderr, "-p requires an argument\n"); exit(1); } if (!monpids[monpids_index]) monpids[monpids_index] = getpid(); /* default to no sorting when monitoring process ids */ if (!monpids_index++) { sort_type = S_NONE; reset_sort_options(); } cp = "_"; break; case 'b': Batch = 1; break; case 'c': show_cmd = !show_cmd; break; case 'S': Cumulative = 1; break; case 'i': Noidle = 1; break; case 's': Secure = 1; break; case 'C': CPU_states = 1; break; case '-': break; /* Just ignore it */ case 'v': case 'V': fprintf(stdout, "top (%s)\n", procps_version); exit(0); case 'h': fprintf(stdout, "usage: " PROGNAME " -hvbcisqS -d delay -p pid -n iterations\n"); exit(0); default: fprintf(stderr, PROGNAME ": Unknown argument `%c'\n", *cp); fprintf(stdout, "usage: " PROGNAME " -hvbcisqS -d delay -p pid -n iterations\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -