master
c 79 lines 2.32 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "nd_log-internals.h"
4
5 void chown_open_file(int fd, uid_t uid, gid_t gid) {
6 if(fd == -1) return;
7
8 struct stat buf;
9
10 if(fstat(fd, &buf) == -1) {
11 netdata_log_error("Cannot fstat() fd %d", fd);
12 return;
13 }
14
15 if((buf.st_uid != uid || buf.st_gid != gid) && S_ISREG(buf.st_mode)) {
16 if(fchown(fd, uid, gid) == -1)
17 netdata_log_error("Cannot fchown() fd %d.", fd);
18 }
19 }
20
21 void nd_log_chown_log_files(uid_t uid, gid_t gid) {
22 for(size_t i = 0 ; i < _NDLS_MAX ; i++) {
23 if(nd_log.sources[i].fd != -1 && nd_log.sources[i].fd != STDIN_FILENO)
24 chown_open_file(nd_log.sources[i].fd, uid, gid);
25 }
26 }
27
28 bool nd_logger_file(int fd, FILE *fp, netdata_mutex_t *mutex, ND_LOG_FORMAT format, struct log_field *fields, size_t fields_max) {
29 (void)fp;
30
31 BUFFER *wb = buffer_create(1024, NULL);
32
33 if(format == NDLF_JSON)
34 nd_logger_json(wb, fields, fields_max);
35 else
36 nd_logger_logfmt(wb, fields, fields_max);
37
38 buffer_strcat(wb, "\n");
39
40 // Serialize writes with a Netdata-owned mutex and use write() on the raw fd.
41 //
42 // We avoid libc's stdio locking (flockfile/funlockfile) because spawn-server
43 // children inherit FILE* state across fork(). In those post-fork children we
44 // disable logger mutexes entirely, since they are single-threaded at that point.
45 //
46 // A netdata_mutex_t sleeps on contention rather than busy-waiting, so blocked
47 // I/O (full pipe, slow disk) does not burn CPU in other logging threads.
48 //
49 // Logger-owned streams are configured unbuffered when opened, so the logger
50 // can stay on raw fd writes here without taking stdio-internal locks.
51
52 const char *buf = buffer_tostring(wb);
53 size_t remaining = buffer_strlen(wb);
54
55 if(mutex)
56 netdata_mutex_lock(mutex);
57
58 while(remaining > 0) {
59 size_t chunk = remaining;
60 if(chunk > (size_t)SSIZE_MAX)
61 chunk = (size_t)SSIZE_MAX;
62
63 ssize_t written = write(fd, buf, chunk);
64 if(written > 0) {
65 buf += written;
66 remaining -= written;
67 }
68 else if(written == 0)
69 break;
70 else if(errno != EINTR)
71 break;
72 }
73
74 if(mutex)
75 netdata_mutex_unlock(mutex);
76
77 buffer_free(wb);
78 return remaining == 0;
79 }