@cryptotaxi247 / netdata-1 / commits / 27f50a10d

re-wrote the popen part, added signal handlers, re-worked the available options for charts.d

Costa Tsaousis (ktsaou) committed May 3, 2014 at 02:05 UTC 27f50a10da1c4eeb3d3a4f897e2e1cf6b5aab074
4 files changed +283 -153
charts.d/example-chart.sh
-15
@@ -17,21 +17,6 @@ update_every=$1
17 update_every=$(( update_every + 1 - 1)) # makes sure it is a number
18 test $update_every -eq 0 && update_every=1 # if it is zero, make it 1
19
20 -# internal default values
21 -enabled="no"
22 -
23 -# check if there is a config for us - if there is, bring it in
24 -if [ -f "$0.conf" ]
25 -then
26 - . "$0.conf"
27 -fi
28 -
29 -# check if it is enabled
30 -if [ ! "$enabled" = "yes" ]
31 -then
32 - echo "DISABLE"
33 - exit 1
34 -fi
20
21 # create the chart with 3 dimensions
22 cat <<EOF
charts.d/squid-chart.sh
+4 -18
@@ -1,6 +1,6 @@
1 #!/bin/sh
2
3 -url="http://127.0.0.1:3128/squid-internal-mgr/counters"
3 +url="http://127.0.0.1:8080/squid-internal-mgr/counters"
4
5 # report our PID back to netdata
6 # this is required for netdata to kill this process when it exits
@@ -19,26 +19,12 @@ update_every=$1
19 update_every=$(( update_every + 1 - 1)) # makes sure it is a number
20 test $update_every -eq 0 && update_every=1 # if it is zero, make it 1
21
22 -# internal default values
23 -min=1
24 -enabled="no"
25 -
26 -# check if there is a config for us - if there is, bring it in
27 -if [ -f "$0.conf" ]
22 +# we accept a url as the second argument
23 +if [ ! -z "$2" ]
24 then
29 - . "$0.conf"
25 + url="$2"
26 fi
27
32 -# check if it is enabled
33 -if [ ! "$enabled" = "yes" ]
34 -then
35 - echo "DISABLE"
36 - exit 1
37 -fi
38 -
39 -# make sure we respect the $min update frequency
40 -test $update_every -lt $min && update_every=$min
41 -
28 # check once if the url works
29 wget 2>/dev/null -O /dev/null "$url"
30 if [ ! $? -eq 0 ]
netdata.c
+278 -119
@@ -9,6 +9,7 @@
9 #include <pwd.h>
10 #include <sys/types.h>
11 #include <sys/time.h>
12 +#include <sys/wait.h>
13
14 #include <sys/socket.h>
15 #include <sys/select.h>
@@ -111,10 +112,6 @@
112 #define HOSTNAME_MAX 1024
113 char *hostname;
114
114 -unsigned long long debug_flags = DEBUG;
115 -char *debug_log = NULL;
116 -int debug_fd = -1;
117 -
115 #define EXIT_FAILURE 1
116 #define LISTEN_BACKLOG 100
117
@@ -160,10 +157,68 @@ unsigned long simple_hash(const char *name)
157 return hash;
158 }
159
160 +#define PIPE_READ 0
161 +#define PIPE_WRITE 1
162 +
163 +FILE *mypopen(const char *command, pid_t *pidptr)
164 +{
165 + int pipefd[2];
166 +
167 + if(pipe(pipefd) == -1) return NULL;
168 +
169 + int pid = fork();
170 + if(pid == -1) {
171 + close(pipefd[PIPE_READ]);
172 + close(pipefd[PIPE_WRITE]);
173 + return NULL;
174 + }
175 + if(pid != 0) {
176 + // the parent
177 + *pidptr = pid;
178 + close(pipefd[PIPE_WRITE]);
179 + FILE *fp = fdopen(pipefd[PIPE_READ], "r");
180 + return(fp);
181 + }
182 + // the child
183 +
184 + // close all files
185 + int i;
186 + for(i = sysconf(_SC_OPEN_MAX); i > 0; i--)
187 + if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
188 +
189 + // move the pipe to stdout
190 + if(pipefd[PIPE_WRITE] != STDOUT_FILENO) {
191 + dup2(pipefd[PIPE_WRITE], STDOUT_FILENO);
192 + close(pipefd[PIPE_WRITE]);
193 + }
194 +
195 + fprintf(stderr, "Running command: '%s'\n", command);
196 + execl("/bin/sh", "sh", "-c", command, NULL);
197 + exit(1);
198 +}
199 +
200 +void mypclose(FILE *fp)
201 +{
202 + fclose(fp);
203 +}
204 +
205 +
206 // ----------------------------------------------------------------------------
207 // LOG
208
166 -void log_date()
209 +unsigned long long debug_flags = DEBUG;
210 +
211 +char *debug_log = NULL;
212 +int debug_fd = -1;
213 +
214 +char *access_log = NULL;
215 +int access_fd = -1;
216 +FILE *stdaccess = NULL;
217 +
218 +int log_syslog = 1;
219 +
220 +
221 +void log_date(FILE *out)
222 {
223 char outstr[200];
224 time_t t;
@@ -175,18 +230,19 @@ void log_date()
230 if (tmp == NULL) return;
231 if (strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0) return;
232
178 - fprintf(stderr, "%s: ", outstr);
233 + fprintf(out, "%s: ", outstr);
234 }
235
236 int debug_variable;
237 //#define debug(args...) debug_int(__FILE__, __FUNCTION__, __LINE__, ##args)
183 -#define debug(type, args...) do { if(!silent && debug_flags & type) debug_int(__FILE__, __FUNCTION__, __LINE__, type, ##args); } while(0)
238 +#define debug(type, args...) do { if(!silent && debug_flags & type) debug_int(__FILE__, __FUNCTION__, __LINE__, ##args); } while(0)
239
185 -void debug_int( const char *file, const char *function, const unsigned long line, unsigned long type, const char *fmt, ... )
240 +void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
241 {
242 + if(file) { ; }
243 va_list args;
244
189 - log_date();
245 + log_date(stderr);
246 va_start( args, fmt );
247 fprintf(stderr, "DEBUG (%04lu@%-15.15s): ", line, function);
248 vfprintf( stderr, fmt, args );
@@ -198,10 +254,11 @@ void debug_int( const char *file, const char *function, const unsigned long line
254
255 void error_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
256 {
257 + if(file) { ; }
258 va_list args;
259
260 if(!silent) {
204 - log_date();
261 + log_date(stderr);
262
263 va_start( args, fmt );
264 fprintf(stderr, "ERROR (%04lu@%-15.15s): ", line, function);
@@ -215,19 +272,22 @@ void error_int( const char *file, const char *function, const unsigned long line
272 else fprintf(stderr, "\n");
273 }
274
218 - va_start( args, fmt );
219 - vsyslog(LOG_ERR, fmt, args );
220 - va_end( args );
275 + if(log_syslog) {
276 + va_start( args, fmt );
277 + vsyslog(LOG_ERR, fmt, args );
278 + va_end( args );
279 + }
280 }
281
282 #define fatal(args...) fatal_int(__FILE__, __FUNCTION__, __LINE__, ##args)
283
284 void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
285 {
286 + if(file) { ; }
287 va_list args;
288
289 if(!silent) {
230 - log_date();
290 + log_date(stderr);
291
292 va_start( args, fmt );
293 fprintf(stderr, "FATAL (%04lu@%-15.15s): ", line, function);
@@ -238,13 +298,36 @@ void fatal_int( const char *file, const char *function, const unsigned long line
298 fprintf(stderr, "\n");
299 }
300
241 - va_start( args, fmt );
242 - vsyslog(LOG_CRIT, fmt, args );
243 - va_end( args );
301 + if(log_syslog) {
302 + va_start( args, fmt );
303 + vsyslog(LOG_CRIT, fmt, args );
304 + va_end( args );
305 + }
306
307 exit(EXIT_FAILURE);
308 }
309
310 +void log_access( const char *fmt, ... )
311 +{
312 + va_list args;
313 +
314 + if(stdaccess) {
315 + log_date(stdaccess);
316 +
317 + va_start( args, fmt );
318 + vfprintf( stdaccess, fmt, args );
319 + va_end( args );
320 + fprintf( stdaccess, "\n");
321 + fflush( stdaccess );
322 + }
323 +
324 + if(log_syslog) {
325 + va_start( args, fmt );
326 + vsyslog(LOG_INFO, fmt, args );
327 + va_end( args );
328 + }
329 +}
330 +
331
332 // ----------------------------------------------------------------------------
333 // URL encode / decode
@@ -320,6 +403,8 @@ char *url_decode(char *str) {
403 // ----------------------------------------------------------------------------
404 // socket
405
406 +int listen_fd = -1;
407 +
408 int create_listen_socket(int port)
409 {
410 int sock=-1;
@@ -1277,7 +1362,7 @@ void rrd_stats_done(RRD_STATS *st)
1362 st->first_entry_t = now.tv_sec * 1000000ULL + now.tv_usec;
1363 }
1364 else {
1280 - if(st->counter > st->entries) {
1365 + if(st->counter > (unsigned long long)st->entries) {
1366 // the db is overwriting values
1367 // add the value we will overwrite
1368 st->first_entry_t += st->timediff[st->current_entry];
@@ -1300,12 +1385,12 @@ void rrd_stats_done(RRD_STATS *st)
1385 // web buffer
1386
1387 struct web_buffer {
1303 - size_t size; // allocation size of buffer
1304 - size_t bytes; // current data length in buffer
1305 - size_t sent; // current data length sent to output
1388 + long size; // allocation size of buffer
1389 + long bytes; // current data length in buffer
1390 + long sent; // current data length sent to output
1391 char *buffer; // the buffer
1392 int contenttype;
1308 - size_t rbytes; // if non-zero, the excepted size of ifd
1393 + long rbytes; // if non-zero, the excepted size of ifd
1394 time_t date; // the date this content has been generated
1395 };
1396
@@ -1314,7 +1399,7 @@ struct web_buffer {
1399 void web_buffer_strcpy(struct web_buffer *wb, const char *txt)
1400 {
1401 char *buffer = wb->buffer;
1317 - size_t bytes = wb->bytes, size = wb->size, i = 0;
1402 + long bytes = wb->bytes, size = wb->size, i = 0;
1403
1404 while(txt[i] && bytes < size)
1405 buffer[bytes++] = txt[i++];
@@ -1410,7 +1495,7 @@ void web_buffer_jsdate(struct web_buffer *wb, int year, int month, int day, int
1495 wb->bytes += 35;
1496 }
1497
1413 -struct web_buffer *web_buffer_create(size_t size)
1498 +struct web_buffer *web_buffer_create(long size)
1499 {
1500 struct web_buffer *b;
1501
@@ -1442,12 +1527,12 @@ void web_buffer_free(struct web_buffer *b)
1527 free(b);
1528 }
1529
1445 -void web_buffer_increase(struct web_buffer *b, size_t free_size_required)
1530 +void web_buffer_increase(struct web_buffer *b, long free_size_required)
1531 {
1447 - size_t left = b->size - b->bytes;
1532 + long left = b->size - b->bytes;
1533
1534 if(left >= free_size_required) return;
1450 - size_t increase = free_size_required - left;
1535 + long increase = free_size_required - left;
1536 if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP;
1537
1538 debug(D_WEB_BUFFER, "Increasing data buffer from size %d to %d.", b->size, b->size + increase);
@@ -1486,8 +1571,8 @@ struct web_client {
1571 int zoutput; // if set to 1, web_client_send() will send compressed data
1572 z_stream zstream; // zlib stream for sending compressed output to client
1573 Bytef zbuffer[ZLIB_CHUNK]; // temporary buffer for storing compressed output
1489 - size_t zsent; // the compressed bytes we have sent to the client
1490 - size_t zhave; // the compressed bytes that we have to send
1574 + long zsent; // the compressed bytes we have sent to the client
1575 + long zhave; // the compressed bytes that we have to send
1576 int zinitialized;
1577
1578 int wait_receive;
@@ -1527,7 +1612,6 @@ struct web_client *web_client_create(int listener)
1612 strncpy(w->client_ip, inet_ntoa(w->clientaddr.sin_addr), 100);
1613 w->client_ip[100] = '\0';
1614
1530 - // syslog(LOG_NOTICE, "%llu: New client from %s.", w->id, w->client_ip);
1615 debug(D_WEB_CLIENT_ACCESS, "%llu: New web client from %s on socket %d.", w->id, w->client_ip, w->ifd);
1616
1617 {
@@ -1702,7 +1786,7 @@ void rrd_stats_all_json(struct web_buffer *wb)
1786 web_buffer_increase(wb, 1024);
1787
1788 unsigned long memory = 0;
1705 - size_t c;
1789 + long c;
1790 RRD_STATS *st;
1791
1792 web_buffer_printf(wb, RRD_GRAPH_JSON_HEADER);
@@ -1728,7 +1812,7 @@ void rrd_stats_all_json(struct web_buffer *wb)
1812 );
1813 }
1814
1731 -unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group, int group_method, time_t after, time_t before)
1815 +unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, int entries_to_show, int group, int group_method, time_t after, time_t before)
1816 {
1817 int c;
1818 pthread_mutex_lock(&st->mutex);
@@ -1764,7 +1848,7 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1848 else if(current_entry >= st->entries) current_entry = st->entries - 1;
1849
1850 // find the oldest entry of the round-robin
1767 - long max_entries = (st->counter <= st->entries) ? st->counter - 1 : st->entries;
1851 + long max_entries = (st->counter <= (unsigned long)st->entries) ? st->counter - 1 : (unsigned long)st->entries;
1852
1853 if(before == 0) before = st->last_updated.tv_sec;
1854 if(after == 0) after = rrd_stats_first_entry_t(st);
@@ -2104,8 +2188,6 @@ int mysendfile(struct web_client *w, char *filename)
2188 }
2189 }
2190
2107 - //syslog(LOG_NOTICE, "%llu: Sending file '%s' to client %s.", w->id, filename, w->client_ip);
2108 -
2191 // pick a Content-Type for the file
2192 if(strstr(filename, ".html") != NULL) w->data->contenttype = CT_TEXT_HTML;
2193 else if(strstr(filename, ".js") != NULL) w->data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
@@ -2145,10 +2227,10 @@ void web_client_reset(struct web_client *w)
2227 struct timeval tv;
2228 gettimeofday(&tv, NULL);
2229
2148 - long sent = w->zoutput?w->zstream.total_out:(w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rbytes:w->data->bytes;
2230 + long sent = w->zoutput?(long)w->zstream.total_out:((w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rbytes:w->data->bytes);
2231 long size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->data->rbytes:w->data->bytes;
2232
2151 - if(w->last_url[0]) syslog(LOG_NOTICE, "%llu: (sent/all = %ld/%ld bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: '%s'",
2233 + if(w->last_url[0]) log_access("%llu: (sent/all = %ld/%ld bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: '%s'",
2234 w->id,
2235 sent, size, -((size>0)?((float)(size-sent)/(float)size * 100.0):0.0),
2236 (float)usecdiff(&w->tv_ready, &w->tv_in) / 1000.0,
@@ -2267,8 +2349,8 @@ int web_client_data_request(struct web_client *w, char *url, int datasource_type
2349 debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
2350
2351 // how many entries does the client want?
2270 - size_t lines = save_history;
2271 - size_t group_count = 1;
2352 + long lines = save_history;
2353 + long group_count = 1;
2354 time_t after = 0, before = 0;
2355 int group_method = GROUP_AVERAGE;
2356
@@ -2691,7 +2773,7 @@ void web_client_process(struct web_client *w)
2773 if(w->response_header[0])
2774 strcpy(custom_header, w->response_header);
2775
2694 - size_t headerlen = 0;
2776 + int headerlen = 0;
2777 headerlen += snprintf(&w->response_header[headerlen], MAX_HTTP_HEADER_SIZE - headerlen,
2778 "HTTP/1.1 %d %s\r\n"
2779 "Connection: %s\r\n"
@@ -2774,7 +2856,7 @@ void web_client_process(struct web_client *w)
2856 // this block of code can be commented, without anything missing.
2857 // when it is commented, the program will copy the data using async I/O.
2858 {
2777 - ssize_t len = sendfile(w->ofd, w->ifd, NULL, w->data->rbytes);
2859 + long len = sendfile(w->ofd, w->ifd, NULL, w->data->rbytes);
2860 if(len != w->data->rbytes) error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->data->rbytes, len);
2861 else web_client_reset(w);
2862 }
@@ -2824,9 +2906,9 @@ void web_client_send_chunk_finalize(struct web_client *w)
2906 else debug(D_DEFLATE, "%llu: Failed to send chunk suffix to client. Reason: %s", w->id, strerror(errno));
2907 }
2908
2827 -ssize_t web_client_send_deflate(struct web_client *w)
2909 +long web_client_send_deflate(struct web_client *w)
2910 {
2829 - ssize_t bytes;
2911 + long bytes;
2912
2913 // when using compression,
2914 // w->data->sent is the amount of bytes passed through compression
@@ -2924,11 +3006,11 @@ ssize_t web_client_send_deflate(struct web_client *w)
3006 return(bytes);
3007 }
3008
2927 -ssize_t web_client_send(struct web_client *w)
3009 +long web_client_send(struct web_client *w)
3010 {
3011 if(w->zoutput) return web_client_send_deflate(w);
3012
2931 - ssize_t bytes;
3013 + long bytes;
3014
3015 if(w->data->bytes - w->data->sent == 0) {
3016 // there is nothing to send
@@ -2969,13 +3051,13 @@ ssize_t web_client_send(struct web_client *w)
3051 return(bytes);
3052 }
3053
2972 -ssize_t web_client_receive(struct web_client *w)
3054 +long web_client_receive(struct web_client *w)
3055 {
3056 // do we have any space for more data?
3057 web_buffer_increase(w->data, WEB_DATA_LENGTH_INCREASE_STEP);
3058
2977 - ssize_t left = w->data->size - w->data->bytes;
2978 - ssize_t bytes;
3059 + long left = w->data->size - w->data->bytes;
3060 + long bytes;
3061
3062 if(w->mode == WEB_CLIENT_MODE_FILECOPY)
3063 bytes = read(w->ifd, &w->data->buffer[w->data->bytes], (left-1));
@@ -3128,30 +3210,20 @@ void syslog_allocations(void)
3210 struct web_client *w;
3211 for(w = web_clients; w ; w = w->next) clients++;
3212
3131 - syslog(LOG_NOTICE, "Allocated memory increased from %d to %d (increased by %d bytes). There are %d web clients connected.", mem, mi.uordblks, mi.uordblks - mem, clients);
3213 + error("Allocated memory increased from %d to %d (increased by %d bytes). There are %d web clients connected.", mem, mi.uordblks, mi.uordblks - mem, clients);
3214 mem = mi.uordblks;
3215 }
3134 - /*
3135 - syslog(LOG_NOTICE, "Total non-mmapped bytes (arena): %d\n", mi.arena);
3136 - syslog(LOG_NOTICE, "# of free chunks (ordblks): %d\n", mi.ordblks);
3137 - syslog(LOG_NOTICE, "# of free fastbin blocks (smblks): %d\n", mi.smblks);
3138 - syslog(LOG_NOTICE, "# of mapped regions (hblks): %d\n", mi.hblks);
3139 - syslog(LOG_NOTICE, "Bytes in mapped regions (hblkhd): %d\n", mi.hblkhd);
3140 - syslog(LOG_NOTICE, "Max. total allocated space (usmblks): %d\n", mi.usmblks);
3141 - syslog(LOG_NOTICE, "Free bytes held in fastbins (fsmblks): %d\n", mi.fsmblks);
3142 - syslog(LOG_NOTICE, "Total allocated space (uordblks): %d\n", mi.uordblks);
3143 - syslog(LOG_NOTICE, "Total free space (fordblks): %d\n", mi.fordblks);
3144 - syslog(LOG_NOTICE, "Topmost releasable block (keepcost): %d\n", mi.keepcost);
3145 - */
3216 }
3217
3218 void *socket_listen_main(void *ptr)
3219 {
3220 + if(ptr) { ; }
3221 struct web_client *w;
3222 struct timeval tv;
3223 int retval;
3224
3154 - int listener = create_listen_socket(listen_port);
3225 + // int listener = create_listen_socket(listen_port);
3226 + int listener = listen_fd;
3227 if(listener == -1) fatal("LISTENER: Cannot create listening socket on port 19999.");
3228
3229 fd_set ifds, ofds, efds;
@@ -3189,7 +3261,7 @@ void *socket_listen_main(void *ptr)
3261 w->obsolete = 1;
3262 }
3263
3192 - syslog(LOG_NOTICE, "%llu: %s connected", w->id, w->client_ip);
3264 + log_access("%llu: %s connected", w->id, w->client_ip);
3265 }
3266 else debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything.");
3267
@@ -3199,7 +3271,7 @@ void *socket_listen_main(void *ptr)
3271 // cleanup unused clients
3272 for(w = web_clients; w ; w = w?w->next:NULL) {
3273 if(w->obsolete) {
3202 - syslog(LOG_NOTICE, "%llu: %s disconnected", w->id, w->client_ip);
3274 + log_access("%llu: %s disconnected", w->id, w->client_ip);
3275 debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
3276 // pthread_join(w->thread, NULL);
3277 w = web_client_free(w);
@@ -5066,6 +5138,7 @@ int do_proc_vmstat() {
5138
5139 void *proc_main(void *ptr)
5140 {
5141 + if(ptr) { ; }
5142 struct rusage me, me_last;
5143 struct timeval last, now;
5144
@@ -5155,8 +5228,6 @@ void *proc_main(void *ptr)
5228 // /sbin/tc processor
5229 // this requires the script charts.d/tc-qos-collector.sh
5230
5158 -#define PIPE_READ 0
5159 -#define PIPE_WRITE 1
5231 #define TC_LINE_MAX 1024
5232
5233 struct tc_class {
@@ -5349,6 +5420,7 @@ void tc_device_free(struct tc_device *n)
5420 pid_t tc_child_pid = 0;
5421 void *tc_main(void *ptr)
5422 {
5423 + if(ptr) { ; }
5424 char buffer[TC_LINE_MAX+1] = "";
5425
5426 for(;1;) {
@@ -5357,9 +5429,11 @@ void *tc_main(void *ptr)
5429 struct tc_class *class = NULL;
5430
5431 snprintf(buffer, TC_LINE_MAX, "exec %s %d", config_get("plugin:tc", "script to run to get tc values", "charts.d/tc-qos-collector.sh"), update_every);
5360 - fp = popen(buffer, "r");
5432 + debug(D_TC_LOOP, "executing '%s'", buffer);
5433 + // fp = popen(buffer, "r");
5434 + fp = mypopen(buffer, &tc_child_pid);
5435 if(!fp) {
5362 - error("Cannot popen(\"%s\", \"r\").", buffer);
5436 + error("TC: Cannot popen(\"%s\", \"r\").", buffer);
5437 return NULL;
5438 }
5439
@@ -5449,7 +5523,7 @@ void *tc_main(void *ptr)
5523 debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid);
5524 }
5525 }
5452 - pclose(fp);
5526 + mypclose(fp);
5527
5528 if(device) {
5529 tc_device_free(device);
@@ -5470,6 +5544,7 @@ void *tc_main(void *ptr)
5544
5545 void *cpuidlejitter_main(void *ptr)
5546 {
5547 + if(ptr) { ; }
5548 int sleep_ms = config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
5549 if(sleep_ms <= 0) {
5550 config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
@@ -5517,18 +5592,18 @@ void *cpuidlejitter_main(void *ptr)
5592 #define CHARTSD_LINE_MAX 1024
5593
5594 struct chartd {
5520 - char id[RRD_STATS_NAME_MAX+1]; // id
5595 + char id[CONFIG_MAX_NAME+1]; // config node id
5596 +
5597 char filename[FILENAME_MAX+1]; // just the filename
5598 char fullfilename[FILENAME_MAX+1]; // with path
5599 char cmd[CHARTSD_CMD_MAX+1]; // the command that is executes
5600
5525 - char config_name[CONFIG_MAX_NAME + 1];
5526 -
5601 pid_t pid;
5602 pthread_t thread;
5603
5604 int update_every;
5605 int obsolete;
5606 + int enabled;
5607
5608 struct chartd *next;
5609 } *chartsd_root = NULL;
@@ -5576,11 +5651,9 @@ void *chartsd_worker_thread(void *arg)
5651 struct chartd *cd = (struct chartd *)arg;
5652 char line[CHARTSD_LINE_MAX + 1];
5653
5579 - cd->update_every = config_get_number(cd->id, "update every", update_every);
5580 - snprintf(cd->cmd, CHARTSD_CMD_MAX, "exec %s %d", cd->fullfilename, cd->update_every);
5581 -
5654 while(1) {
5583 - FILE *fp = popen(cd->cmd, "r");
5655 + // FILE *fp = popen(cd->cmd, "r");
5656 + FILE *fp = mypopen(cd->cmd, &cd->pid);
5657 if(!fp) {
5658 error("Cannot popen(\"%s\", \"r\").", cd->cmd);
5659 break;
@@ -5748,21 +5821,21 @@ void *chartsd_worker_thread(void *arg)
5821 }
5822 else if(!strcmp(s, "DISABLE")) {
5823 error("CHARTSD: script '%s' called DISABLE. Disabling it.", cd->fullfilename);
5751 - config_set_boolean("plugin:charts.d", cd->config_name, 0);
5824 + cd->enabled = 0;
5825 break;
5826 }
5827 else error("CHARTSD: script %s is sending command '%s' which is not known by netdata", cd->fullfilename, s);
5828 }
5829
5830 // fgets() failed or loop broke
5758 - pclose(fp);
5831 + mypclose(fp);
5832
5760 - if(!count) {
5833 + if(!count && cd->enabled) {
5834 error("CHARTSD: script '%s' does not generate usefull output. Disabling it.", cd->fullfilename);
5762 - config_set_boolean("plugin:charts.d", cd->config_name, 0);
5835 + cd->enabled = 0;
5836 }
5837
5765 - if(config_get_boolean("plugin:charts.d", cd->config_name, 1)) sleep(cd->update_every);
5838 + if(cd->enabled) sleep(cd->update_every);
5839 else break;
5840 }
5841
@@ -5772,7 +5845,9 @@ void *chartsd_worker_thread(void *arg)
5845
5846 void *chartsd_main(void *ptr)
5847 {
5848 + if(ptr) { ; }
5849 char *dir_name = config_get("plugin:charts.d", "charts.d directory", "charts.d");
5850 + int automatic_run = config_get_boolean("plugin:charts.d", "enable runnig new scripts", 0);
5851 DIR *dir = NULL;
5852 struct dirent *file = NULL;
5853 struct chartd *cd;
@@ -5790,16 +5865,12 @@ void *chartsd_main(void *ptr)
5865 if(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0) continue;
5866
5867 int len = strlen(file->d_name);
5793 - if(len <= CHARTS_D_FILE_SUFFIX_LEN) continue;
5868 + if(len <= (int)CHARTS_D_FILE_SUFFIX_LEN) continue;
5869 if(strcmp(CHARTS_D_FILE_SUFFIX, &file->d_name[len - CHARTS_D_FILE_SUFFIX_LEN]) != 0) {
5870 debug(D_CHARTSD, "CHARTSD: File '%s' does not end in '%s'.", file->d_name, CHARTS_D_FILE_SUFFIX);
5871 continue;
5872 }
5873
5799 - char varname[CONFIG_MAX_NAME + 1];
5800 - snprintf(varname, CONFIG_MAX_NAME, "plugin %.*s", (int)(len - CHARTS_D_FILE_SUFFIX_LEN), file->d_name);
5801 - if(!config_get_boolean("plugin:charts.d", varname, 1)) continue;
5802 -
5874 // check if it runs already
5875 for(cd = chartsd_root ; cd ; cd = cd->next) {
5876 if(strcmp(cd->filename, file->d_name) == 0) break;
@@ -5815,19 +5886,23 @@ void *chartsd_main(void *ptr)
5886 cd = calloc(sizeof(struct chartd), 1);
5887 if(!cd) fatal("Cannot allocate memory for chart.d");
5888
5889 + snprintf(cd->id, CONFIG_MAX_NAME, "plugin:charts.d:%.*s", (int)(len - CHARTS_D_FILE_SUFFIX_LEN), file->d_name);
5890 +
5891 + strncpy(cd->filename, file->d_name, FILENAME_MAX);
5892 + snprintf(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
5893 +
5894 + cd->enabled = config_get_boolean(cd->id, "enable", automatic_run);
5895 + cd->update_every = config_get_number(cd->id, "update every", update_every);
5896 + snprintf(cd->cmd, CHARTSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "more command options", ""));
5897 +
5898 // link it
5899 if(chartsd_root) cd->next = chartsd_root;
5900 chartsd_root = cd;
5821 -
5822 - // copy its config name
5823 - strncpy(cd->config_name, varname, CONFIG_MAX_NAME);
5901 }
5825 -
5826 - strncpy(cd->filename, file->d_name, FILENAME_MAX);
5827 - snprintf(cd->id, RRD_STATS_NAME_MAX, "plugin:charts.d:%.*s", (int)(len - CHARTS_D_FILE_SUFFIX_LEN), file->d_name);
5828 - snprintf(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
5902 cd->obsolete = 0;
5903
5904 + if(!cd->enabled) continue;
5905 +
5906 // spawn a new thread for it
5907 if(pthread_create(&cd->thread, NULL, chartsd_worker_thread, cd) != 0) {
5908 error("CHARTS.D: failed to create new thread for chart.d %s.", cd->filename);
@@ -5863,7 +5938,7 @@ void kill_childs()
5938
5939 void bye(void)
5940 {
5866 - error("bye...");
5941 + error("exiting. bye...");
5942 kill_childs();
5943 tc_child_pid = 0;
5944 }
@@ -5882,6 +5957,40 @@ void sig_handler(int signo)
5957 break;
5958
5959 case SIGCHLD:
5960 + error("Received SIGCHLD (signal %d).", signo);
5961 + siginfo_t info;
5962 + while(waitid(P_ALL, 0, &info, WEXITED|WNOHANG) == 0) {
5963 + if(!info.si_pid) break;
5964 + switch(info.si_code) {
5965 + case CLD_EXITED:
5966 + error("pid %d exited with code %d.", info.si_pid, info.si_status);
5967 + break;
5968 +
5969 + case CLD_KILLED:
5970 + error("pid %d killed by signal %d.", info.si_pid, info.si_status);
5971 + break;
5972 +
5973 + case CLD_DUMPED:
5974 + error("pid %d core dumped by signal %d.", info.si_pid, info.si_status);
5975 + break;
5976 +
5977 + case CLD_STOPPED:
5978 + error("pid %d stopped by signal %d.", info.si_pid, info.si_status);
5979 + break;
5980 +
5981 + case CLD_TRAPPED:
5982 + error("pid %d trapped by signal %d.", info.si_pid, info.si_status);
5983 + break;
5984 +
5985 + case CLD_CONTINUED:
5986 + error("pid %d continued by signal %d.", info.si_pid, info.si_status);
5987 + break;
5988 +
5989 + default:
5990 + error("pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status);
5991 + break;
5992 + }
5993 + }
5994 break;
5995
5996 default:
@@ -5917,8 +6026,15 @@ int become_user(const char *username)
6026 return(0);
6027 }
6028
6029 +int fd_is_valid(int fd)
6030 +{
6031 + return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
6032 +}
6033 +
6034 void become_daemon()
6035 {
6036 + fflush(NULL);
6037 +
6038 int i = fork();
6039 if(i == -1) {
6040 perror("cannot fork");
@@ -5951,10 +6067,17 @@ void become_daemon()
6067
6068 // close all files
6069 for(i = sysconf(_SC_OPEN_MAX); i > 0; i--)
5954 - if(i != debug_fd) close(i);
6070 + if(i != debug_fd && i != access_fd && i != listen_fd && fd_is_valid(i)) close(i);
6071 +
6072 + silent = 0;
6073 + if(debug_fd == -1) {
6074 + silent = 1;
6075 + debug_fd = open("/dev/null", O_RDWR | O_APPEND | O_CREAT, 0666);
6076 + }
6077
5956 - if(debug_fd >= 0) {
5957 - silent = 0;
6078 + if(debug_fd != -1) {
6079 + if(dup2(debug_fd, STDIN_FILENO) < 0)
6080 + silent = 1;
6081
6082 if(dup2(debug_fd, STDOUT_FILENO) < 0)
6083 silent = 1;
@@ -6015,9 +6138,61 @@ int main(int argc, char **argv)
6138
6139 // --------------------------------------------------------------------
6140
6141 + sprintf(buffer, "0x%08llx", debug_flags);
6142 + char *flags = config_get("debug", "flags", buffer);
6143 + debug_flags = strtoull(flags, NULL, 0);
6144 + debug(D_OPTIONS, "Debug flags set to '0x%8llx'.", debug_flags);
6145 +
6146 + // --------------------------------------------------------------------
6147 +
6148 + debug_log = config_get("debug", "log", "");
6149 + if(*debug_log) {
6150 + debug_fd = open(debug_log, O_RDWR | O_APPEND | O_CREAT, 0666);
6151 + if(debug_fd < 0) {
6152 + fprintf(stderr, "Cannot open file '%s'. Reason: %s\n", debug_log, strerror(errno));
6153 + exit(1);
6154 + }
6155 + debug(D_OPTIONS, "Debug LOG set to '%s'.", debug_log);
6156 + }
6157 +
6158 + // --------------------------------------------------------------------
6159 +
6160 + access_log = config_get("global", "access log", "syslog");
6161 + if(strcmp(access_log, "syslog") == 0) {
6162 + log_syslog = 1;
6163 + access_fd = -1;
6164 + stdaccess = NULL;
6165 +
6166 + debug(D_OPTIONS, "access log on syslog.");
6167 + }
6168 + else if(strcmp(access_log, "none") == 0) {
6169 + log_syslog = 0;
6170 + access_fd = -1;
6171 + stdaccess = NULL;
6172 + debug(D_OPTIONS, "access log disabled.");
6173 + }
6174 + else {
6175 + access_fd = open(access_log, O_WRONLY | O_APPEND | O_CREAT, 0666);
6176 + if(access_fd < 0) {
6177 + fprintf(stderr, "Cannot open file '%s'. Reason: %s\n", access_log, strerror(errno));
6178 + exit(1);
6179 + }
6180 +
6181 + stdaccess = fdopen(access_fd, "w");
6182 + if(!stdaccess) {
6183 + fprintf(stderr, "Cannot migrate file's '%s' fd %d. Reason: %s\n", access_log, access_fd, strerror(errno));
6184 + exit(1);
6185 + }
6186 +
6187 + debug(D_OPTIONS, "access log to file '%s'.", access_log);
6188 + }
6189 +
6190 + // --------------------------------------------------------------------
6191 +
6192 if(gethostname(buffer, HOSTNAME_MAX) == -1)
6193 error("WARNING: Cannot get machine hostname.");
6194 hostname = config_get("global", "hostname", buffer);
6195 + debug(D_OPTIONS, "hostname set to '%s'", hostname);
6196
6197 // --------------------------------------------------------------------
6198
@@ -6032,18 +6207,6 @@ int main(int argc, char **argv)
6207
6208 // --------------------------------------------------------------------
6209
6035 - debug_log = config_get("debug", "log", "");
6036 - if(*debug_log) {
6037 - debug_fd = open(debug_log, O_WRONLY | O_APPEND | O_CREAT, 0666);
6038 - if(debug_fd < 0) {
6039 - fprintf(stderr, "Cannot open file '%s'. Reason: %s\n", debug_log, strerror(errno));
6040 - exit(1);
6041 - }
6042 - debug(D_OPTIONS, "Debug LOG set to '%s'.", debug_log);
6043 - }
6044 -
6045 - // --------------------------------------------------------------------
6046 -
6210 char *user = config_get("global", "run as user", "");
6211 if(*user) {
6212 if(become_user(user) != 0) {
@@ -6055,13 +6218,6 @@ int main(int argc, char **argv)
6218
6219 // --------------------------------------------------------------------
6220
6058 - sprintf(buffer, "0x%08llx", debug_flags);
6059 - char *flags = config_get("debug", "flags", buffer);
6060 - debug_flags = strtoull(flags, NULL, 0);
6061 - debug(D_OPTIONS, "Debug flags set to '0x%8llx'.", debug_flags);
6062 -
6063 - // --------------------------------------------------------------------
6064 -
6221 update_every = config_get_number("global", "update every", UPDATE_EVERY);
6222 if(update_every < 1 || update_every > 600) {
6223 fprintf(stderr, "Invalid update timer %d given. Defaulting to %d.\n", update_every, UPDATE_EVERY_MAX);
@@ -6078,6 +6234,8 @@ int main(int argc, char **argv)
6234 }
6235 else debug(D_OPTIONS, "listen port set to %d.", listen_port);
6236
6237 + listen_fd = create_listen_socket(listen_port);
6238 +
6239 // --------------------------------------------------------------------
6240
6241 daemon = config_get_boolean("global", "daemon", 0);
@@ -6094,9 +6252,10 @@ int main(int argc, char **argv)
6252
6253 if(daemon) become_daemon();
6254
6097 - // open syslog
6098 - openlog("netdata", LOG_PID, LOG_DAEMON);
6099 - syslog(LOG_NOTICE, "netdata started.");
6255 + if(log_syslog) {
6256 + openlog("netdata", LOG_PID, LOG_DAEMON);
6257 + syslog(LOG_NOTICE, "netdata started.");
6258 + }
6259
6260 // make sure we cleanup correctly
6261 atexit(bye);
netdata.start
+1 -1
@@ -59,7 +59,7 @@ echo "Compiling netdata (debug=$NETDATA_CONFIG_DEBUG)"
59 if [ $NETDATA_CONFIG_DEBUG -eq 1 ]
60 then
61 ulimit -c unlimited
62 - gcc -Wall -ggdb -o netdata netdata.c -lpthread -lz || exit 1
62 + gcc -Wall -Wextra -ggdb -o netdata netdata.c -lpthread -lz || exit 1
63 debug_opts="-df 0xfffffadf -dl netdata.log"
64 else
65 gcc -Wall -O3 -o netdata netdata.c -lpthread -lz || exit 1