add .gitignore
[remotetop.git] / sendtop.c
1 /*
2  * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *      notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *      notice, this list of conditions and the following disclaimer in the
12  *      documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of any co-contributors
14  *      may be used to endorse or promote products derived from this software
15  *      without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <ctype.h>
37 #include <sys/sysctl.h>
38
39 #include "tlog.h"
40 #include "tmalloc.h"
41 #include "connection.h"
42
43 #include "top.h"
44
45 #ifdef FreeBSD
46
47 static int
48 getsysctl(char *name, void *ptr, size_t len) {
49         size_t nlen = len;
50         if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
51                 tlog(TL_ALARM, "sysctl(\"%s\", ...) failed: %s\n", name,
52                         strerror(errno));
53                 return 1;
54         }   
55         if (nlen != len) {
56                 tlog(TL_ALARM, "sysctl(\"%s\", ...) expected %lu, got %lu\n", name,
57                         (unsigned long)len, (unsigned long)nlen);
58                 return 1;
59         }
60         return 0;
61 }
62
63
64 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
65
66 static void
67 getmeminfo(TCMsgTop *m) {
68         int    memory_tmp;
69         long    memory_tmp1;
70
71         if ( GETSYSCTL("vm.stats.vm.v_inactive_count", memory_tmp) == 0 )
72                 m->freemem += memory_tmp;
73         else
74                 m->freemem = -1;
75
76         if ( m->freemem>=0 && GETSYSCTL("vm.stats.vm.v_free_count", memory_tmp) == 0 )
77                 m->freemem += memory_tmp;
78         else
79                 m->freemem = -1;
80
81         if (  m->freemem>=0 )
82                 m->freemem *= getpagesize();
83          
84         if ( GETSYSCTL("hw.physmem", memory_tmp1) == 0 )
85                 m->physmem = memory_tmp1;
86 }
87
88
89 #elif defined  Linux /* end FreeBSD */
90
91 #define MEMBUFSIZE 256
92
93 /*
94  * if str mathes by pattern returns poineter to begin of value
95  * and NULL in opposite case
96  */
97 static char*
98 cmpPattern( char *str, char *pattern ) {
99         while( *str != '\0' && *str == *pattern ) {
100                 str++;
101                 pattern++;
102         }
103
104         if ( *pattern == '\0' ) {
105                 if ( *str == '\0' )
106                         return NULL;
107
108                 /*
109                  * str matches by pattern, so skip leading spaces 
110                  * before actual value
111                  */
112                 while( *str != '\0' ) {
113                         if ( isspace( *str ) )
114                                 str++;
115                         else 
116                                 return str;
117                 }
118         }
119         
120         return NULL;
121 }
122
123 static void
124 getmeminfo(TCMsgTop *m) {
125         FILE *fh;
126         static char buf[MEMBUFSIZE];
127         char *ptr;
128
129         fh=fopen("/proc/meminfo", "r");
130         if (fh == NULL) {
131                 tlog(TL_ALARM, "fopen(\"/proc/meminfo\", ...) failed: %s", strerror(errno));
132                 return;
133         }
134
135         while( fgets(buf, MEMBUFSIZE, fh) &&  (m->physmem == 0 || m->freemem == 0) ) {
136                 if ( (ptr = cmpPattern(buf, "MemTotal:")) != NULL ) {
137                         m->physmem = atoll(ptr) * 1024; /* mem in Kb */ 
138                 } else if ( (ptr = cmpPattern(buf, "MemFree:")) != NULL ) {
139                         m->freemem = atoll(ptr) * 1024; /* mem in Kb */ 
140                 }
141         }
142
143         fclose(fh);
144 }
145
146 #else /* end Linux*/
147 #error No memory stat for current OS
148 #endif 
149
150 #define NITEM   0
151
152 static void
153 fillMsgTop(TCMsgTop *m) {
154         double lll[3];
155
156         memset(m,0,sizeof(TCMsgTop));
157         if ( getloadavg(lll,3) >= NITEM+1 )
158                 m->load=lll[NITEM];
159         else
160                 m->load=-1.0;
161
162         m->freemem = 0;
163         m->physmem = 0;
164         getmeminfo(m);
165
166         tlog( TL_DEBUG, "Sended topdata: %.2f load, %lld free, %lld total", m->load, m->freemem, m->physmem);
167 }
168
169 static int
170 sendTop(Msg *msg) {
171         TCMsg *pmsg;
172         int msglen = TCMSGHDRSZ + sizeof(TCMsgTop);
173
174         if ( !msg->msg ) {
175                 pmsg = (TCMsg*)tmalloc(msglen);
176                 msg->msg = pmsg;
177         } else {
178                 pmsg = msg->msg;
179         }
180
181         pmsg->len = msglen;
182         pmsg->type=TOPMSGTYPE;
183         fillMsgTop( (TCMsgTop*)(pmsg->data) );
184
185         return TC_sendMsg(msg);
186 }
187
188 void usage() {
189         fputs(
190                 "Copyright (c) 2004-2007 Teodor Sigaev <teodor@sigaev.ru>. All rights reserved.\n"
191                 "sendtop - small daemon to send load of box to server\n"
192                 "Usage:\n"
193                 "./sendtop [-D] -h HOST [-p PORT] [-s PERIOD]\n"
194                 "  -D        - debug mode (do not daemonize, print to stderr instead of syslog)\n"
195                 "  -h HOST   - server IP to send data\n"
196                 "  -p PORT   - port number of server\n"
197                 "  -s PERIOD - period of of send (in seconds)\n",
198                 stdout
199         );
200
201         exit(1);
202 }
203
204 extern char *optarg;
205 int
206 main( int argc, char *argv[] ) {
207         int ch;
208         Msg     msg;
209         int debug=0, child=0;
210         int period=30;
211
212         msg.port        = TOPD_SERVER_DEFAULT_PORT;
213         msg.host        = NULL;
214         msg.msg = NULL;
215         msg.sockfd =-1;
216
217         while( (ch=getopt(argc, argv, "h:p:s:D"))!=-1) {
218                 switch(ch) {
219                         case 'h':
220                                 msg.host = strdup(optarg);
221                                 break;
222                         case 'p':
223                                 msg.port = atoi(optarg);
224                                 break;
225                         case 's':
226                                 period = atoi(optarg);
227                                 break;
228                         case 'D':
229                                 debug=1;
230                                 break;
231                         default:
232                                 usage();
233                                 return 1;
234                 }
235         }
236
237         if (!msg.host)
238                 usage();
239
240         signal(SIGCHLD, SIG_IGN);
241
242         if ( debug )
243                 opentlog( TL_OPEN_STDERR,  TL_DEBUG, NULL);
244         else
245                 opentlog( TL_OPEN_SYSLOG, TL_INFO, NULL);
246
247         if ( debug || (child = fork()) == 0 ) {
248                 while(1) {
249                         sendTop(&msg);
250                         sleep(period);  
251                 }
252                 TC_closefd(&msg);       
253         }
254         
255         if (child == -1)
256                 tlog(TL_CRIT|TL_EXIT, "Can't start child process: %s", strerror(errno));
257
258         return (0);
259 }