📄 ctop.c
字号:
/* * Print cluster's top information. * * Copyright (c) 2004, by: Jian Shen * All rights reserved. Peking University, China * <shenjian@net.pku.edu.cn> * * This file may be used subject to the terms and conditions of the * GNU Library General Public License Version 2, or any later version * at your option, as published by the Free Software Foundation. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * */#include "statinfo.h"#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <dirent.h>#include <getopt.h>#include <string.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/select.h>#include <termios.h>#include <signal.h>#include <arpa/inet.h>#include <netdb.h>#include <curses.h>#include <term.h>#include <sys/ioctl.h>static int msg_row;static int msg_column;static int NEED_CLEAR = 0;#define MAXSTR 80/********************************* * screen operation *********************************/void msg_print(const char* str) { putp(tgoto(cursor_address, msg_column, msg_row));// putp(clr_eol);// putp(str); printf("\r%s", str);}void msg_flush(){ fflush(stdout);}void my_clear_screen(){ putp(clear_screen); fflush(stdout);}/********************************* * host operation *********************************/#define MAX_HOSTS 16#define NO_SPACE -1#define FAIL_HOST -2char all_hosts[MAX_HOSTS][20];int VERBOSE = 0;static int compare_host(const void*a, const void* b){ char *p,*q; p = (char*)a; q = (char*)b; return strcmp(p, q);}char* get_host_name(char* host_ip){ long hostname; struct hostent *hinfo; hostname = inet_addr(host_ip); hinfo = gethostbyaddr((char *)&hostname, sizeof(long), AF_INET); if(hinfo != NULL) return hinfo->h_name; else return host_ip;}int get_all_hosts(){ DIR *dp; struct dirent *dirp; int count; if((dp = opendir("/proc/cluster")) == NULL) { fprintf(stderr, "Failed to open /proc/cluster!\n"); exit(1); } count = 0; while((dirp = readdir(dp)) != NULL) { if(count >= MAX_HOSTS) break; if(strcmp(dirp->d_name, ".") == 0) continue; if(strcmp(dirp->d_name, "..") == 0) continue; strcpy(all_hosts[count], dirp->d_name); count ++; } closedir(dp); qsort(all_hosts, count, 20, compare_host); return count;}#define CHECK_ROW() if(msg_row+3 > wsz.ws_row){msg_flush(); return NO_SPACE;}#define PRINT_ROW(r) do { \ msg_print(buf); \ msg_row += r; \ CHECK_ROW(); \ bzero(buf, MAXSTR); \}while(0)int print_load(system_load_info* sysload, char* hostname){ int i; struct winsize wsz; ioctl(STDIN_FILENO, TIOCGWINSZ, (char*)&wsz); if(VERBOSE == 0) { char buf[MAXSTR]; sprintf(buf, "%s:\n", get_host_name(hostname)); PRINT_ROW(1); sprintf(buf, " load average:%5s,%5s,%5s; ", sysload->loadavg[0], sysload->loadavg[1], sysload->loadavg[2]); double average = 0; for(i=0; i<sysload->num_of_cpu; i++) { average += atof(sysload->cpu_util[i]); } average = average / sysload->num_of_cpu; sprintf(buf, "%s cpu: %5.1f%%; ", buf, average); sprintf(buf, "%s mem:%8dk used,%8dk free.\n\n", buf, sysload->total_mem - sysload->free_mem, sysload->free_mem); PRINT_ROW(2); msg_flush(); NEED_CLEAR = 0; }else if(VERBOSE == 1) { char buf[MAXSTR]; sprintf(buf, "%s:\n", get_host_name(hostname)); PRINT_ROW(1); sprintf(buf, " load average:%5s,%5s,%5s\n", sysload->loadavg[0], sysload->loadavg[1], sysload->loadavg[2]); PRINT_ROW(1); int LINECNT = 4; for(i=0; i<sysload->num_of_cpu; i++) { sprintf(buf, "%s cpu%d:%5s%% ", buf, i, sysload->cpu_util[i]); if((i+1) % LINECNT == 0) { sprintf(buf, "%s\n", buf); PRINT_ROW(1); } } if(sysload->num_of_cpu % LINECNT != 0) { sprintf(buf, "%s\n", buf); PRINT_ROW(1); } sprintf(buf, "%s mem:%8dk av,%8dk used,%8dk free\n\n", buf, sysload->total_mem, sysload->total_mem - sysload->free_mem, sysload->free_mem); PRINT_ROW(2); msg_flush(); NEED_CLEAR = 0; }else if(VERBOSE == 2) { /* most in detail */ printf("%s:\n", get_host_name(hostname)); printf(" os version: %s %s\n", sysload->sysinfo.sysname, sysload->sysinfo.release); printf(" load average: %5s, %5s, %5s\n", sysload->loadavg[0], sysload->loadavg[1], sysload->loadavg[2]); for(i=0; i<sysload->num_of_cpu; i++) { printf(" cpu%d (%sMHZ) states: %5s%%\n", i, sysload->cpu_freq[i], sysload->cpu_util[i]); } printf(" mem: %8dk av, %8dk used, %8dk free\n", sysload->total_mem, sysload->total_mem - sysload->free_mem, sysload->free_mem); printf("\n"); } return 0;}int print_host_load(char* hostname){ system_load_info sysload; char filename[100]; int fd; int rv; sprintf(filename, "/proc/cluster/%s/top.bin", hostname); fd = open(filename, O_RDONLY); if(fd < 0) { return FAIL_HOST; } rv = read(fd, &sysload, sizeof(system_load_info)); if(rv != sizeof(system_load_info)) { close(fd); return FAIL_HOST; } close(fd); return print_load(&sysload, hostname);}/* get host's ip address by its alias according to /etc/hosts */char* get_host_ip(const char* hostname){ char* hostIP; struct hostent * h; struct in_addr* in; hostIP = (char*)malloc(20*sizeof(char)); /* get host structure by host name */ h = gethostbyname(hostname); if(h != NULL) { in = (struct in_addr*)h->h_addr; sprintf(hostIP,"%s", inet_ntoa(*in)); return hostIP; /* caller free */ }else {// fprintf(stderr, "gethostbyname failed.\n"); return NULL; }}/************************************ * tty operation ************************************/static struct termios save_termios;static int ttysavefd = -1;static enum {RESET, CBREAK} ttystate = RESET;/* put terminal into a cbreak mode */int tty_cbreak(int fd){ struct termios buf; if(tcgetattr(fd, &save_termios) < 0) return -1; buf = save_termios; buf.c_lflag &= ~(ECHO | ICANON); buf.c_cc[VMIN] = 1; /* 1 byte at a time, no timer */ buf.c_cc[VTIME] = 0; if(tcsetattr(fd, TCSAFLUSH, &buf) < 0) return -1; ttystate = CBREAK; ttysavefd = fd; return 0;}/* restore terminal's mode */int tty_reset(int fd){ if(ttystate != CBREAK) return 0; if(tcsetattr(fd, TCSAFLUSH, &save_termios) < 0) return -1; ttystate = RESET; return 0;}void tty_atexit(){ if(ttysavefd >= 0) tty_reset(ttysavefd);}struct termios* tty_termios(){ return (&save_termios);}/********************************* * signal operation *********************************/static void sig_catch(int signo){ exit(0);}static void sig_winch(int signo){ my_clear_screen(); NEED_CLEAR = 1;}void catch_signals(){ if(signal(SIGINT, sig_catch) == SIG_ERR) fprintf(stderr, "signal(SIGINT) failed.\n"); if(signal(SIGQUIT, sig_catch) == SIG_ERR) fprintf(stderr, "signal(SIGQUIT) failed.\n"); if(signal(SIGTERM, sig_catch) == SIG_ERR) fprintf(stderr, "signal(SIGTERM) failed.\n"); if(signal(SIGWINCH, sig_winch) == SIG_ERR) fprintf(stderr, "signal(SIGWINCH) failed.\n");}/********************************* * main loop *********************************/void do_key(unsigned c){ switch(c) { case 'q': exit(0); case 'v': VERBOSE = 1 - VERBOSE; /* toggle verbose option */ NEED_CLEAR = 1; break; }}void read_key(){ long file_flags; char c; int rc; fd_set fs; FD_ZERO(&fs); FD_SET(STDIN_FILENO, &fs); file_flags = fcntl(STDIN_FILENO, F_GETFL); if(file_flags == -1) file_flags = 0; fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK | file_flags); rc = read(STDIN_FILENO, &c, 1); if (rc > 0) { fcntl(STDIN_FILENO, F_SETFL, file_flags); do_key((unsigned)c); } else { fcntl(STDIN_FILENO, F_SETFL, file_flags); }}void init_term(){ setupterm((char *) 0, STDOUT_FILENO, (int *) 0); putp(clear_screen);// putp(cursor_invisible); fflush(stdout); msg_row = 0; msg_column = 0; /* this is always 0 */ NEED_CLEAR = 0;}void reset_term(){/* putp(cursor_visible); *//* fflush(stdout); */}#define SLEEP_INTERVAL 2void usage(){ printf("usage: ctop [-v] [hostname]\n");}void help(){ printf("\nCluster load monitor like top.\n"); printf("usage:\n"); printf("\tctop [-v] [hostname]\n"); printf("examples:\n"); printf("\tctop\n"); printf("\tctop node1\n"); printf("\tctop -v\n"); printf("\tctop -v node1\n"); printf("\nreport bugs to <shenjian@net.pku.edu.cn>.\n"); printf("\n");}int main(int argc, char* argv[]){ /* deal with options */ int MODE = 0; /* two modes: non-continous and continuous */ int SHOW_HOST = 0; /* two kinds: one host and all host */ int next_opt; char** program = argv; int argcnt = argc; char* target; /* target hostname */ const char* short_options = "hv"; const struct option long_options[] = { {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'} }; do{ next_opt = getopt_long(argc, argv, short_options, long_options, NULL); argcnt -= 1; switch(next_opt) { case 'h' : /* -h or --help */ help(); exit(1); case '?' : /* invalid option */ usage(); exit(1); case 'v': /* -v or --verbose */ MODE = 1; program += 1; break; case ':' : /* missing parameters */ usage(); exit(1); case -1 : /* end of option list */ break; default: printf("Something wrong with getopt_long.\n"); exit(1); } }while(next_opt != -1); program += 1; if(argcnt == 0) { SHOW_HOST = 0; }else if(argcnt == 1) { SHOW_HOST = 1; }else { usage(); exit(1); } int num_of_hosts; int i; if(SHOW_HOST == 1) { target = get_host_ip(program[0]); if(target == NULL) { fprintf(stderr, "Who is \"%s\"?\n", program[0]); exit(1); } } if(MODE == 1) { VERBOSE = 2; if(SHOW_HOST == 0) { /* show all host */ num_of_hosts = get_all_hosts(); for(i=0; i<num_of_hosts; i++) print_host_load(all_hosts[i]); }else { /* show only one host */ print_host_load(target); } }else { /* test: terminal is stdin */ if(isatty(STDIN_FILENO) == 0) { fprintf(stderr, "standard input is not a terminal device\n"); return -1; } /* register exit functions */ if(atexit(reset_term) != 0) { fprintf(stderr, "atexit failed\n"); return -1; } if(atexit(tty_atexit) != 0) { fprintf(stderr, "atexit failed\n"); return -1; } catch_signals(); /* initialize terminal */ init_term(); /* set terminal to cbreak mode */ if(tty_cbreak(STDIN_FILENO) < 0) { fprintf(stderr, "tty_cbreak failed\n"); return -1; } if(SHOW_HOST == 0) { /* get host list */ num_of_hosts = get_all_hosts(); int NEED_RELOAD = 0; int time_cnt = 0; for(;;) { if(time_cnt > 30) { NEED_RELOAD = 1; } if(NEED_RELOAD) { num_of_hosts = get_all_hosts(); NEED_RELOAD = 0; NEED_CLEAR = 1; time_cnt = 0; } if(NEED_CLEAR) my_clear_screen(); msg_row = 0; for(i=0; i<num_of_hosts; i++) { int ret = print_host_load(all_hosts[i]); if(ret == NO_SPACE) break; else if(ret == FAIL_HOST) NEED_RELOAD = 1; } sleep(SLEEP_INTERVAL); time_cnt += SLEEP_INTERVAL; read_key(); } }else { for(;;) { if(NEED_CLEAR) my_clear_screen(); msg_row = 0; print_host_load(target); sleep(SLEEP_INTERVAL); read_key(); } } /* reset terminal to original mode */ if(tty_reset(STDIN_FILENO) < 0) { fprintf(stderr, "tty_reset failed\n"); return -1; } reset_term(); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -