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