Add Linux support, code cleanups
[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 static char*
94 cmpPattern( char *str, char *pattern ) {
95         while( *str != '\0' && *str == *pattern ) {
96                 str++;
97                 pattern++;
98         }
99
100         if ( *pattern == '\0' ) {
101                 if ( *str == '\0' )
102                         return NULL;
103
104                 /*
105                  * str matches by pattern, so skip leading spaces 
106                  * before actual value
107                  */
108                 while( *str != '\0' ) {
109                         if ( isspace( *str ) )
110                                 str++;
111                         else 
112                                 return str;
113                 }
114         }
115         
116         return NULL;
117 }
118
119 static void
120 getmeminfo(TCMsgTop *m) {
121         FILE *fh;
122         static char buf[MEMBUFSIZE];
123         char *ptr;
124
125         fh=fopen("/proc/meminfo", "r");
126         if (fh == NULL) {
127                 tlog(TL_ALARM, "fopen(\"/proc/meminfo\", ...) failed: %s", strerror(errno));
128                 return;
129         }
130
131         while( fgets(buf, MEMBUFSIZE, fh) &&  (m->physmem == 0 || m->freemem == 0) ) {
132                 if ( (ptr = cmpPattern(buf, "MemTotal:")) != NULL ) {
133                         m->physmem = atoll(ptr) * 1024; /* mem in Kb */ 
134                 } else if ( (ptr = cmpPattern(buf, "MemFree:")) != NULL ) {
135                         m->freemem = atoll(ptr) * 1024; /* mem in Kb */ 
136                 }
137         }
138
139         fclose(fh);
140 }
141
142 #else /* end Linux*/
143 #error No memory stat for current OS
144 #endif 
145
146 #define NITEM   0
147
148 static void
149 fillMsgTop(TCMsgTop *m) {
150         double lll[3];
151
152         memset(m,0,sizeof(TCMsgTop));
153         if ( getloadavg(lll,3) >= NITEM+1 )
154                 m->load=lll[NITEM];
155         else
156                 m->load=-1.0;
157
158         m->freemem = 0;
159         m->physmem = 0;
160         getmeminfo(m);
161
162         tlog( TL_DEBUG, "Sended topdata: %.2f load, %lld free, %lld total", m->load, m->freemem, m->physmem);
163 }
164
165 static int
166 sendTop(Msg *msg) {
167         TCMsg *pmsg;
168
169         if ( !msg->msg ) {
170                 int msglen = TCMSGHDRSZ + sizeof(TCMsgTop);
171                 pmsg = (TCMsg*)tmalloc(msglen);
172                 pmsg->len = msglen;
173                 pmsg->type=TOPMSGTYPE;
174                 msg->msg = pmsg;
175         } else {
176                 pmsg = msg->msg;
177         }
178
179         fillMsgTop( (TCMsgTop*)(pmsg->data) );
180
181         return TC_sendMsg(msg);
182 }
183
184 void usage() {
185         fputs(
186                 "Copyright (c) 2004-2007 Teodor Sigaev <teodor@sigaev.ru>. All rights reserved.\n"
187                 "sendtop - small daemon to send load of box to server\n"
188                 "Usage:\n"
189                 "./sendtop [-D] -h HOST [-p PORT] [-s PERIOD]\n"
190                 "  -D        - debug mode (do not daemonize, print to stderr instead of syslog)\n"
191                 "  -h HOST   - server IP to send data\n"
192                 "  -p PORT   - port number of server\n"
193                 "  -s PERIOD - period of of send (in seconds)\n",
194                 stdout
195         );
196
197         exit(1);
198 }
199
200 extern char *optarg;
201 int
202 main( int argc, char *argv[] ) {
203         int ch;
204         Msg     msg;
205         int debug=0, child=0;
206         int period=30;
207
208         msg.port        = TOPD_SERVER_DEFAULT_PORT;
209         msg.host        = NULL;
210         msg.msg = NULL;
211         msg.sockfd =-1;
212
213         while( (ch=getopt(argc, argv, "h:p:s:D"))!=-1) {
214                 switch(ch) {
215                         case 'h':
216                                 msg.host = strdup(optarg);
217                                 break;
218                         case 'p':
219                                 msg.port = atoi(optarg);
220                                 break;
221                         case 's':
222                                 period = atoi(optarg);
223                                 break;
224                         case 'D':
225                                 debug=1;
226                                 break;
227                         default:
228                                 usage();
229                                 return 1;
230                 }
231         }
232
233         if (!msg.host)
234                 usage();
235
236         signal(SIGCHLD, SIG_IGN);
237
238         if ( debug )
239                 opentlog( TL_OPEN_STDERR,  TL_DEBUG, NULL);
240         else
241                 opentlog( TL_OPEN_SYSLOG, TL_INFO, NULL);
242
243         if ( debug || (child = fork()) == 0 ) {
244                 while(1) {
245                         sendTop(&msg);
246                         sleep(period);  
247                 }
248                 TC_closefd(&msg);       
249         }
250         
251         if (child == -1)
252                 tlog(TL_CRIT|TL_EXIT, "Can't start child process: %s", strerror(errno));
253
254         return (0);
255 }