/* * Copyright (c) 2004 Teodor Sigaev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "tlog.h" #include "tmalloc.h" #include "connection.h" #include "top.h" #ifdef FreeBSD static int getsysctl(char *name, void *ptr, size_t len) { size_t nlen = len; if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { tlog(TL_ALARM, "sysctl(\"%s\", ...) failed: %s\n", name, strerror(errno)); return 1; } if (nlen != len) { tlog(TL_ALARM, "sysctl(\"%s\", ...) expected %lu, got %lu\n", name, (unsigned long)len, (unsigned long)nlen); return 1; } return 0; } #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) static void getmeminfo(TCMsgTop *m) { int memory_tmp; long memory_tmp1; if ( GETSYSCTL("vm.stats.vm.v_inactive_count", memory_tmp) == 0 ) m->freemem += memory_tmp; else m->freemem = -1; if ( m->freemem>=0 && GETSYSCTL("vm.stats.vm.v_free_count", memory_tmp) == 0 ) m->freemem += memory_tmp; else m->freemem = -1; if ( m->freemem>=0 ) m->freemem *= getpagesize(); if ( GETSYSCTL("hw.physmem", memory_tmp1) == 0 ) m->physmem = memory_tmp1; } #elif defined Linux /* end FreeBSD */ #define MEMBUFSIZE 256 /* * if str mathes by pattern returns poineter to begin of value * and NULL in opposite case */ static char* cmpPattern( char *str, char *pattern ) { while( *str != '\0' && *str == *pattern ) { str++; pattern++; } if ( *pattern == '\0' ) { if ( *str == '\0' ) return NULL; /* * str matches by pattern, so skip leading spaces * before actual value */ while( *str != '\0' ) { if ( isspace( *str ) ) str++; else return str; } } return NULL; } static void getmeminfo(TCMsgTop *m) { FILE *fh; static char buf[MEMBUFSIZE]; char *ptr; fh=fopen("/proc/meminfo", "r"); if (fh == NULL) { tlog(TL_ALARM, "fopen(\"/proc/meminfo\", ...) failed: %s", strerror(errno)); return; } while( fgets(buf, MEMBUFSIZE, fh) && (m->physmem == 0 || m->freemem == 0) ) { if ( (ptr = cmpPattern(buf, "MemTotal:")) != NULL ) { m->physmem = atoll(ptr) * 1024; /* mem in Kb */ } else if ( (ptr = cmpPattern(buf, "MemFree:")) != NULL ) { m->freemem = atoll(ptr) * 1024; /* mem in Kb */ } } fclose(fh); } #else /* end Linux*/ #error No memory stat for current OS #endif #define NITEM 0 static void fillMsgTop(TCMsgTop *m) { double lll[3]; memset(m,0,sizeof(TCMsgTop)); if ( getloadavg(lll,3) >= NITEM+1 ) m->load=lll[NITEM]; else m->load=-1.0; m->freemem = 0; m->physmem = 0; getmeminfo(m); tlog( TL_DEBUG, "Sended topdata: %.2f load, %lld free, %lld total", m->load, m->freemem, m->physmem); } static int sendTop(Msg *msg) { TCMsg *pmsg; int msglen = TCMSGHDRSZ + sizeof(TCMsgTop); if ( !msg->msg ) { pmsg = (TCMsg*)tmalloc(msglen); msg->msg = pmsg; } else { pmsg = msg->msg; } pmsg->len = msglen; pmsg->type=TOPMSGTYPE; fillMsgTop( (TCMsgTop*)(pmsg->data) ); return TC_sendMsg(msg); } void usage() { fputs( "Copyright (c) 2004-2007 Teodor Sigaev . All rights reserved.\n" "sendtop - small daemon to send load of box to server\n" "Usage:\n" "./sendtop [-D] -h HOST [-p PORT] [-s PERIOD]\n" " -D - debug mode (do not daemonize, print to stderr instead of syslog)\n" " -h HOST - server IP to send data\n" " -p PORT - port number of server\n" " -s PERIOD - period of of send (in seconds)\n", stdout ); exit(1); } extern char *optarg; int main( int argc, char *argv[] ) { int ch; Msg msg; int debug=0, child=0; int period=30; msg.port = TOPD_SERVER_DEFAULT_PORT; msg.host = NULL; msg.msg = NULL; msg.sockfd =-1; while( (ch=getopt(argc, argv, "h:p:s:D"))!=-1) { switch(ch) { case 'h': msg.host = strdup(optarg); break; case 'p': msg.port = atoi(optarg); break; case 's': period = atoi(optarg); break; case 'D': debug=1; break; default: usage(); return 1; } } if (!msg.host) usage(); signal(SIGCHLD, SIG_IGN); if ( debug ) opentlog( TL_OPEN_STDERR, TL_DEBUG, NULL); else opentlog( TL_OPEN_SYSLOG, TL_INFO, NULL); if ( debug || (child = fork()) == 0 ) { while(1) { sendTop(&msg); sleep(period); } TC_closefd(&msg); } if (child == -1) tlog(TL_CRIT|TL_EXIT, "Can't start child process: %s", strerror(errno)); return (0); }