/* Uptime Client v5.0 beta $Id: stats-sol.c,v 1.40 2002/12/22 17:53:42 carstenklapp Exp $ Logs system uptime and statistics with Uptimes Project servers Copyright (C) 1999-2002 Martijn Broenland, Alex C. de Haas, Carsten Klapp 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 even 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 Carsten Klapp Alex C. de Haas Martijn Broenland */ /** * @filename stats-sol.c * * @desc Retrieve stats for the Solaris 6 / Irix platforms */ #if defined PLATFORM_SOLARIS /*@unused@*/ static const char rcsid[] = "@(#)$Id: stats-sol.c,v 1.40 2002/12/22 17:53:42 carstenklapp Exp $"; /* My includes */ #include "upclient.h" #include "options.h" #include "stats.h" #include "uplog.h" /* wrapper for */ /* System includes */ #include #include #include #include #include #include #include #include #include #include #include #include "locale.h" /* gettext */ /** * @desc Verbose level 3 logging of calulations */ void logcalc(char *whatwascalculateddesc, char *value) { #if defined DEBUG uplog(LOG_DEBUG, _("%s calculated: %s"), whatwascalculateddesc, value); #endif /* DEBUG */ } void initCPU(char *cpu) { static int initialized = 0; #if !defined SI_PLATFORM # define SI_PLATFORM SI_MACHINE /* for Irix 6.5.17 */ #endif /* !defined SI_PLATFORM */ if (!initialized) { initialized = 1; if (sysinfo ((cfg_sendcpudetail) ? SI_PLATFORM : SI_ARCHITECTURE, cpu, CPU_SIZE - 1) < 0) { uplog(LOG_ERR, "%s cfg_sendcpu sysinfo(): %s", _("ERROR:"), strerror(errno)); } logcalc(_("CPU"), cpu); } } /** * @desc Get os & osversion once */ void initOS(char *osname, char *osversion) { static int initialized = 0; if (!initialized) { initialized = 1; if (cfg_sendosversion) { if (sysinfo(SI_RELEASE, osversion, OSVERSION_SIZE - 1) < 0) { uplog(LOG_ERR, "%s cfg_sendosname && cfg_sendosversion sysinfo(): %s", _("ERROR:"), strerror(errno)); } logcalc(_("OS version"), osversion); } if (cfg_sendosname) { if (sysinfo(SI_SYSNAME, osname, OS_SIZE - 1) < 0) { uplog(LOG_ERR, "%s cfg_sendosname sysinfo(): %s", _("ERROR:"), strerror(errno)); } logcalc(_("OS"), osname); } } } /** * @desc Only Solaris 7 provides getloadavg() */ void getLoadavg(double *loadavg) { uplog(LOG_WARNING, _("%s %s not implemented for this operating system %s"), _("WARNING:"), _("Load-average"), strerror(errno)); cfg_sendloadavg = 0; return; } /* LIBS: -lkvm -lkstat*/ #if defined NOT_FINISHED #if OSREV >= 53 # define USE_KSTAT #endif #ifdef USE_KSTAT # include /** * Some kstats are fixed at 32 bits, these will be specified as ui32; some * are "natural" size (32 bit on 32 bit Solaris, 64 on 64 bit Solaris * we'll make those unsigned long) * Older Solaris doesn't define KSTAT_DATA_UINT32, those are always 32 bit. */ # if !defined KSTAT_DATA_UINT32 # define ui32 ul # endif #endif #define CPUSTATES 5 #ifdef USE_KSTAT #define UPDKCID(nk,ok) \ if (nk == -1) { \ perror("kstat_read "); \ quit(1); \ } \ if (nk != ok)\ goto kcid_changed; int kupdate(int avenrun[3]) { kstat_t *ks; kid_t nkcid; int i; int changed = 0; static int ncpu = 0; static kid_t kcid = 0; kstat_named_t *kn; /** * 0. kstat_open */ if (!kc) { kc = kstat_open(); if (!kc) { perror("kstat_open "); quit(1); } changed = 1; kcid = kc->kc_chain_id; } /* keep doing it until no more changes */ kcid_changed: /** * 1. kstat_chain_update */ nkcid = kstat_chain_update(kc); if (nkcid) { /* UPDKCID will abort if nkcid is -1, so no need to check */ changed = 1; kcid = nkcid; } UPDKCID(nkcid, 0); ks = kstat_lookup(kc, "unix", 0, "system_misc"); if (kstat_read(kc, ks, 0) == -1) { perror("kstat_read"); quit(1); } /* load average */ kn = kstat_data_lookup(ks, "avenrun_1min"); if (kn) avenrun[0] = kn->value.ui32; kn = kstat_data_lookup(ks, "avenrun_5min"); if (kn) avenrun[1] = kn->value.ui32; kn = kstat_data_lookup(ks, "avenrun_15min"); if (kn) avenrun[2] = kn->value.ui32; /* nproc */ kn = kstat_data_lookup(ks, "nproc"); if (kn) { nproc = kn->value.ui32; #ifdef NO_NPROC if (nproc > maxprocs) reallocproc(2 * nproc); #endif } if (changed) { /** * 2. get data addresses */ ncpu = 0; kn = kstat_data_lookup(ks, "ncpus"); if (kn && kn->value.ui32 > ncpus) { ncpus = kn->value.ui32; cpu_ks = (kstat_t **) realloc(cpu_ks, ncpus * sizeof(kstat_t *)); cpu_stat = (cpu_stat_t *) realloc(cpu_stat, ncpus * sizeof(cpu_stat_t)); } for (ks = kc->kc_chain; ks; ks = ks->ks_next) { if (strncmp(ks->ks_name, "cpu_stat", 8) == 0) { nkcid = kstat_read(kc, ks, NULL); /* if kcid changed, pointer might be invalid */ UPDKCID(nkcid, kcid); cpu_ks[ncpu] = ks; ncpu++; if (ncpu > ncpus) { fprintf(stderr, "kstat finds too many cpus: should be %d\n", ncpus); quit(1); } } } /* note that ncpu could be less than ncpus, but that's okay */ changed = 0; } /** * 3. get data */ for (i = 0; i < ncpu; i++) { nkcid = kstat_read(kc, cpu_ks[i], &cpu_stat[i]); /* if kcid changed, pointer might be invalid */ UPDKCID(nkcid, kcid); } /* return the number of cpus found */ return (ncpu); } #endif /* USE_KSTAT */ #endif /* NOT_FINISHED */ void getLoadIdle(double *UsagePercent, double *IdlePercent) { if (cfg_SendUsage || cfg_SendIdle) { uplog(LOG_WARNING, _("%s %s not implemented for this operating system %s"), _("WARNING:"), _("Usage and idle percentages"), "(stats-sol.c)"); cfg_SendUsage = 0; cfg_SendIdle = 0; } #if defined NOT_FINISHED /* code taken from top m_sunos5.c */ int cpu_states[CPUSTATES]; char *cpustatenames[] = { "idle", "user", "kernel", "iowait", "swap", NULL }; #define CPUSTATE_IOWAIT 3 #define CPUSTATE_SWAP 4 static long cp_time[CPUSTATES]; static long cp_old[CPUSTATES]; static long cp_diff[CPUSTATES]; #ifdef USE_KSTAT kstat_t *ks; kstat_named_t *kn; int cpus_found; #else struct cpu cpu; #endif /* get the cp_time array */ for (j = 0; j < CPUSTATES; j++) cp_time[j] = 0L; #ifdef USE_KSTAT /* use kstat to update all processor information */ cpus_found = kupdate(avenrun); for (i = 0; i < cpus_found; i++) { /* sum counters up to, but not including, wait state counter */ for (j = 0; j < CPU_WAIT; j++) cp_time[j] += (long)cpu_stat[i].cpu_sysinfo.cpu[j]; /* add in wait state breakdown counters */ cp_time[CPUSTATE_IOWAIT] += (long)cpu_stat[i].cpu_sysinfo.wait[W_IO] + (long)cpu_stat[i].cpu_sysinfo.wait[W_PIO]; cp_time[CPUSTATE_SWAP] += (long)cpu_stat[i].cpu_sysinfo.wait[W_SWAP]; } #else /* !USE_KSTAT */ for (i = 0; i < ncpus; i++) if (cpu_offset[i] != 0) { /* get struct cpu for this processor */ (void)getkval(cpu_offset[i], &cpu, sizeof(struct cpu), "cpu"); /* sum counters up to, but not including, wait state counter */ for (j = 0; j < CPU_WAIT; j++) cp_time[j] += (long)cpu.cpu_stat.cpu_sysinfo.cpu[j]; /* add in wait state breakdown counters */ cp_time[CPUSTATE_IOWAIT] += (long)cpu.cpu_stat.cpu_sysinfo.wait[W_IO] + (long)cpu.cpu_stat.cpu_sysinfo.wait[W_PIO]; cp_time[CPUSTATE_SWAP] += (long)cpu.cpu_stat.cpu_sysinfo.wait[W_SWAP]; } /* get load average array */ (void)getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun), "avenrun"); #endif /* USE_KSTAT */ /* convert cp_time counts to percentages */ (void)percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); #endif /* NOT_FINISHED */ } time_t initBoottime(void) { static time_t boottimesecs; static int initialized = 0; if (!initialized) { int fd; struct utmpx ut; int found; fd = open(UTMPX_FILE, O_RDONLY); if (fd < 0) { uplog(LOG_ERR, "%s UTMPX_FILE: %s", _("FATAL ERROR:"), strerror(errno)); exit(EX_OSFILE); } found = 0; while (!found) { if (read(fd, &ut, sizeof(ut)) < 0) found = -1; else if (ut.ut_type == BOOT_TIME) found = 1; } close(fd); if (found == -1) { uplog(LOG_ERR, _("%s Could not find %s."), _("FATAL ERROR:"), "uptime"); exit(EX_OSFILE); } boottimesecs = ut.ut_tv.tv_sec; #if defined DEBUG uplog(LOG_DEBUG, "initBoottime() initialized, boottime.tv_sec: %d", boottimesecs); #endif /* DEBUG */ } return boottimesecs; } void getUptime(unsigned long *uptimeminutes) { static time_t boottimesecs; boottimesecs = initBoottime(); if (boottimesecs) { time_t now; time(&now); *uptimeminutes = (now - boottimesecs) / 60; #if defined DEBUG uplog(LOG_DEBUG, "getUptime() uptime: %d", *uptimeminutes); #endif /* DEBUG */ } else { uplog(LOG_ERR, "getUptime() boottime.tv_sec: failed"); } } /** * @desc Get statistics */ void getstats(unsigned long *uptimeminutes, double *UsagePercent, double *IdlePercent, char *osname, char *osversion, char *cpu, double *loadavg) { getUptime(&*uptimeminutes); if (cfg_SendUsage || cfg_SendIdle) getLoadIdle(&*UsagePercent, &*IdlePercent); if (cfg_sendosname || cfg_sendosversion) initOS(&*osname, &*osversion); if (cfg_sendcpu) initCPU(&*cpu); if (cfg_sendloadavg) getLoadavg(&*loadavg); } #endif /* PLATFORM_SOLARIS */