/* File for parsing top-level /proc entities. */ #include "sysinfo.h" #include #include #include #include #include #include #include "version.h" #define BAD_OPEN_MESSAGE \ "Error: /proc must be mounted\n" \ " To mount /proc at boot you need an /etc/fstab line like:\n" \ " /proc /proc proc defaults\n" \ " In the meantime, mount /proc /proc -t proc\n" #define UPTIME_FILE "/proc/uptime" #define LOADAVG_FILE "/proc/loadavg" #define MEMINFO_FILE "/proc/meminfo" static char buf[1024]; /* This macro opens FILE only if necessary and seeks to 0 so that successive calls to the functions are more efficient. It also reads the current contents of the file into the global buf. */ #define FILE_TO_BUF(FILE) { \ static int n, fd = -1; \ if (fd == -1 && (fd = open(FILE, O_RDONLY)) == -1) { \ fprintf(stderr, BAD_OPEN_MESSAGE); \ close(fd); \ return 0; \ } \ lseek(fd, 0L, SEEK_SET); \ if ((n = read(fd, buf, sizeof buf - 1)) < 0) { \ perror(FILE); \ close(fd); \ fd = -1; \ return 0; \ } \ buf[n] = '\0'; \ } #define SET_IF_DESIRED(x,y) if (x) *(x) = (y) /* evals 'x' twice */ int uptime(double *uptime_secs, double *idle_secs) { double up=0, idle=0; FILE_TO_BUF(UPTIME_FILE) if (sscanf(buf, "%lf %lf", &up, &idle) < 2) { fprintf(stderr, "bad data in " UPTIME_FILE "\n"); return 0; } SET_IF_DESIRED(uptime_secs, up); SET_IF_DESIRED(idle_secs, idle); return up; /* assume never be zero seconds in practice */ } int loadavg(double *av1, double *av5, double *av15) { double avg_1=0, avg_5=0, avg_15=0; FILE_TO_BUF(LOADAVG_FILE) if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) { fprintf(stderr, "bad data in " LOADAVG_FILE "\n"); exit(1); } SET_IF_DESIRED(av1, avg_1); SET_IF_DESIRED(av5, avg_5); SET_IF_DESIRED(av15, avg_15); return 1; } /* The following /proc/meminfo parsing routine assumes the following format: [