/* called to setup bootcharting */ int bootchart_init( void ) { int ret; char buff[4]; int timeout = 0, count = 0; buff[0] = 0; proc_read( LOG_STARTFILE, buff, sizeof(buff) ); if (buff[0] != 0) { timeout = atoi(buff); } else { /* when running with emulator, androidboot.bootchart=<timeout> * might be passed by as kernel parameters to specify the bootchart * timeout. this is useful when using -wipe-data since the /data * partition is fresh */ char cmdline[1024]; char* s; #define KERNEL_OPTION "androidboot.bootchart=" proc_read( "/proc/cmdline", cmdline, sizeof(cmdline) ); s = strstr(cmdline, KERNEL_OPTION); if (s) { s += sizeof(KERNEL_OPTION)-1; timeout = atoi(s); } } if (timeout == 0) return 0; if (timeout > BOOTCHART_MAX_TIME_SEC) timeout = BOOTCHART_MAX_TIME_SEC; count = (timeout*1000 + BOOTCHART_POLLING_MS-1)/BOOTCHART_POLLING_MS; do {ret=mkdir(LOG_ROOT,0755);}while (ret < 0 && errno == EINTR); selinux_android_restorecon(LOG_ROOT, 0); file_buff_open(log_stat, LOG_STAT); file_buff_open(log_procs, LOG_PROCS); file_buff_open(log_disks, LOG_DISK); /* create kernel process accounting file */ { int fd = open( LOG_ACCT, O_WRONLY|O_CREAT|O_TRUNC,0644); if (fd >= 0) { close(fd); acct( LOG_ACCT ); } } log_header(); return count; }
int sys_read(unsigned int fd,char * buf,int count) { struct file * file; struct m_inode * inode; if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) return -EINVAL; if (!count) return 0; verify_area(buf,count); inode = file->f_inode; if (inode->i_pipe) return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; if (S_ISCHR(inode->i_mode)) return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); if (S_ISBLK(inode->i_mode)) return block_read(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { if (count+file->f_pos > inode->i_size) count = inode->i_size - file->f_pos; if (count<=0) return 0; return file_read(inode,file,buf,count); } if(S_ISPROC(inode->i_mode)) return proc_read(inode, buf, count, &file->f_pos); printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); return -EINVAL; }
int proc_seek_args(proc_obj_t* obj, args_t* args) { regs_t* regs = NULL; list_t* list = NULL; arg_t* arg = NULL; int i; addr_t cur_addr = 0; if (!args) return (-1); regs = proc_get_registers(obj); if (regs == NULL) return (-1); /* ** Browse the stack to find args. */ for (list = args->prev, i = 0; list; list = list->prev, i++) { arg = (arg_t*) list->value; /* ** TODO struct ... */ if (arg->size > sizeof(long double)) { if (regs) free(regs); return (-1); } if (arg->size < sizeof(int)) arg->size = sizeof(int); /* ** 7 first arguments are in register R_O0 to R_06 ** nexts are on the stack. */ arg->value[0] = 0; if (last_call_reg && i < 6) long_to_strval(last_call_reg->greg[R_O0 + i], arg); else { long ulr; if (cur_addr == 0) cur_addr = regs->greg[R_FP] + 92; if (proc_read(obj, cur_addr, sizeof(long), (char*) &ulr) != sizeof(long)) return (-1); long_to_strval(ulr, arg); cur_addr += arg->size; } if (list == args) break; } free(regs); return (0); }
static long long get_uptime_jiffies() { char buff[64]; long long jiffies = 0; if (proc_read("/proc/uptime", buff, sizeof(buff)) > 0) jiffies = 100LL*strtod(buff,NULL); return jiffies; }
void setup_history() { /* * The /proc file size will vary during intervals, use double of current * size to have enough buffer for growing values. */ meminfo_size = proc_read_size("/proc/meminfo") * 2; vmstat_size = proc_read_size("/proc/vmstat") * 2; cpustat_size = CPUSTAT_SIZE; meminfo = malloc(meminfo_size * (history_max + 1)); if (!meminfo) cpuplugd_exit("Out of memory: meminfo\n"); vmstat = malloc(vmstat_size * (history_max + 1)); if (!vmstat) cpuplugd_exit("Out of memory: vmstat\n"); cpustat = malloc(cpustat_size * (history_max + 1)); if (!cpustat) cpuplugd_exit("Out of memory: cpustat\n"); timestamps = malloc(sizeof(double) * (history_max + 1)); if (!timestamps) cpuplugd_exit("Out of memory: timestamps\n"); /* * Read history data, at least 1 interval for swaprate, apcr, idle, etc. */ history_current = 0; cpuplugd_info("Waiting %i intervals to accumulate history.\n", history_max); do { time_read(×tamps[history_current]); proc_read(meminfo + history_current * meminfo_size, "/proc/meminfo", meminfo_size); proc_read(vmstat + history_current * vmstat_size, "/proc/vmstat", vmstat_size); proc_cpu_read(cpustat + history_current * cpustat_size); sleep(cfg.update); history_current++; } while (history_current < history_max); history_current--; }
static void do_log_procs(FileBuff log) { DIR* dir = opendir("/proc"); struct dirent* entry; do_log_uptime(log); while ((entry = readdir(dir)) != NULL) { /* only match numeric values */ char* end; int pid = strtol( entry->d_name, &end, 10); if (end != NULL && end > entry->d_name && *end == 0) { char filename[32]; char buff[1024]; char cmdline[1024]; int len; int fd; /* read command line and extract program name */ snprintf(filename,sizeof(filename),"/proc/%d/cmdline",pid); proc_read(filename, cmdline, sizeof(cmdline)); /* read process stat line */ snprintf(filename,sizeof(filename),"/proc/%d/stat",pid); fd = open(filename,O_RDONLY); if (fd >= 0) { len = unix_read(fd, buff, sizeof(buff)-1); close(fd); if (len > 0) { int len2 = strlen(cmdline); if (len2 > 0) { /* we want to substitute the process name with its real name */ const char* p1; const char* p2; buff[len] = 0; p1 = strchr(buff, '('); p2 = strchr(p1, ')'); file_buff_write(log, buff, p1+1-buff); file_buff_write(log, cmdline, strlen(cmdline)); file_buff_write(log, p2, strlen(p2)); } else { /* no substitution */ file_buff_write(log,buff,len); } } } } } closedir(dir); do_log_ln(log); }
static void log_header(void) { FILE* out; char cmdline[1024]; char uname[128]; char cpuinfo[128]; char* cpu; char date[32]; time_t now_t = time(NULL); struct tm now = *localtime(&now_t); strftime(date, sizeof(date), "%x %X", &now); out = fopen( LOG_HEADER, "w" ); if (out == NULL) return; proc_read("/proc/cmdline", cmdline, sizeof(cmdline)); proc_read("/proc/version", uname, sizeof(uname)); proc_read("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo)); cpu = strchr( cpuinfo, ':' ); if (cpu) { char* p = strchr(cpu, '\n'); cpu += 2; if (p) *p = 0; } fprintf(out, "version = %s\n", VERSION); fprintf(out, "title = Boot chart for Linux ( %s )\n", date); fprintf(out, "system.uname = %s\n", uname); fprintf(out, "system.release = 0.0\n"); fprintf(out, "system.cpu = %s\n", cpu); fprintf(out, "system.kernel.options = %s\n", cmdline); fclose(out); }
void *proc_mmap(struct proc *p, int prot, int flags) { void *addr = NULL; char *code = "\xcd\x80\x00\x00\x00\x00\x00\x00"; proc_save(p); p->regs = p->oregs; p->regs.rax = SYS_mmap; p->regs.rdi = 0; p->regs.rsi = 4; p->regs.rdx = prot; p->regs.r10 = flags; p->regs.r8 = -1; p->regs.r9 = 0; p->regs.rip = EBASE; char savebuf[8] = {0}; int n = proc_read(p, (void*)EBASE, savebuf, 8); if (n != 8) { perror("read"); exit(1); } n = proc_write(p, (void*)EBASE, code, 8); if (n != 8) { perror("write"); exit(1); } proc_regs(p, 1); printf("syscall mmap begin...\n"); ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); while (1) { proc_wait(p); if (p->stat != SYSCALL_STOP) { goto cont; } proc_regs(p, 0); if (p->regs.orig_rax == SYS_mmap) { if (p->insys == 0) { p->insys = 1; } else if (p->insys == 1) { addr = (void *)p->regs.rax; p->insys = 0; break; } } cont: ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); } proc_write(p, (void *)EBASE, savebuf, 4); proc_restore(p); return addr; }
static void detect_call_and_save_args(proc_obj_t* obj, regs_t* regs) { addr_t r; if (proc_read(obj, regs->greg[R_PC], sizeof(int), (char*) &r) != -1) { if ((0xFF000000 & r) == 0x7f000000 || (0xFF000000 & r) == 0x40000000) { if (last_call_reg) free(last_call_reg); last_call_reg = proc_get_registers(obj); } } }
int proc_mprotect(struct proc *p, void *addr, int prot) { int ret = 0; unsigned long err = 0; char *code = "\x0f\x05\x00\x00\x00\x00\x00\x00"; proc_save(p); p->regs = p->oregs; p->regs.rax = SYS_mprotect; p->regs.rdi = (unsigned long)addr; p->regs.rsi = 0x1000; p->regs.rdx = prot; p->regs.rip = EBASE; char savebuf[8] = {0}; int n = proc_read(p, (void*)EBASE, savebuf, 8); if (n != 8) { perror("read"); exit(1); } n = proc_write(p, (void*)EBASE, code, 8); if (n != 8) { perror("write"); exit(1); } proc_regs(p, 1); ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); while (1) { proc_wait(p); if (p->stat != SYSCALL_STOP) { printf("not syscall\n"); goto cont; } proc_regs(p, 0); if (p->regs.orig_rax == SYS_mprotect) { if (p->insys == 0) { p->insys = 1; } else if (p->insys == 1) { err = p->regs.rax; p->insys = 0; break; } } cont: ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); } proc_write(p, (void *)EBASE, savebuf, 8); proc_restore(p); printf("%d, %s\n", err, strerror(-err)); return ret; }
/* called each time you want to perform a bootchart sampling op */ int bootchart_step( void ) { do_log_file(log_stat, "/proc/stat"); do_log_file(log_disks, "/proc/diskstats"); do_log_procs(log_procs); /* we stop when /data/bootchart-stop contains 1 */ { char buff[2]; if (proc_read(LOG_STOPFILE,buff,sizeof(buff)) > 0 && buff[0] == '1') { return -1; } } return 0; }
static int do_proc_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int (*proc_read)(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi); char *error; dlerror(); /* Clear any existing error */ proc_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "proc_read"); error = dlerror(); if (error != NULL) { fprintf(stderr, "proc_read: %s\n", error); return -1; } return proc_read(path, buf, size, offset, fi); }
void proc_exit(struct proc *p, int no) { char *code = "\xcd\x80\x00\x00\x00\x00\x00\x00"; proc_save(p); p->regs = p->oregs; p->regs.rax = SYS_exit; p->regs.rdi = no; p->regs.rip = EBASE; char savebuf[8] = {0}; int n = proc_read(p, (void*)EBASE, savebuf, 8); if (n != 8) { perror("read"); exit(1); } proc_write(p, (void*)EBASE, code, 8); proc_regs(p, 1); printf("syscall exit begin...\n"); ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); while (1) { proc_wait(p); if (p->stat == DEAD) { printf("%p: ", p->status); if (WIFEXITED(p->status)) { printf("exit code %d\n", WEXITSTATUS(p->status)); } else if (WIFSIGNALED(p->status)) { printf("signal %d\n", WTERMSIG(p->status)); } break; } if (p->stat != SYSCALL_STOP) { goto cont; } proc_regs(p, 0); if (p->regs.orig_rax == SYS_exit) { if (p->insys == 0) { p->insys = 1; } else if (p->insys == 1) { p->insys = 0; break; } } cont: ptrace(PTRACE_SYSCALL, p->pid, NULL, NULL); } }
void proc_mem (struct mem_brk * mem_brk) { if (mem_brk == NULL) return; struct proc_file * proc = mem_brk->ext->proc; struct data * p = mem_brk->ext->p; if(proc[P_MEMINFO].read_this_interval == 0) proc_read(proc, P_MEMINFO); p->mem.memtotal = proc_mem_search(proc, "MemTotal"); p->mem.memfree = proc_mem_search(proc, "MemFree"); p->mem.memshared = proc_mem_search(proc, "MemShared"); p->mem.buffers = proc_mem_search(proc, "Buffers"); p->mem.cached = proc_mem_search(proc, "Cached"); p->mem.swapcached = proc_mem_search(proc, "SwapCached"); p->mem.active = proc_mem_search(proc, "Active"); p->mem.inactive = proc_mem_search(proc, "Inactive"); p->mem.hightotal = proc_mem_search(proc, "HighTotal"); p->mem.highfree = proc_mem_search(proc, "HighFree"); p->mem.lowtotal = proc_mem_search(proc, "LowTotal"); p->mem.lowfree = proc_mem_search(proc, "LowFree"); p->mem.swaptotal = proc_mem_search(proc, "SwapTotal"); p->mem.swapfree = proc_mem_search(proc, "SwapFree"); #ifdef LARGEMEM p->mem.dirty = proc_mem_search(proc, "Dirty"); p->mem.writeback = proc_mem_search(proc, "Writeback"); p->mem.mapped = proc_mem_search(proc, "Mapped"); p->mem.slab = proc_mem_search(proc, "Slab"); p->mem.committed_as = proc_mem_search(proc, "Committed_AS"); p->mem.pagetables = proc_mem_search(proc, "PageTables"); p->mem.hugetotal = proc_mem_search(proc, "HugePages_Total"); p->mem.hugefree = proc_mem_search(proc, "HugePages_Free"); p->mem.hugesize = proc_mem_search(proc, "Hugepagesize"); #else p->mem.bigfree = proc_mem_search(proc, "BigFree"); #endif /*LARGEMEM*/ }
/** void loop_all_pids(char *ps, pid_t max_pid, int *_errors, int *_total) * Check all the available PIDs for hidden stuff. */ void loop_all_pids(char *ps, pid_t max_pid, int *_errors, int *_total) { int _kill0 = 0; int _kill1 = 0; int _gsid0 = 0; int _gsid1 = 0; int _gpid0 = 0; int _gpid1 = 0; int _ps0 = -1; int _proc_stat = 0; int _proc_read = 0; int _proc_chdir = 0; pid_t i = 1; pid_t my_pid; char command[OS_SIZE_1024 +1]; my_pid = getpid(); for(;;i++) { if((i <= 0)||(i > max_pid)) break; (*_total)++; _kill0 = 0; _kill1 = 0; _gsid0 = 0; _gsid1 = 0; _gpid0 = 0; _gpid1 = 0; _ps0 = -1; _proc_stat = 0; _proc_read = 0; _proc_chdir = 0; /* kill test */ if(!((kill(i, 0) == -1)&&(errno == ESRCH))) { _kill0 = 1; } /* getsid to test */ if(!((getsid(i) == -1)&&(errno == ESRCH))) { _gsid0 = 1; } /* getpgid test */ if(!((getpgid(i) == -1)&&(errno == ESRCH))) { _gpid0 = 1; } /* proc stat */ _proc_stat = proc_stat(i); /* proc readdir */ _proc_read = proc_read(i); /* proc chdir */ _proc_chdir = proc_chdir(i); /* IF PID does not exist, keep going */ if(!_kill0 && !_gsid0 && !_gpid0 && !_proc_stat && !_proc_read && !_proc_chdir) { continue; } /* We do not need to look at our own pid */ else if(i == my_pid) { continue; } /* Checking the number of errors */ if((*_errors) > 15) { char op_msg[OS_SIZE_1024 +1]; snprintf(op_msg,OS_SIZE_1024,"Excessive number of hidden processes" ". It maybe a false-positive or " "something really bad is going on."); notify_rk(ALERT_SYSTEM_CRIT, op_msg); return; } /* checking if process appears on ps */ if(*ps) { snprintf(command, OS_SIZE_1024, "%s -p %d > /dev/null 2>&1", ps, (int)i); /* Found PID on ps */ _ps0 = 0; if(system(command) == 0) _ps0 = 1; } /* If we are being run by the ossec hids, sleep here (no rush) */ #ifdef OSSECHIDS sleep(2); #endif /* Everyone returned ok */ if(_ps0 && _kill0 && _gsid0 && _gpid0 && _proc_stat && _proc_read) { continue; } /* If our kill or getsid system call, got the * PID , but ps didn't, we need to find if it was a problem * with a PID being deleted (not used anymore) */ { if(!((getsid(i) == -1)&&(errno == ESRCH))) { _gsid1 = 1; } if(!((kill(i, 0) == -1)&&(errno == ESRCH))) { _kill1 = 1; } if(!((getpgid(i) == -1)&&(errno == ESRCH))) { _gpid1 = 1; } _proc_stat = proc_stat(i); _proc_read = proc_read(i); _proc_chdir = proc_chdir(i); /* If it matches, process was terminated */ if(!_gsid1 &&!_kill1 &&!_gpid1 &&!_proc_stat && !_proc_read &&!_proc_chdir) { continue; } } #ifdef AIX /* Ignoring AIX wait and sched programs. */ if((_gsid0 == _gsid1) && (_kill0 == _kill1) && (_gpid0 == _gpid1) && (_ps0 == 1) && (_gsid0 == 1) && (_kill0 == 0)) { /* The wait and sched programs do not respond to kill 0. * So, if everything else finds it, including ps, getpid, getsid, * but not * kill, we can safely ignore on AIX. * A malicious program would specially try to hide from ps.. */ continue; } #endif if((_gsid0 == _gsid1)&& (_kill0 == _kill1)&& (_gsid0 != _kill0)) { /* If kill found, but getsid and getpgid didnt', it may * be a defunct process -- ignore. */ if(!((_kill0 == 1)&&(_gsid0 == 0)&&(_gpid0 == 0)&&(_gsid1 == 0))) { char op_msg[OS_SIZE_1024 +1]; snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from " "kill (%d) or getsid (%d). Possible kernel-level" " rootkit.", (int)i, _kill0, _gsid0); notify_rk(ALERT_ROOTKIT_FOUND, op_msg); (*_errors)++; } } else if((_kill1 != _gsid1)|| (_gpid1 != _kill1)|| (_gpid1 != _gsid1)) { /* See defunct process comment above. */ if(!((_kill1 == 1)&&(_gsid1 == 0)&&(_gpid0 == 0)&&(_gsid1 == 0))) { char op_msg[OS_SIZE_1024 +1]; snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from " "kill (%d), getsid (%d) or getpgid. Possible " "kernel-level rootkit.", (int)i, _kill1, _gsid1); notify_rk(ALERT_ROOTKIT_FOUND, op_msg); (*_errors)++; } } else if((_proc_read != _proc_stat)|| (_proc_read != _proc_chdir)|| (_proc_stat != _kill1)) { /* checking if the pid is a thread (not showing on proc */ if(!noproc && !check_rc_readproc((int)i)) { char op_msg[OS_SIZE_1024 +1]; snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from " "/proc. Possible kernel level rootkit.", (int)i); notify_rk(ALERT_ROOTKIT_FOUND, op_msg); (*_errors)++; } } else if(_gsid1 && _kill1 && !_ps0) { /* checking if the pid is a thread (not showing on ps */ if(!check_rc_readproc((int)i)) { char op_msg[OS_SIZE_1024 +1]; snprintf(op_msg, OS_SIZE_1024, "Process '%d' hidden from " "ps. Possible trojaned version installed.", (int)i); notify_rk(ALERT_ROOTKIT_FOUND, op_msg); (*_errors)++; } } } }
void ProcWriteInt(struct proc *p, void *addr, int n) { char buf[8] = {0}; proc_read(p, addr, buf, 8); memmove(buf, &n, 4); proc_write(p, addr, buf, 8); }
list_t* proc_get_depends_list(proc_obj_t* obj) { Elf_Ehdr ehdr; Elf_Phdr phdr; Elf_Dyn dyn; struct link_map lmap; unsigned long phdr_addr, dyn_addr, addr; struct r_debug rdebug; char buf[PATH_MAX + 1]; list_t* ret = NULL; depend_t* cur = NULL; /* ** Get elf header. */ if (proc_read(obj, 0x10000, sizeof(Elf32_Ehdr), (char*) &ehdr) == -1) return (NULL); if (!IS_ELF(ehdr)) { errno = EFTRACE; ftrace_errstr = "Not Elf ?!"; exit(1); return (NULL); } /* ** Get program Headers and find the Dynamic program header.. */ phdr_addr = 0x10000 + ehdr.e_phoff; if (proc_read(obj, phdr_addr, sizeof(Elf32_Phdr), (char*) &phdr) == -1) return (NULL); while (phdr.p_type != PT_DYNAMIC) { if (proc_read(obj, phdr_addr += sizeof(Elf32_Phdr), sizeof(Elf32_Phdr), (char*) &phdr) == -1) return (NULL); } if (phdr.p_type != PT_DYNAMIC) return (NULL); /* ** Browse evrey dyn and find {DT_PLTGOT|DT_DEBUG} */ if (proc_read(obj, phdr.p_vaddr, sizeof(Elf32_Dyn), (char*) &dyn) == -1) return (NULL); dyn_addr = phdr.p_vaddr; /* ** --------------------------- ** Retrieve with the DT_DEBUG */ while (dyn.d_tag != DT_DEBUG) { if (proc_read(obj, dyn_addr += sizeof(Elf32_Dyn), sizeof(Elf32_Dyn), (char*) &dyn) == -1) return (NULL); } if (dyn.d_tag != DT_DEBUG) return (NULL); /* printf("struct rdebug found @ 0x%x\n", dyn.d_un.d_ptr); */ /* ** Get addresse's struct rdebug */ if (proc_read(obj, dyn.d_un.d_ptr, sizeof(struct r_debug), (char*) &rdebug) == -1) return (NULL); /* ** Here we have the link_map addr. ** Create the depend list... */ for (addr = (unsigned long) rdebug.r_map; addr; addr = (unsigned long) lmap.l_next) { if (proc_read(obj, addr, sizeof(struct link_map), (char*) &lmap) == -1) goto proc_get_depends_list_failed; if (lmap.l_name == 0) continue; if (proc_read(obj, (long) lmap.l_name, PATH_MAX, (char*) buf) == -1) goto proc_get_depends_list_failed; cur = malloc(sizeof(depend_t)); if (cur == NULL) goto proc_get_depends_list_failed; cur->path = strdup(buf); cur->base_addr = (addr_t) lmap.l_addr; ret = list_add(ret, cur); if (ret == NULL) goto proc_get_depends_list_failed; } return (ret); /* ** If failed, free list And return NULL. */ proc_get_depends_list_failed: for (; ret; ) { cur = (depend_t*) ret->value; ret = list_del(ret, cur); if (cur && cur->path) free(cur->path); free(cur); } return (NULL); }
int main(int argc, char *argv[]) { double interval; int fd, rc; reload_pending = 0; sym_names_count = sizeof(sym_names) / sizeof(struct symbol_names); varinfo_size = VARINFO_SIZE; varinfo = calloc(varinfo_size, 1); if (!varinfo) { cpuplugd_error("Out of memory: varinfo\n"); exit(1); } /* * varinfo must start with '\n' for correct string matching * in get_var_rvalue(). */ varinfo[0] = '\n'; /* Parse the command line options */ parse_options(argc, argv); /* flock() lock file to prevent multiple instances of cpuplugd */ fd = open(LOCKFILE, O_CREAT | O_RDONLY, S_IRUSR); if (fd == -1) { cpuplugd_error("Cannot open lock file %s: %s\n", LOCKFILE, strerror(errno)); exit(1); } rc = flock(fd, LOCK_EX | LOCK_NB); if (rc) { cpuplugd_error("flock() failed on lock file %s: %s\nThis might " "indicate that an instance of this daemon is " "already running.\n", LOCKFILE, strerror(errno)); exit(1); } /* Make sure that the daemon is not started multiple times */ check_if_started_twice(); /* Store daemon pid also in foreground mode */ handle_signals(); handle_sighup(); /* Need 1 history level minimum for internal symbols */ history_max = 1; /* * Parse arguments from the configuration file, also calculate * history_max */ parse_configfile(configfile); if (history_max > MAX_HISTORY) cpuplugd_exit("History depth %i exceeded maximum (%i)\n", history_max, MAX_HISTORY); /* Check the settings in the configuration file */ check_config(); if (!foreground) { rc = daemon(1, 0); if (rc < 0) cpuplugd_exit("Detach from terminal failed: %s\n", strerror(errno)); } /* Store daemon pid */ store_pid(); /* Unlock lock file */ flock(fd, LOCK_UN); close(fd); /* Install signal handler for floating point exceptions */ rc = feenableexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INVALID); act.sa_flags = SA_NODEFER; sigemptyset(&act.sa_mask); act.sa_handler = sigfpe_handler; if (sigaction(SIGFPE, &act, NULL) < 0) cpuplugd_exit("sigaction( SIGFPE, ... ) failed - reason %s\n", strerror(errno)); setup_history(); /* Main loop */ while (1) { if (reload_pending) { // check for daemon reload reload_daemon(); reload_pending = 0; } history_prev = history_current; history_current = (history_current + 1) % (history_max + 1); time_read(×tamps[history_current]); proc_read(meminfo + history_current * meminfo_size, "/proc/meminfo", meminfo_size); proc_read(vmstat + history_current * vmstat_size, "/proc/vmstat", vmstat_size); proc_cpu_read(cpustat + history_current * cpustat_size); interval = timestamps[history_current] - timestamps[history_prev]; cpuplugd_debug("config update interval: %ld seconds\n", cfg.update); cpuplugd_debug("real update interval: %f seconds\n", interval); /* Run code that may signal failure via longjmp. */ if (cpu == 1) { if (setjmp(jmpenv) == 0) eval_cpu_rules(); else cpuplugd_error("Floating point exception, " "skipping cpu rule " "evaluation.\n"); } if (memory == 1) { if (setjmp(jmpenv) == 0) eval_mem_rules(interval); else cpuplugd_error("Floating point exception, " "skipping memory rule " "evaluation.\n"); } sleep(cfg.update); } return 0; }
TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS, jlongArray inf) { jint rv; int i; jsize ilen = (*e)->GetArrayLength(e, inf); jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL); UNREFERENCED(o); if (ilen < 16) { return APR_EINVAL; } for (i = 0; i < 16; i++) pvals[i] = 0; #if defined(__linux__) { struct sysinfo info; if (sysinfo(&info)) rv = apr_get_os_error(); else { pvals[0] = (jlong)(info.totalram * info.mem_unit); pvals[1] = (jlong)(info.freeram * info.mem_unit); pvals[2] = (jlong)(info.totalswap * info.mem_unit); pvals[3] = (jlong)(info.freeswap * info.mem_unit); pvals[4] = (jlong)(info.sharedram * info.mem_unit); pvals[5] = (jlong)(info.bufferram * info.mem_unit); pvals[6] = (jlong)(100 - (info.freeram * 100 / info.totalram)); rv = APR_SUCCESS; } } #elif defined(sun) { /* static variables with basic procfs info */ static long creation = 0; /* unix timestamp of process creation */ static int psinf_fd = 0; /* file descriptor for the psinfo procfs file */ static int prusg_fd = 0; /* file descriptor for the usage procfs file */ static size_t rss = 0; /* maximum of resident set size from previous calls */ /* static variables with basic kstat info */ static kstat_ctl_t *kstat_ctl = NULL; /* kstat control object, only initialized once */ static kstat_t *kstat_cpu[MAX_CPUS]; /* array of kstat objects for per cpu statistics */ static int cpu_count = 0; /* number of cpu structures found in kstat */ static kid_t kid = 0; /* kstat ID, for which the kstat_ctl holds the correct chain */ /* non-static variables - general use */ int res = 0; /* general result state */ /* non-static variables - sysinfo/swapctl use */ long ret_sysconf; /* value returned from sysconf call */ long tck_dividend; /* factor used by transforming tick numbers to milliseconds */ long tck_divisor; /* divisor used by transforming tick numbers to milliseconds */ long sys_pagesize = sysconf(_SC_PAGESIZE); /* size of a system memory page in bytes */ long sys_clk_tck = sysconf(_SC_CLK_TCK); /* number of system ticks per second */ struct anoninfo info; /* structure for information about sizes in anonymous memory system */ /* non-static variables - procfs use */ psinfo_t psinf; /* psinfo structure from procfs */ prusage_t prusg; /* usage structure from procfs */ size_t new_rss = 0; /* resident set size read from procfs */ time_t now; /* time needed for calculating process creation time */ /* non-static variables - kstat use */ kstat_t *kstat = NULL; /* kstat working pointer */ cpu_sysinfo_t cpu; /* cpu sysinfo working pointer */ kid_t new_kid = 0; /* kstat ID returned from chain update */ int new_kstat = 0; /* flag indicating, if kstat structure has changed since last call */ rv = APR_SUCCESS; if (sys_pagesize <= 0) { rv = apr_get_os_error(); } else { ret_sysconf = sysconf(_SC_PHYS_PAGES); if (ret_sysconf >= 0) { pvals[0] = (jlong)((jlong)sys_pagesize * ret_sysconf); } else { rv = apr_get_os_error(); } ret_sysconf = sysconf(_SC_AVPHYS_PAGES); if (ret_sysconf >= 0) { pvals[1] = (jlong)((jlong)sys_pagesize * ret_sysconf); } else { rv = apr_get_os_error(); } res=swapctl(SC_AINFO, &info); if (res >= 0) { pvals[2] = (jlong)((jlong)sys_pagesize * info.ani_max); pvals[3] = (jlong)((jlong)sys_pagesize * info.ani_free); pvals[6] = (jlong)(100 - (jlong)info.ani_free * 100 / info.ani_max); } else { rv = apr_get_os_error(); } } if (psinf_fd == 0) { psinf_fd = proc_open("psinfo"); } res = proc_read(&psinf, PSINFO_T_SZ, psinf_fd); if (res >= 0) { new_rss = psinf.pr_rssize*1024; pvals[13] = (jlong)(new_rss); if (new_rss > rss) { rss = new_rss; } pvals[14] = (jlong)(rss); } else { psinf_fd = 0; rv = apr_get_os_error(); } if (prusg_fd == 0) { prusg_fd = proc_open("usage"); } res = proc_read(&prusg, PRUSAGE_T_SZ, prusg_fd); if (res >= 0) { if (creation <= 0) { time(&now); creation = (long)(now - (prusg.pr_tstamp.tv_sec - prusg.pr_create.tv_sec)); } pvals[10] = (jlong)(creation); pvals[11] = (jlong)((jlong)prusg.pr_stime.tv_sec * 1000 + (prusg.pr_stime.tv_nsec / 1000000)); pvals[12] = (jlong)((jlong)prusg.pr_utime.tv_sec * 1000 + (prusg.pr_utime.tv_nsec / 1000000)); pvals[15] = (jlong)(prusg.pr_majf); } else { prusg_fd = 0; rv = apr_get_os_error(); } if (sys_clk_tck <= 0) { rv = apr_get_os_error(); } else { tck_dividend = 1000; tck_divisor = sys_clk_tck; for (i = 0; i < 3; i++) { if (tck_divisor % 2 == 0) { tck_divisor = tck_divisor / 2; tck_dividend = tck_dividend / 2; } if (tck_divisor % 5 == 0) { tck_divisor = tck_divisor / 5; tck_dividend = tck_dividend / 5; } } if (kstat_ctl == NULL) { kstat_ctl = kstat_open(); kid = kstat_ctl->kc_chain_id; new_kstat = 1; } else { new_kid = kstat_chain_update(kstat_ctl); if (new_kid < 0) { res=kstat_close(kstat_ctl); kstat_ctl = kstat_open(); kid = kstat_ctl->kc_chain_id; new_kstat = 1; } else if (new_kid > 0 && kid != new_kid) { kid = new_kid; new_kstat = 1; } } if (new_kstat) { cpu_count = 0; for (kstat = kstat_ctl->kc_chain; kstat; kstat = kstat->ks_next) { if (strncmp(kstat->ks_name, "cpu_stat", 8) == 0) { kstat_cpu[cpu_count++]=kstat; } } } for (i = 0; i < cpu_count; i++) { new_kid = kstat_read(kstat_ctl, kstat_cpu[i], NULL); if (new_kid >= 0) { cpu = ((cpu_stat_t *)kstat_cpu[i]->ks_data)->cpu_sysinfo; if ( tck_divisor == 1 ) { pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend); pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend); pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend); pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend); } else { pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend / tck_divisor); pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend / tck_divisor); pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend / tck_divisor); pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend / tck_divisor); } } } } /* * The next two are not implemented yet for Solaris * inf[4] - Amount of shared memory * inf[5] - Memory used by buffers * */ } #elif defined(DARWIN) uint64_t mem_total; size_t len = sizeof(mem_total); vm_statistics_data_t vm_info; mach_msg_type_number_t info_count = HOST_VM_INFO_COUNT; sysctlbyname("hw.memsize", &mem_total, &len, NULL, 0); pvals[0] = (jlong)mem_total; host_statistics(mach_host_self (), HOST_VM_INFO, (host_info_t)&vm_info, &info_count); pvals[1] = (jlong)(((double)vm_info.free_count)*vm_page_size); pvals[6] = (jlong)(100 - (pvals[1] * 100 / mem_total)); rv = APR_SUCCESS; /* DARWIN */ #else rv = APR_ENOTIMPL; #endif (*e)->ReleaseLongArrayElements(e, inf, pvals, 0); return rv; }