⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sadc.c

📁 linux下查看系统工具原码,如IOSTAT等
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * sadc: system activity data collector * (C) 1999-2006 by Sebastien GODARD (sysstat <at> wanadoo.fr) * *************************************************************************** * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published  by  the * * Free Software Foundation; either version 2 of the License, or (at  your * * option) any later version.                                              * *                                                                         * * This program is distributed in the hope that it  will  be  useful,  but * * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY * * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details.                                                       * *                                                                         * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                   * *************************************************************************** */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#include <unistd.h>#include <fcntl.h>#include <time.h>#include <errno.h>#include <signal.h>#include <dirent.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/utsname.h>#include "sa.h"#include "common.h"#include "ioconf.h"#ifdef USE_NLS#include <locale.h>#include <libintl.h>#define _(string) gettext(string)#else#define _(string) (string)#endif/* Nb of processors on the machine. A value of 1 means two processors */int cpu_nr = -1;unsigned int serial_nr = 0, iface_nr = 0, irqcpu_nr = 0, disk_nr = 0;int pid_idx = 0, pid_nr = 0;unsigned int sadc_actflag;long interval = 0;int kb_shift = 0;struct file_hdr file_hdr;struct file_stats file_stats;struct stats_one_cpu *st_cpu = NULL;struct stats_serial *st_serial = NULL;struct stats_net_dev *st_net_dev = NULL;struct stats_irq_cpu *st_irq_cpu = NULL;struct disk_stats *st_disk = NULL;struct pid_stats *pid_stats[MAX_PID_NR];unsigned long all_pids[MAX_PID_NR];unsigned char f_pids[MAX_PID_NR];unsigned int interrupts[NR_IRQS];unsigned int u_tmp[NR_DISKS - 1];/* *************************************************************************** * Print usage and exit *************************************************************************** */void usage(char *progname){   /*    * Don't show options like -x ALL or -X SELF.    * They should only be used with sar.    */   fprintf(stderr, _("Usage: %s [ options... ] [ <interval> [ <count> ] ] [ <outfile> ]\n"		   "Options are:\n"		   "[ -d ] [ -F ] [ -I ] [ -V ]\n"),	   progname);   exit(1);}/* *************************************************************************** * SIGALRM signal handler *************************************************************************** */void alarm_handler(int sig){   signal(SIGALRM, alarm_handler);   alarm(interval);}/* *************************************************************************** * Allocate pid_stats structures *************************************************************************** */void salloc_pid(int nb_pid){   int pid;   if ((pid_stats[0] = (struct pid_stats *) malloc(PID_STATS_SIZE * nb_pid)) == NULL) {      perror("malloc");      exit(4);   }   memset(pid_stats[0], 0, PID_STATS_SIZE * nb_pid);   for (pid = 1; pid < nb_pid; pid++)      /* Structures are aligned but also padded. Thus array members are packed */      pid_stats[pid] = pid_stats[0] + pid;	/* Assume nb_pid <= MAX_PID_NR */}/* *************************************************************************** * Display an error message *************************************************************************** */void p_write_error(void){    fprintf(stderr, _("Cannot write data to system activity file: %s\n"),	    strerror(errno));    exit(2);}/* *************************************************************************** * Init dk_drive* counters (used for sar -b) *************************************************************************** */void init_dk_drive_stat(void){   file_stats.dk_drive = 0;   file_stats.dk_drive_rio  = file_stats.dk_drive_wio  = 0;   file_stats.dk_drive_rblk = file_stats.dk_drive_wblk = 0;}/* *************************************************************************** * Insert PID number into the list if not already there and if possible. * Return the index in the list, or MAX_PID_NR if PID could not be inserted. *************************************************************************** */int save_pid(unsigned long pid){   int i = 0;   while ((i < pid_idx) && (all_pids[i] != pid))      i++;   /* PID not found: insert it if possible */   if ((i == pid_idx) && (pid_idx < MAX_PID_NR))      all_pids[pid_idx++] = pid;   return i;}/* *************************************************************************** * Set PID flag value (bit 0 set: -x, bit 1 set: -X) *************************************************************************** */void set_pflag(int child, unsigned long pid){   int i = 0, flag;   if (child)      flag = X_PPID_SET;   else      flag = X_PID_SET;   if (!pid) {      for (i = 0; i < MAX_PID_NR; i++)	 f_pids[i] |= flag;   }   else {      if ((i = save_pid(pid)) < MAX_PID_NR)	 f_pids[i] |= flag;   }}/* *************************************************************************** * Look for all the PIDs *************************************************************************** */void get_pid_list(void){   DIR *dir;   struct dirent *drp;   /* Open /proc directory */   if ((dir = opendir(PROC)) == NULL) {      perror("opendir");      exit(4);   }   /* Get directory entries */   while ((drp = readdir(dir)) != NULL) {      if (isdigit(drp->d_name[0])) {	 /* Save PID in the list */	 if (save_pid(atol(drp->d_name)) == MAX_PID_NR)	    break;      }   }   /* Close /proc directory */   closedir(dir);}/* *************************************************************************** * Find number of serial lines that support tx/rx accounting * in /proc/tty/driver/serial file. *************************************************************************** */unsigned int get_serial_lines(void)#ifdef SMP_RACE{   /*    * Ignore serial lines if SMP_RACE flag is defined.    * This is because there is an SMP race in some 2.2.x kernels that    * may be triggered when reading the /proc/tty/driver/serial file.    */   return 0;}#else{   FILE *fp;   char line[256];   unsigned int sl = 0;   if ((fp = fopen(SERIAL, "r")) == NULL)      return 0;	/* No SERIAL file */   while (fgets(line, 256, fp) != NULL) {      /*       * tx/rx statistics are always present,       * except when serial line is unknown.       */      if (strstr(line, "tx:") != NULL)	 sl++;   }   fclose(fp);   return (sl + NR_SERIAL_PREALLOC);}#endif/* *************************************************************************** * Find number of interfaces (network devices) that are in /proc/net/dev * file *************************************************************************** */unsigned int get_net_dev(void){   FILE *fp;   char line[128];   unsigned int dev = 0;   if ((fp = fopen(NET_DEV, "r")) == NULL)      return 0;	/* No network device file */   while (fgets(line, 128, fp) != NULL) {      if (strchr(line, ':'))	 dev++;   }   fclose(fp);   return (dev + NR_IFACE_PREALLOC);}/* *************************************************************************** * Find number of interrupts available per processor (use * /proc/interrupts file). Called on SMP machines only. *************************************************************************** */unsigned int get_irqcpu_nb(unsigned int max_nr_irqcpu){   FILE *fp;   char line[256];   unsigned int irq = 0;   if ((fp = fopen(INTERRUPTS, "r")) == NULL)      return 0;	/* No interrupts file */   while ((fgets(line, 256, fp) != NULL) && (irq < max_nr_irqcpu)) {      if (isdigit(line[2]))	 irq++;   }   fclose(fp);   return (irq + NR_IRQPROC_PREALLOC);}/* *************************************************************************** * Allocate and init structures, according to system state *************************************************************************** */void sa_sys_init(unsigned int *flags){   /* How many processors on this machine ? */   if ((cpu_nr = get_cpu_nr(NR_CPUS)) > 0)      SREALLOC(st_cpu, struct stats_one_cpu, STATS_ONE_CPU_SIZE * (cpu_nr + 1));   /* Get serial lines that support accounting */   if ((serial_nr = get_serial_lines())) {      sadc_actflag |= A_SERIAL;      SREALLOC(st_serial, struct stats_serial, STATS_SERIAL_SIZE * serial_nr);   }   /* Get number of interrupts available per processor */   if (cpu_nr > 0) {      if ((irqcpu_nr = get_irqcpu_nb(NR_IRQS)))	 SREALLOC(st_irq_cpu, struct stats_irq_cpu,		  STATS_IRQ_CPU_SIZE * (cpu_nr + 1) * irqcpu_nr);   }   else      /* IRQ per processor are not provided by sadc on UP machines */      irqcpu_nr = 0;   /* Get number of network devices (interfaces) */   if ((iface_nr = get_net_dev())) {      sadc_actflag |= A_NET_DEV + A_NET_EDEV;      SREALLOC(st_net_dev, struct stats_net_dev, STATS_NET_DEV_SIZE * iface_nr);   }   /*    * Get number of devices in /proc/{diskstats,partitions}    * or number of disk_io entries in /proc/stat.    * Alwyays done, since disk stats must be read at least for sar -b    * if not for sar -d.    */   if ((disk_nr = get_diskstats_dev_nr(CNT_DEV, CNT_USED_DEV)) > 0) {      *flags |= S_F_HAS_DISKSTATS;      disk_nr += NR_DISK_PREALLOC;      SREALLOC(st_disk, struct disk_stats, DISK_STATS_SIZE * disk_nr);   }   else if ((disk_nr = get_ppartitions_dev_nr(CNT_DEV)) > 0) {      *flags |= S_F_HAS_PPARTITIONS;      disk_nr += NR_DISK_PREALLOC;      SREALLOC(st_disk, struct disk_stats, DISK_STATS_SIZE * disk_nr);   }   else if ((disk_nr = get_disk_io_nr()) > 0) {      disk_nr += NR_DISK_PREALLOC;      SREALLOC(st_disk, struct disk_stats, DISK_STATS_SIZE * disk_nr);   }}/* *************************************************************************** * If -L option used, request a non-blocking, exclusive lock on the file. * If lock would block, then another process (possibly sadc) has already * opened that file => exit. *************************************************************************** */int ask_for_flock(int fd, unsigned int *flags, int fatal){   /* Option -L may be used only if an outfile was specified on the command line */   if (USE_L_OPTION(*flags)) {      /*       * Yes: try to lock file. To make code portable, check for both EWOULDBLOCK       * and EAGAIN return codes, and treat them the same (glibc documentation).       * Indeed, some Linux ports (e.g. hppa-linux) do not equate EWOULDBLOCK and       * EAGAIN like every other Linux port.       */      if (flock(fd, LOCK_EX | LOCK_NB) < 0) {	 if ((((errno == EWOULDBLOCK) || (errno == EAGAIN)) && (fatal == FATAL)) ||	      ((errno != EWOULDBLOCK) && (errno != EAGAIN))) {	    perror("flock");	    exit(1);	 }	 /* Was unable to lock file: lock would have blocked... */	 return 1;      }      else	 /* File successfully locked */	 *flags |= S_F_FILE_LCK;   }   return 0;}/* *************************************************************************** * Fill system activity file header, then print it *************************************************************************** */void setup_file_hdr(int fd, size_t *file_stats_size){   int nb;   struct tm loc_time;   struct utsname header;   /* First reset the structure */   memset(&file_hdr, 0, FILE_HDR_SIZE);   /* Then get current date */   file_hdr.sa_ust_time = get_localtime(&loc_time);   /* Ok, now fill the header */   file_hdr.sa_actflag = sadc_actflag;   file_hdr.sa_magic = SA_MAGIC;   file_hdr.sa_st_size = FILE_STATS_SIZE;   file_hdr.sa_day = loc_time.tm_mday;   file_hdr.sa_month = loc_time.tm_mon;   file_hdr.sa_year = loc_time.tm_year;   file_hdr.sa_sizeof_long = sizeof(long);   file_hdr.sa_proc = cpu_nr;   file_hdr.sa_nr_pid = pid_nr;   file_hdr.sa_serial = serial_nr;   file_hdr.sa_irqcpu = irqcpu_nr;   file_hdr.sa_iface = iface_nr;   if (GET_DISK(sadc_actflag))      file_hdr.sa_nr_disk = disk_nr;   else      file_hdr.sa_nr_disk = 0;   *file_stats_size = FILE_STATS_SIZE;   /* Get system name, release number and hostname */   uname(&header);   strncpy(file_hdr.sa_sysname, header.sysname, UTSNAME_LEN);   file_hdr.sa_sysname[UTSNAME_LEN - 1] = '\0';   strncpy(file_hdr.sa_nodename, header.nodename, UTSNAME_LEN);   file_hdr.sa_nodename[UTSNAME_LEN - 1] = '\0';   strncpy(file_hdr.sa_release, header.release, UTSNAME_LEN);   file_hdr.sa_release[UTSNAME_LEN - 1] = '\0';   /* Write file header */   if ((nb = write(fd, &file_hdr, FILE_HDR_SIZE)) != FILE_HDR_SIZE) {      fprintf(stderr, _("Cannot write system activity file header: %s\n"),	      strerror(errno));      exit(2);   }}/* *************************************************************************** * sadc called with interval and count parameters not set: * write a dummy record notifying a system restart. * This should typically be called this way at boot time, * before the cron daemon is started to avoid conflict with sa1/sa2 scripts. *************************************************************************** */void write_dummy_record(int ofd, size_t file_stats_size, unsigned int *flags){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -