+/*
+ * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/sysctl.h>
+
+#include "tlog.h"
+#include "tmalloc.h"
+#include "connection.h"
+
+#include "top.h"
+
+#define NITEM 0
+
+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
+fillMsgTop(TCMsgTop *m) {
+ double lll[3];
+ int memory_tmp;
+
+ memset(m,0,sizeof(TCMsgTop));
+ if ( getloadavg(lll,3) >= NITEM+1 )
+ m->load=lll[NITEM];
+ else
+ m->load=-1.0;
+
+ m->freemem = 0;
+ 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_cache_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();
+
+ m->usermem =-1;
+ if ( GETSYSCTL("hw.usermem", memory_tmp) == 0 )
+ m->usermem = memory_tmp;
+
+ tlog( TL_DEBUG, "Sended topdata: %.2f load, %d free, %d total", m->load, m->freemem, m->usermem);
+}
+
+static int
+sendTop(Msg *msg) {
+ TCMsg *pmsg;
+
+ if ( !msg->msg ) {
+ int msglen = TCMSGHDRSZ + sizeof(TCMsgTop);
+ pmsg = (TCMsg*)tmalloc(msglen);
+ pmsg->len = msglen;
+ pmsg->type=TOPMSGTYPE;
+ msg->msg = pmsg;
+ } else {
+ pmsg = msg->msg;
+ }
+
+ fillMsgTop( (TCMsgTop*)(pmsg->data) );
+
+ return TC_sendMsg(msg);
+}
+
+
+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 = "127.0.0.1";
+ 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:
+ return 1;
+ }
+ }
+
+ 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);
+}