1 /* A complicated in the internet domain using TCP */
5 #include <sys/socket.h>
7 #include <netinet/in.h>
17 #define MAX_DIR_STR 4096
18 #define CONFIGEXPR "^config (([a-zA-z0-9_]+(\\.)?)+)"
19 #define FETCHEXPR "^fetch (([a-zA-z0-9_]+(\\.)?)+)"
20 #define LISTEXPR "^list"
21 #define QUITEXPR "^quit"
25 /* This function is called when a system call fails,
26 * it will display on stderr and then abort */
35 /* The following keeps zombies at bay.
36 * When children die and the parent doesn't wait() on
37 * them then their SIGCHLD handler is not happy because
38 * the process is not permitted to fully die because at
39 * some point in the future, the parent of the process might
40 * want to execute a wait and would want info on the death of
43 signal(SIGCHLD
,SIG_IGN
);
45 int sockfd
, newsockfd
, portno
, clilen
, pid
;
48 /* sockfd and newsockfd are file descriptors containing
49 * the values returned by the socket and accept syscall
50 * portno stores the port number the server will accept
51 * connections, clilen stores the size of the address of
52 * the client, this is needed for the accept syscall,
53 * n is the return value for the read() and write() calls,
54 * which will be the number of characters read or written.
57 /* serv_addr will contain the address of the server, and
58 * cli_addr will contain the address of the client connecting */
60 struct sockaddr_in serv_addr
, cli_addr
;
62 /* Create a new socket */
63 sockfd
= socket(AF_INET
, SOCK_STREAM
, 0);
65 error("ERROR opening socket");
68 if (setsockopt(sockfd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
)) < 0) {
69 error("can't reuse, lame.");
73 /* zero out the serv_addr buffer */
75 bzero((char *) &serv_addr
, sizeof(serv_addr
));
77 /* set serv_addr structure fields:
78 * sin_family = code for the address family
79 * sin_port = contains the port number (converted to network byte order)
80 * in_addr = contains s_addr = IP address of the server */
81 serv_addr
.sin_family
= AF_INET
;
82 serv_addr
.sin_port
= htons(portno
);
83 serv_addr
.sin_addr
.s_addr
= INADDR_ANY
;
85 /* bind() binds a socket to an address, takes socket fd, address to bind
86 * size of the address to which it is bound */
87 if (bind(sockfd
, (struct sockaddr
*) &serv_addr
,
88 sizeof(serv_addr
)) < 0)
89 error("ERROR on binding");
91 /* listen on the socket for connections */
94 /* accept() causes the process to block until client connects, wakes up
95 * when a connection from a client has succeeded and then returns a new
96 * file descriptor, and all communications should be done on this fd.
97 * The second argument is a reference pointer to the address of the client
98 * on the other end of the connection, third arg is the size of the structure. */
99 clilen
= sizeof(cli_addr
);
102 newsockfd
= accept(sockfd
,
103 (struct sockaddr
*) &cli_addr
,
106 error("ERROR on accept");
109 error("ERROR on fork");
115 else close (newsockfd
);
116 } /* end of while loop */
117 return 0; /* never gets here */
120 /******** commands() *********************
121 * There is a separate instance of this function
122 * for each connection. It handles all communication
123 * once a connnection has been established.
124 ******************************************/
126 void commands(int sock
)
130 /* Server reads characters from the socket connection into
135 nodemsg
= "birdbath.riseup.net\n.\n";
138 version
= "fakemunins node on birdbath.riseup.net version: 1.2.4\n";
141 timeoutmsg
= "Timeout!\n";
144 errormsg
= "# Unknown command. Try list, nodes, config, fetch, version or quit\n";
147 greeting
= "# munin node at birdbath.riseup.net\n";
149 char* unknownservice
;
150 unknownservice
= "# Unknown service\n.\n";
153 debug
= "# HI YOU GOT TEH DEBEUG!!?!\n";
156 fetch
= "# fetch message\n";
161 n
= write(sock
, greeting
, strlen(greeting
));
166 /* To be able to match regular expressions, we need this,
167 * one for "config" and one for "fetch"
171 if(regcomp(&config_re
, CONFIGEXPR
, REG_EXTENDED
) != 0) {
176 if(regcomp(&fetch_re
, FETCHEXPR
, REG_EXTENDED
) != 0) {
181 if(regcomp(&list_re
, LISTEXPR
, REG_EXTENDED
) != 0) {
186 if(regcomp(&quit_re
, QUITEXPR
, REG_EXTENDED
) != 0) {
190 char ret
[MAX_DIR_STR
];
196 n
= read(sock
,buffer
,255);
199 if (n
< 0) error("ERROR reading from socket");
201 if((regexec(&list_re
, buffer
, 0, NULL
, 0)) == 0) {
207 if ((dfd
= opendir("/etc/munin/plugins")) == NULL
) {
212 while ((dp
= readdir(dfd
)) !=NULL
) {
214 /* skip self and parent */
215 if (strcmp(dp
->d_name
, ".") == 0 ||
216 strcmp(dp
->d_name
, "..") == 0) {
220 if (strlen(ret
) + strlen(dp
->d_name
) + 2 > MAX_DIR_STR
) {
222 strcpy(ret
, "too long");
225 strcat(ret
, strcat(dp
->d_name
, " "));
228 ret
[strlen(ret
) - 1] = 0;
231 n
= write (sock
, ret
, strlen(ret
));
235 else if(strcmp(buffer
, "nodes\r\n") == 0) {
236 n
= write (sock
, nodemsg
, strlen(nodemsg
));
239 /* do a a regexp to see if "config bar" was sent
240 * check if second arg is a plugin, otherwise print
241 * "# Unknown service\n." */
243 else if((regexec(&config_re
, buffer
, 0, NULL
, 0)) == 0) {
244 struct stat statinfo
;
245 char *p
= strchr(buffer
, ' '); /* Now p will point to the space between config and bar */
246 char *service
= p
+1; /* put whatever is after that space into *service */
247 char *servicedir
= malloc(sizeof(char) * 1024); /* allocate some memory to store everything */
248 char *plugin_path
= "/etc/munin/plugins"; /* where the plugins are located */
250 /* Do a little overflow checking */
251 if ((strlen(plugin_path
) + strlen(service
) + 3) > 1024) {
252 error("path too long");
256 /* Prepend the plugin path into the beginning of the service name */
257 sprintf(servicedir
, "%s/%s", plugin_path
, service
);
259 /* Remove the \r\n at the end of the string */
260 if (servicedir
[strlen(servicedir
) -1 ] == '\n') {
261 if (servicedir
[strlen(servicedir
) -2 ] == '\r') {
262 servicedir
[strlen(servicedir
) - 2] = 0;
265 servicedir
[strlen(servicedir
) - 1] = 0;
269 /* what the string has
270 char*temp = servicedir; while(*temp){printf("%c - %d\n", *temp, (int)*temp);temp++;}
273 /* Check to see if the service entered exists in the directory */
274 if(stat(servicedir
, &statinfo
) == -1) {
275 n
= write(sock
, unknownservice
, strlen(unknownservice
));
277 /* Since it does exist, check to make sure it is a regular file or a link */
278 else if(statinfo
.st_mode
& (S_IFREG
|| S_IFLNK
)) {
281 char *command
=(strcat(servicedir
, " config"));
283 if ( !(fpipe
= (FILE*)popen(command
,"r")) )
284 { // If fpipe is NULL
285 perror("Problems with pipe");
289 while ( fgets( results
, sizeof results
, fpipe
))
291 n
= write(sock
, results
, strlen(results
));
294 n
= write(sock
, eofmsg
, strlen(eofmsg
));
296 /* gotta free up this memory because servicedir is malloc()'d */
300 /* do a a regexp to see if "fetch bar" was sent
301 * check if second arg is a plugin, otherwise print
302 * "# Unknown service\n." */
304 else if((regexec(&fetch_re
, buffer
, 0, NULL
, 0)) == 0) {
305 struct stat statinfo
;
306 char *p
= strchr(buffer
, ' '); /* Now p will point to the space between config and bar */
307 char *service
= p
+1; /* put whatever is after that space into *service */
308 char *servicedir
= malloc(sizeof(char) * 1024); /* allocate some memory to store everything */
309 char *plugin_path
= "/etc/munin/plugins"; /* where the plugins are located */
311 /* Do a little overflow checking */
312 if ((strlen(plugin_path
) + strlen(service
) + 3) > 1024) {
313 error("path too long");
317 /* Prepend the plugin path into the beginning of the service name */
318 sprintf(servicedir
, "%s/%s", plugin_path
, service
);
320 /* Remove the \r\n at the end of the string */
321 if (servicedir
[strlen(servicedir
) -1 ] == '\n') {
322 if (servicedir
[strlen(servicedir
) -2 ] == '\r') {
323 servicedir
[strlen(servicedir
) - 2] = 0;
326 servicedir
[strlen(servicedir
) - 1] = 0;
330 /* Check to see if the service entered exists in the directory */
331 if(stat(servicedir
, &statinfo
) == -1) {
332 n
= write(sock
, unknownservice
, strlen(unknownservice
));
334 /* Since it does exist, check to make sure it is a regular file or a link */
335 else if(statinfo
.st_mode
& (S_IFREG
|| S_IFLNK
)) {
338 char *command
=(strcat(servicedir
, " fetch"));
340 if ( !(fpipe
= (FILE*)popen(command
,"r")) )
341 { // If fpipe is NULL
342 perror("Problems with pipe");
346 while ( fgets( results
, sizeof results
, fpipe
))
348 n
= write(sock
, results
, strlen(results
));
351 n
= write(sock
, eofmsg
, strlen(eofmsg
));
353 /* gotta free up this memory because servicedir is malloc()'d */
357 else if(strcmp(buffer
, "help\r\n") == 0) {
358 n
= write (sock
, errormsg
, strlen(errormsg
));
361 else if(strcmp(buffer
, "version\r\n") == 0) {
362 n
= write (sock
, version
, strlen(version
));
365 else if((regexec(&quit_re
, buffer
, 0, NULL
, 0)) == 0) {
370 n
= write(sock
, errormsg
, strlen(errormsg
));
374 if (n
< 0) error("ERROR writing to socket");