sysdep.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C), 2000-2002 by Contributors to the monit codebase. 
00003  * All Rights Reserved.
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License as
00007  * published by the Free Software Foundation; either version 2 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  */
00019 
00020 
00021 #include <config.h>
00022 
00023 #ifdef HAVE_SYS_TYPES_H
00024 #include <sys/types.h>
00025 #endif
00026 
00027 #ifdef HAVE_SYS_STAT_H
00028 #include <sys/stat.h>
00029 #endif
00030 
00031 #ifdef HAVE_FCNTL_H
00032 #include <fcntl.h>
00033 #endif
00034 
00035 #ifdef HAVE_STDLIB_H
00036 #include <stdlib.h>
00037 #endif
00038 
00039 #ifdef TIME_WITH_SYS_TIME
00040 #include <time.h>
00041 
00042 #ifdef HAVE_SYS_TIME_H
00043 #include <sys/time.h>
00044 #endif
00045 #else
00046 #include <time.h>
00047 #endif
00048 
00049 #ifdef HAVE_STRING_H
00050 #include <string.h>
00051 #endif
00052 
00053 #include <stdio.h>
00054 
00055 
00056 #ifdef SOLARIS
00057 #include <procfs.h>
00058 #endif
00059 
00060 #ifdef FREEBSD
00061 #include <kvm.h>
00062 #include <sys/param.h>
00063 #include <sys/proc.h>
00064 #include <sys/resource.h>
00065 #include <sys/resourcevar.h>
00066 #include <sys/lock.h>
00067 #include <sys/user.h>
00068 #include <vm/vm.h>
00069 #include <vm/vm_object.h>
00070 #include <vm/pmap.h>
00071 #include <machine/pmap.h>
00072 #include <machine/vmparam.h>
00073 #include <vm/vm_map.h>
00074 #include <sys/vmmeter.h>
00075 #include <sys/sysctl.h>
00076 #endif
00077 
00078 #ifdef LINUX
00079 #include <asm/param.h>
00080 #include <asm/page.h>
00081 #endif
00082 
00083 
00084 #include "process.h"
00085 
00097 /* ------------------------------------------------------------------ Public */
00098 
00099 #ifdef SOLARIS
00100 
00101 int init_process_info_sysdep(void) {
00102 
00103   return (getuid()==0);
00104 
00105 }
00106 
00107 double timestruc_to_tseconds(timestruc_t t) {
00108   return  t.tv_sec * 10 + t.tv_nsec / 100000000.0;
00109 }
00110 
00111 int get_process_info_sysdep(ProcInfo_T p) {
00112 
00113   char buf[4096];
00114   psinfo_t  * psinfo=  (psinfo_t *)&buf;
00115   pstatus_t * pstatus= (pstatus_t *)&buf;
00116 
00117   if (!read_proc_file(buf,4096, "psinfo", p->pid)) {
00118 
00119     return FALSE;
00120 
00121   }
00122 
00123   /* If we don't have any light-weight processes (LWP) then we
00124      are definitely a zombie */
00125 
00126   if ( psinfo->pr_nlwp == 0 ) {
00127 
00128     p->status_flag = PROCESS_ZOMBIE;
00129 
00130   }
00131 
00132 
00133   if ( p->status_flag != PROCESS_ZOMBIE ) {
00134     /* We can't access /proc/$pid/status of a zombie */
00135     /* and does it anyway matter? */
00136 
00137     p->mem_percent = psinfo->pr_pctmem * 1000 / 0x8000;
00138     p->mem_kbyte = psinfo->pr_rssize;
00139 
00140     if (!read_proc_file(buf,4096, "status", p->pid)) {
00141 
00142       return FALSE;
00143 
00144     }
00145 
00146     p->cputime_prev= p->cputime;
00147     p->cputime= ( timestruc_to_tseconds(pstatus->pr_utime) +
00148           timestruc_to_tseconds(pstatus->pr_stime) );
00149 
00150     if( include_children ) {
00151 
00152       p->cputime+= ( timestruc_to_tseconds(pstatus->pr_cutime) +
00153              timestruc_to_tseconds(pstatus->pr_cstime) );
00154 
00155     }
00156     /* first run ? */
00157 
00158     if ( p->time_prev == 0.0 ) {
00159 
00160       p->cputime_prev= p->cputime;
00161 
00162     }
00163 
00164   } else {
00165 
00166     p->cputime_prev= p->cputime = 0;
00167     p->mem_kbyte= 0;
00168     p->mem_percent= 0.0;
00169 
00170   }
00171 
00172   return TRUE;
00173 }
00174 
00175 #endif
00176 
00177 #ifdef LINUX
00178 
00179 #define PAGE_TO_KBYTE_SHIFT PAGE_SHIFT-10
00180 
00181 static long mem_kbyte_max;
00182 
00183 int init_process_info_sysdep(void) {
00184 
00185   struct stat buf;
00186 
00187   /* I hope this is okay hack to get the total memsize. (-: */
00188 
00189   if ( stat("/proc/kcore", &buf) != 0 ) {
00190 
00191     return FALSE;
00192 
00193   }
00194 
00195   mem_kbyte_max = buf.st_size>>10;
00196 
00197   return TRUE;
00198 
00199 }
00200 
00201 int get_process_info_sysdep(ProcInfo_T p) {
00202 
00203   char buf[4096];
00204   char* tmp;
00205   char stat_item_state;
00206   unsigned long stat_item_utime;
00207   unsigned long stat_item_stime;
00208   long stat_item_cutime;
00209   long stat_item_cstime;
00210   long stat_item_rss;
00211 
00212   if (!read_proc_file(buf,4096, "stat", p->pid)) {
00213 
00214     return FALSE;
00215 
00216   }
00217 
00218   /* Move along the buffer to get past the process name */
00219 
00220   tmp = strrchr(buf, ')') + 2;
00221 
00222   /* This implementation is done by using fs/procfs/array.c as a basis
00223      it is also worth looking into the source of the procps utils */
00224 
00225   sscanf(tmp,"%c %*d %*d %*d %*d %*d %*u %*u"
00226      "%*u %*u %*u %lu %lu %ld %ld %*d %*d %*d "
00227      "%*d %*u %*u %ld %*u %*u %*u %*u %*u "
00228      "%*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n",
00229      &stat_item_state, &stat_item_utime, &stat_item_stime,
00230      &stat_item_cutime, &stat_item_cstime, &stat_item_rss);
00231 
00232   /* abs to please the compiler... we dont want to shift negatively.
00233      why doesn't C understand this??? */
00234 
00235   if ( PAGE_TO_KBYTE_SHIFT < 0 ) {
00236 
00237     p->mem_kbyte= stat_item_rss >> abs(PAGE_TO_KBYTE_SHIFT);
00238 
00239   } else {
00240 
00241     p->mem_kbyte= stat_item_rss << abs(PAGE_TO_KBYTE_SHIFT);
00242 
00243   }
00244 
00245   p->mem_percent = (int) ((double) p->mem_kbyte * 1000.0 / mem_kbyte_max);
00246 
00247   /* jiffies -> seconds = 1 / HZ
00248      HZ is defined in "asm/param.h"  and it is usually 1/100s but on
00249      alpha system it is 1/1024s */
00250 
00251   p->cputime_prev = p->cputime;
00252   p->cputime =  ( stat_item_utime + stat_item_stime ) * 10 / HZ;
00253 
00254   if ( include_children ) {
00255 
00256     p->cputime += ( stat_item_cutime + stat_item_cstime ) * 10 / HZ;
00257 
00258   }
00259 
00260   /* first run ? */
00261 
00262   if ( p->time_prev == 0.0 ) {
00263 
00264       p->cputime_prev = p->cputime;
00265 
00266   }
00267 
00268   /* State is Zombie -> then we are a Zombie ... clear or? (-: */
00269 
00270   if ( stat_item_state == 'Z' ) {
00271 
00272     p->status_flag |= PROCESS_ZOMBIE;
00273 
00274   }
00275 
00276   return TRUE;
00277 
00278 }
00279 
00280 #endif
00281 
00282 #ifdef FREEBSD
00283 
00284 #define pagetok(size) ((size) << pageshift)
00285 #define tv2sec(tv) (((u_int64_t) tv.tv_sec * 1000000) + (u_int64_t) tv.tv_usec)
00286 
00287 static int pageshift;
00288 static long mem_kbyte_max;
00289 
00290 #ifndef LOG1024
00291 #define LOG1024         10
00292 #endif
00293 
00294 static kvm_t * kvm_handle;
00295 
00296 static void calcru(struct proc *p, struct timeval *up, struct timeval *sp,
00297            struct timeval *ip)
00298 {
00299   quad_t totusec;
00300   u_quad_t u, st, ut, it, tot;
00301 #if (__FreeBSD_version < 300003)
00302   long sec, usec;
00303 #endif
00304   
00305   st = p->p_sticks;
00306   ut = p->p_uticks;
00307   it = p->p_iticks;
00308   
00309   tot = st + ut + it;
00310   if (tot == 0)
00311     {
00312       st = 1;
00313       tot = 1;
00314     }
00315   
00316 #if (defined __FreeBSD__) && (__FreeBSD_version >= 300003)
00317   totusec = (u_quad_t) p->p_runtime;
00318 #else
00319   sec = p->p_rtime.tv_usec;
00320   usec = p->p_rtime.tv_usec;
00321   
00322   totusec = (quad_t)sec * 1000000 + usec;
00323 #endif
00324   
00325   if(totusec < 0)
00326     {
00327       fprintf (stderr, "calcru: negative time: %ld usec\n",
00328            (long)totusec);
00329       totusec = 0;
00330     }
00331   
00332   u = totusec;
00333   st = (u * st) / tot;
00334   sp->tv_sec = st / 1000000;
00335   sp->tv_usec = st % 1000000;
00336   ut = (u * ut) / tot;
00337   up->tv_sec = ut / 1000000;
00338   up->tv_usec = ut % 1000000;
00339   
00340   if(ip != NULL)
00341     {
00342       it = (u * it) / tot;
00343       ip->tv_sec = it / 1000000;
00344       ip->tv_usec = it % 1000000;
00345     }
00346 }
00347 
00348 int init_process_info_sysdep(void) {
00349 
00350   register int pagesize;
00351   struct vmmeter vmm;
00352   
00353   struct nlist nlst [] = {
00354       { "_bufspace"},
00355       { "_cnt" },
00356       { 0 }
00357   };
00358 
00359   if(getuid()!=0) {
00360 
00361     return FALSE;
00362 
00363   }
00364 
00365   kvm_handle = kvm_open(NULL, NULL, NULL, O_RDONLY, "monit");
00366   
00367   if ( kvm_handle == NULL ) {
00368     
00369     return FALSE;
00370     
00371   }
00372   
00373   /* ----------------------------- INIT MEM -----------------------------*/
00374   /* Got it from libgtop/sysdep/freebsd/mem.c */
00375 
00376   /* Initialize nlist structure */
00377   if (kvm_nlist (kvm_handle, nlst) < 0)
00378   {
00379     return FALSE;
00380   }
00381 
00382   /* get the page size with "getpagesize" and calculate pageshift
00383    * from it */
00384 
00385   pagesize = getpagesize ();
00386   pageshift = 0;
00387   while (pagesize > 1) {
00388 
00389     pageshift++;
00390     pagesize >>= 1;
00391 
00392   }
00393 
00394   /* we only need the amount of log(2)1024 for our conversion */
00395   pageshift -= LOG1024;
00396 
00397   /* Get the data from kvm_* */
00398   if (kvm_read (kvm_handle, nlst[1].n_value,
00399         &vmm, sizeof (vmm)) != sizeof (vmm)) {
00400     return FALSE;
00401 
00402   }
00403 
00404   mem_kbyte_max= vmm.v_pageout_free_min +
00405     vmm.v_free_count + vmm.v_wire_count +
00406     vmm.v_active_count + vmm.v_inactive_count;
00407 
00408   return TRUE;
00409 
00410 }
00411 
00412 int get_process_info_sysdep(ProcInfo_T p) {
00413 
00414   struct kinfo_proc *pinfo;
00415   struct user *u_addr = (struct user *)USRSTACK;
00416   struct pstats pstats;
00417   struct plimit plimit;
00418   struct vmspace *vms;
00419   register struct rusage *rup;
00420   long stat_utime;
00421   long stat_stime;
00422   long stat_cutime;
00423   long stat_cstime;
00424 
00425   u_int64_t rss_lim;
00426 
00427   int count;
00428 
00429   /* Got it from libgtop */
00430 
00431   pinfo = kvm_getprocs(kvm_handle, KERN_PROC_PID, p->pid, &count);
00432 
00433   if ((pinfo == NULL) || (count < 1)) {
00434 
00435     return FALSE;
00436 
00437   }
00438 
00439   /* ----------------------------- CPU TIMING ----------------------------*/
00440   /* Got it from libgtop/sysdep/freebsd/proctime.c */
00441   
00442   if ((pinfo [0].kp_proc.p_flag & P_INMEM) &&
00443       kvm_uread (kvm_handle, &(pinfo [0]).kp_proc,
00444          (unsigned long) &u_addr->u_stats,
00445          (char *) &pstats, sizeof (pstats)) == sizeof (pstats)) {
00446 
00447     rup = &pstats.p_ru;
00448     calcru(&(pinfo [0]).kp_proc,
00449        &rup->ru_utime, &rup->ru_stime, NULL);
00450 
00451     stat_utime = tv2sec (pstats.p_ru.ru_utime);
00452     stat_stime = tv2sec (pstats.p_ru.ru_stime);
00453 
00454     stat_cutime = tv2sec (pstats.p_cru.ru_utime);
00455     stat_cstime = tv2sec (pstats.p_cru.ru_stime);
00456 
00457   } else {
00458 
00459     return FALSE;
00460 
00461   }
00462 
00463   p->cputime_prev= p->cputime;
00464   p->cputime= ( stat_utime + stat_stime );
00465 
00466   if( include_children ) {
00467 
00468     p->cputime+= ( stat_cutime + stat_cstime );
00469 
00470   }
00471 
00472   /* first run ? */
00473 
00474   if ( p->time_prev == 0.0 ) {
00475 
00476     p->cputime_prev= p->cputime;
00477 
00478   }
00479 
00480   /* ----------------------------- MEMORY --------------------------------*/
00481   /* Got it from libgtop/sysdep/freebsd/procmem.c */
00482 
00483   if (kvm_read (kvm_handle,
00484         (unsigned long) pinfo [0].kp_proc.p_limit,
00485         (char *) &plimit, sizeof (plimit)) != sizeof (plimit)) {
00486 
00487     return FALSE;
00488 
00489   }
00490 
00491   rss_lim = (u_int64_t)
00492     (plimit.pl_rlimit [RLIMIT_RSS].rlim_cur);
00493 
00494   vms = &pinfo [0].kp_eproc.e_vm;
00495 
00496   p->mem_kbyte= (u_int64_t) pagetok (vms->vm_rssize);
00497              /* <<LOG1024 removed, we wanna have kb */
00498 
00499   /* ----------------------------- STATE ---------------------------------*/
00500   /* Got it from libgtop/sysdep/freebsd/procstate.c */
00501 
00502   if ( pinfo [0].kp_proc.p_stat == SZOMB ) {
00503 
00504     p->status_flag |= PROCESS_ZOMBIE;
00505 
00506   }
00507 
00508   p->mem_percent = (int) ((double) p->mem_kbyte * 1000.0 / mem_kbyte_max);
00509 
00510   return TRUE;
00511 
00512 }
00513 
00514 #endif
00515