]> arthur.barton.de Git - netdata.git/blob - src/common.c
small changes, adaptation of #428 from @fredericopissarra
[netdata.git] / src / common.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 #include <sys/syscall.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <errno.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <sys/mman.h>
13
14
15 #include "log.h"
16 #include "common.h"
17 #include "appconfig.h"
18 #include "../config.h"
19
20 char *global_host_prefix = "";
21 int enable_ksm = 1;
22
23 // time(NULL) in milliseconds
24 unsigned long long timems(void) {
25         struct timeval now;
26         gettimeofday(&now, NULL);
27         return now.tv_sec * 1000000ULL + now.tv_usec;
28 }
29
30 unsigned char netdata_map_chart_names[256] = {
31                 [0] = '\0', //
32                 [1] = '_', //
33                 [2] = '_', //
34                 [3] = '_', //
35                 [4] = '_', //
36                 [5] = '_', //
37                 [6] = '_', //
38                 [7] = '_', //
39                 [8] = '_', //
40                 [9] = '_', //
41                 [10] = '_', //
42                 [11] = '_', //
43                 [12] = '_', //
44                 [13] = '_', //
45                 [14] = '_', //
46                 [15] = '_', //
47                 [16] = '_', //
48                 [17] = '_', //
49                 [18] = '_', //
50                 [19] = '_', //
51                 [20] = '_', //
52                 [21] = '_', //
53                 [22] = '_', //
54                 [23] = '_', //
55                 [24] = '_', //
56                 [25] = '_', //
57                 [26] = '_', //
58                 [27] = '_', //
59                 [28] = '_', //
60                 [29] = '_', //
61                 [30] = '_', //
62                 [31] = '_', //
63                 [32] = '_', //
64                 [33] = '_', // !
65                 [34] = '_', // "
66                 [35] = '_', // #
67                 [36] = '_', // $
68                 [37] = '_', // %
69                 [38] = '_', // &
70                 [39] = '_', // '
71                 [40] = '_', // (
72                 [41] = '_', // )
73                 [42] = '_', // *
74                 [43] = '_', // +
75                 [44] = '.', // ,
76                 [45] = '-', // -
77                 [46] = '.', // .
78                 [47] = '/', // /
79                 [48] = '0', // 0
80                 [49] = '1', // 1
81                 [50] = '2', // 2
82                 [51] = '3', // 3
83                 [52] = '4', // 4
84                 [53] = '5', // 5
85                 [54] = '6', // 6
86                 [55] = '7', // 7
87                 [56] = '8', // 8
88                 [57] = '9', // 9
89                 [58] = '_', // :
90                 [59] = '_', // ;
91                 [60] = '_', // <
92                 [61] = '_', // =
93                 [62] = '_', // >
94                 [63] = '_', // ?
95                 [64] = '_', // @
96                 [65] = 'a', // A
97                 [66] = 'b', // B
98                 [67] = 'c', // C
99                 [68] = 'd', // D
100                 [69] = 'e', // E
101                 [70] = 'f', // F
102                 [71] = 'g', // G
103                 [72] = 'h', // H
104                 [73] = 'i', // I
105                 [74] = 'j', // J
106                 [75] = 'k', // K
107                 [76] = 'l', // L
108                 [77] = 'm', // M
109                 [78] = 'n', // N
110                 [79] = 'o', // O
111                 [80] = 'p', // P
112                 [81] = 'q', // Q
113                 [82] = 'r', // R
114                 [83] = 's', // S
115                 [84] = 't', // T
116                 [85] = 'u', // U
117                 [86] = 'v', // V
118                 [87] = 'w', // W
119                 [88] = 'x', // X
120                 [89] = 'y', // Y
121                 [90] = 'z', // Z
122                 [91] = '_', // [
123                 [92] = '/', // backslash
124                 [93] = '_', // ]
125                 [94] = '_', // ^
126                 [95] = '_', // _
127                 [96] = '_', // `
128                 [97] = 'a', // a
129                 [98] = 'b', // b
130                 [99] = 'c', // c
131                 [100] = 'd', // d
132                 [101] = 'e', // e
133                 [102] = 'f', // f
134                 [103] = 'g', // g
135                 [104] = 'h', // h
136                 [105] = 'i', // i
137                 [106] = 'j', // j
138                 [107] = 'k', // k
139                 [108] = 'l', // l
140                 [109] = 'm', // m
141                 [110] = 'n', // n
142                 [111] = 'o', // o
143                 [112] = 'p', // p
144                 [113] = 'q', // q
145                 [114] = 'r', // r
146                 [115] = 's', // s
147                 [116] = 't', // t
148                 [117] = 'u', // u
149                 [118] = 'v', // v
150                 [119] = 'w', // w
151                 [120] = 'x', // x
152                 [121] = 'y', // y
153                 [122] = 'z', // z
154                 [123] = '_', // {
155                 [124] = '_', // |
156                 [125] = '_', // }
157                 [126] = '_', // ~
158                 [127] = '_', //
159                 [128] = '_', //
160                 [129] = '_', //
161                 [130] = '_', //
162                 [131] = '_', //
163                 [132] = '_', //
164                 [133] = '_', //
165                 [134] = '_', //
166                 [135] = '_', //
167                 [136] = '_', //
168                 [137] = '_', //
169                 [138] = '_', //
170                 [139] = '_', //
171                 [140] = '_', //
172                 [141] = '_', //
173                 [142] = '_', //
174                 [143] = '_', //
175                 [144] = '_', //
176                 [145] = '_', //
177                 [146] = '_', //
178                 [147] = '_', //
179                 [148] = '_', //
180                 [149] = '_', //
181                 [150] = '_', //
182                 [151] = '_', //
183                 [152] = '_', //
184                 [153] = '_', //
185                 [154] = '_', //
186                 [155] = '_', //
187                 [156] = '_', //
188                 [157] = '_', //
189                 [158] = '_', //
190                 [159] = '_', //
191                 [160] = '_', //
192                 [161] = '_', //
193                 [162] = '_', //
194                 [163] = '_', //
195                 [164] = '_', //
196                 [165] = '_', //
197                 [166] = '_', //
198                 [167] = '_', //
199                 [168] = '_', //
200                 [169] = '_', //
201                 [170] = '_', //
202                 [171] = '_', //
203                 [172] = '_', //
204                 [173] = '_', //
205                 [174] = '_', //
206                 [175] = '_', //
207                 [176] = '_', //
208                 [177] = '_', //
209                 [178] = '_', //
210                 [179] = '_', //
211                 [180] = '_', //
212                 [181] = '_', //
213                 [182] = '_', //
214                 [183] = '_', //
215                 [184] = '_', //
216                 [185] = '_', //
217                 [186] = '_', //
218                 [187] = '_', //
219                 [188] = '_', //
220                 [189] = '_', //
221                 [190] = '_', //
222                 [191] = '_', //
223                 [192] = '_', //
224                 [193] = '_', //
225                 [194] = '_', //
226                 [195] = '_', //
227                 [196] = '_', //
228                 [197] = '_', //
229                 [198] = '_', //
230                 [199] = '_', //
231                 [200] = '_', //
232                 [201] = '_', //
233                 [202] = '_', //
234                 [203] = '_', //
235                 [204] = '_', //
236                 [205] = '_', //
237                 [206] = '_', //
238                 [207] = '_', //
239                 [208] = '_', //
240                 [209] = '_', //
241                 [210] = '_', //
242                 [211] = '_', //
243                 [212] = '_', //
244                 [213] = '_', //
245                 [214] = '_', //
246                 [215] = '_', //
247                 [216] = '_', //
248                 [217] = '_', //
249                 [218] = '_', //
250                 [219] = '_', //
251                 [220] = '_', //
252                 [221] = '_', //
253                 [222] = '_', //
254                 [223] = '_', //
255                 [224] = '_', //
256                 [225] = '_', //
257                 [226] = '_', //
258                 [227] = '_', //
259                 [228] = '_', //
260                 [229] = '_', //
261                 [230] = '_', //
262                 [231] = '_', //
263                 [232] = '_', //
264                 [233] = '_', //
265                 [234] = '_', //
266                 [235] = '_', //
267                 [236] = '_', //
268                 [237] = '_', //
269                 [238] = '_', //
270                 [239] = '_', //
271                 [240] = '_', //
272                 [241] = '_', //
273                 [242] = '_', //
274                 [243] = '_', //
275                 [244] = '_', //
276                 [245] = '_', //
277                 [246] = '_', //
278                 [247] = '_', //
279                 [248] = '_', //
280                 [249] = '_', //
281                 [250] = '_', //
282                 [251] = '_', //
283                 [252] = '_', //
284                 [253] = '_', //
285                 [254] = '_', //
286                 [255] = '_'  //
287 };
288
289 // make sure the supplied string
290 // is good for a netdata chart/dimension ID/NAME
291 void netdata_fix_chart_name(char *s) {
292         while((*s = netdata_map_chart_names[(unsigned char)*s])) s++;
293 }
294
295 unsigned char netdata_map_chart_ids[256] = {
296                 [0] = '\0', //
297                 [1] = '_', //
298                 [2] = '_', //
299                 [3] = '_', //
300                 [4] = '_', //
301                 [5] = '_', //
302                 [6] = '_', //
303                 [7] = '_', //
304                 [8] = '_', //
305                 [9] = '_', //
306                 [10] = '_', //
307                 [11] = '_', //
308                 [12] = '_', //
309                 [13] = '_', //
310                 [14] = '_', //
311                 [15] = '_', //
312                 [16] = '_', //
313                 [17] = '_', //
314                 [18] = '_', //
315                 [19] = '_', //
316                 [20] = '_', //
317                 [21] = '_', //
318                 [22] = '_', //
319                 [23] = '_', //
320                 [24] = '_', //
321                 [25] = '_', //
322                 [26] = '_', //
323                 [27] = '_', //
324                 [28] = '_', //
325                 [29] = '_', //
326                 [30] = '_', //
327                 [31] = '_', //
328                 [32] = '_', //
329                 [33] = '_', // !
330                 [34] = '_', // "
331                 [35] = '_', // #
332                 [36] = '_', // $
333                 [37] = '_', // %
334                 [38] = '_', // &
335                 [39] = '_', // '
336                 [40] = '_', // (
337                 [41] = '_', // )
338                 [42] = '_', // *
339                 [43] = '_', // +
340                 [44] = '.', // ,
341                 [45] = '-', // -
342                 [46] = '.', // .
343                 [47] = '_', // /
344                 [48] = '0', // 0
345                 [49] = '1', // 1
346                 [50] = '2', // 2
347                 [51] = '3', // 3
348                 [52] = '4', // 4
349                 [53] = '5', // 5
350                 [54] = '6', // 6
351                 [55] = '7', // 7
352                 [56] = '8', // 8
353                 [57] = '9', // 9
354                 [58] = '_', // :
355                 [59] = '_', // ;
356                 [60] = '_', // <
357                 [61] = '_', // =
358                 [62] = '_', // >
359                 [63] = '_', // ?
360                 [64] = '_', // @
361                 [65] = 'a', // A
362                 [66] = 'b', // B
363                 [67] = 'c', // C
364                 [68] = 'd', // D
365                 [69] = 'e', // E
366                 [70] = 'f', // F
367                 [71] = 'g', // G
368                 [72] = 'h', // H
369                 [73] = 'i', // I
370                 [74] = 'j', // J
371                 [75] = 'k', // K
372                 [76] = 'l', // L
373                 [77] = 'm', // M
374                 [78] = 'n', // N
375                 [79] = 'o', // O
376                 [80] = 'p', // P
377                 [81] = 'q', // Q
378                 [82] = 'r', // R
379                 [83] = 's', // S
380                 [84] = 't', // T
381                 [85] = 'u', // U
382                 [86] = 'v', // V
383                 [87] = 'w', // W
384                 [88] = 'x', // X
385                 [89] = 'y', // Y
386                 [90] = 'z', // Z
387                 [91] = '_', // [
388                 [92] = '/', // backslash
389                 [93] = '_', // ]
390                 [94] = '_', // ^
391                 [95] = '_', // _
392                 [96] = '_', // `
393                 [97] = 'a', // a
394                 [98] = 'b', // b
395                 [99] = 'c', // c
396                 [100] = 'd', // d
397                 [101] = 'e', // e
398                 [102] = 'f', // f
399                 [103] = 'g', // g
400                 [104] = 'h', // h
401                 [105] = 'i', // i
402                 [106] = 'j', // j
403                 [107] = 'k', // k
404                 [108] = 'l', // l
405                 [109] = 'm', // m
406                 [110] = 'n', // n
407                 [111] = 'o', // o
408                 [112] = 'p', // p
409                 [113] = 'q', // q
410                 [114] = 'r', // r
411                 [115] = 's', // s
412                 [116] = 't', // t
413                 [117] = 'u', // u
414                 [118] = 'v', // v
415                 [119] = 'w', // w
416                 [120] = 'x', // x
417                 [121] = 'y', // y
418                 [122] = 'z', // z
419                 [123] = '_', // {
420                 [124] = '_', // |
421                 [125] = '_', // }
422                 [126] = '_', // ~
423                 [127] = '_', //
424                 [128] = '_', //
425                 [129] = '_', //
426                 [130] = '_', //
427                 [131] = '_', //
428                 [132] = '_', //
429                 [133] = '_', //
430                 [134] = '_', //
431                 [135] = '_', //
432                 [136] = '_', //
433                 [137] = '_', //
434                 [138] = '_', //
435                 [139] = '_', //
436                 [140] = '_', //
437                 [141] = '_', //
438                 [142] = '_', //
439                 [143] = '_', //
440                 [144] = '_', //
441                 [145] = '_', //
442                 [146] = '_', //
443                 [147] = '_', //
444                 [148] = '_', //
445                 [149] = '_', //
446                 [150] = '_', //
447                 [151] = '_', //
448                 [152] = '_', //
449                 [153] = '_', //
450                 [154] = '_', //
451                 [155] = '_', //
452                 [156] = '_', //
453                 [157] = '_', //
454                 [158] = '_', //
455                 [159] = '_', //
456                 [160] = '_', //
457                 [161] = '_', //
458                 [162] = '_', //
459                 [163] = '_', //
460                 [164] = '_', //
461                 [165] = '_', //
462                 [166] = '_', //
463                 [167] = '_', //
464                 [168] = '_', //
465                 [169] = '_', //
466                 [170] = '_', //
467                 [171] = '_', //
468                 [172] = '_', //
469                 [173] = '_', //
470                 [174] = '_', //
471                 [175] = '_', //
472                 [176] = '_', //
473                 [177] = '_', //
474                 [178] = '_', //
475                 [179] = '_', //
476                 [180] = '_', //
477                 [181] = '_', //
478                 [182] = '_', //
479                 [183] = '_', //
480                 [184] = '_', //
481                 [185] = '_', //
482                 [186] = '_', //
483                 [187] = '_', //
484                 [188] = '_', //
485                 [189] = '_', //
486                 [190] = '_', //
487                 [191] = '_', //
488                 [192] = '_', //
489                 [193] = '_', //
490                 [194] = '_', //
491                 [195] = '_', //
492                 [196] = '_', //
493                 [197] = '_', //
494                 [198] = '_', //
495                 [199] = '_', //
496                 [200] = '_', //
497                 [201] = '_', //
498                 [202] = '_', //
499                 [203] = '_', //
500                 [204] = '_', //
501                 [205] = '_', //
502                 [206] = '_', //
503                 [207] = '_', //
504                 [208] = '_', //
505                 [209] = '_', //
506                 [210] = '_', //
507                 [211] = '_', //
508                 [212] = '_', //
509                 [213] = '_', //
510                 [214] = '_', //
511                 [215] = '_', //
512                 [216] = '_', //
513                 [217] = '_', //
514                 [218] = '_', //
515                 [219] = '_', //
516                 [220] = '_', //
517                 [221] = '_', //
518                 [222] = '_', //
519                 [223] = '_', //
520                 [224] = '_', //
521                 [225] = '_', //
522                 [226] = '_', //
523                 [227] = '_', //
524                 [228] = '_', //
525                 [229] = '_', //
526                 [230] = '_', //
527                 [231] = '_', //
528                 [232] = '_', //
529                 [233] = '_', //
530                 [234] = '_', //
531                 [235] = '_', //
532                 [236] = '_', //
533                 [237] = '_', //
534                 [238] = '_', //
535                 [239] = '_', //
536                 [240] = '_', //
537                 [241] = '_', //
538                 [242] = '_', //
539                 [243] = '_', //
540                 [244] = '_', //
541                 [245] = '_', //
542                 [246] = '_', //
543                 [247] = '_', //
544                 [248] = '_', //
545                 [249] = '_', //
546                 [250] = '_', //
547                 [251] = '_', //
548                 [252] = '_', //
549                 [253] = '_', //
550                 [254] = '_', //
551                 [255] = '_'  //
552 };
553
554 // make sure the supplied string
555 // is good for a netdata chart/dimension ID/NAME
556 void netdata_fix_chart_id(char *s) {
557         while((*s = netdata_map_chart_ids[(unsigned char)*s])) s++;
558 }
559
560 /*
561 // http://stackoverflow.com/questions/7666509/hash-function-for-string
562 uint32_t simple_hash(const char *name)
563 {
564         const char *s = name;
565         uint32_t hash = 5381;
566         int i;
567
568         while((i = *s++)) hash = ((hash << 5) + hash) + i;
569
570         // fprintf(stderr, "HASH: %lu %s\n", hash, name);
571
572         return hash;
573 }
574 */
575
576
577 // http://isthe.com/chongo/tech/comp/fnv/#FNV-1a
578 uint32_t simple_hash(const char *name) {
579         unsigned char *s = (unsigned char *)name;
580         uint32_t hval = 0x811c9dc5;
581
582         // FNV-1a algorithm
583         while (*s) {
584                 // multiply by the 32 bit FNV magic prime mod 2^32
585                 // NOTE: No need to optimize with left shifts.
586                 //       GCC will use imul instruction anyway.
587                 //       Tested with 'gcc -O3 -S'
588                 //hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
589                 hval *= 16777619;
590
591                 // xor the bottom with the current octet
592                 hval ^= (uint32_t)*s++;
593         }
594
595         // fprintf(stderr, "HASH: %u = %s\n", hval, name);
596         return hval;
597 }
598
599 uint32_t simple_uhash(const char *name) {
600         unsigned char *s = (unsigned char *)name;
601         uint32_t hval = 0x811c9dc5, c;
602
603         // FNV-1a algorithm
604         while((c = *s++)) {
605                 if(unlikely(c >= 'A' && c <= 'Z')) c += 'a' - 'A';
606                 hval *= 16777619;
607                 hval ^= c;
608         }
609         return hval;
610 }
611
612 /*
613 // http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
614 // one at a time hash
615 uint32_t simple_hash(const char *name) {
616         unsigned char *s = (unsigned char *)name;
617         uint32_t h = 0;
618
619         while(*s) {
620                 h += *s++;
621                 h += (h << 10);
622                 h ^= (h >> 6);
623         }
624
625         h += (h << 3);
626         h ^= (h >> 11);
627         h += (h << 15);
628
629         // fprintf(stderr, "HASH: %u = %s\n", h, name);
630
631         return h;
632 }
633 */
634
635 void strreverse(char* begin, char* end)
636 {
637         char aux;
638
639         while (end > begin)
640         {
641                 // clearer code.
642                 aux = *end;
643                 *end-- = *begin;
644                 *begin++ = aux;
645         }
646 }
647
648 char *mystrsep(char **ptr, char *s)
649 {
650         char *p = "";
651         while ( p && !p[0] && *ptr ) p = strsep(ptr, s);
652         return(p);
653 }
654
655 char *trim(char *s)
656 {
657         // skip leading spaces
658         // and 'comments' as well!?
659         while(*s && isspace(*s)) s++;
660         if(!*s || *s == '#') return NULL;
661
662         // skip tailing spaces
663         // this way is way faster. Writes only one NUL char.
664         ssize_t l = strlen(s);
665   if (--l >= 0)
666         {
667                 char *p = s + l;
668                 while (p > s && isspace(*p)) p--;
669                 *++p = '\0';
670         }
671
672         if(!*s) return NULL;
673
674         return s;
675 }
676
677 void *mymmap(const char *filename, size_t size, int flags, int ksm)
678 {
679         int fd;
680         void *mem = NULL;
681
682         errno = 0;
683         fd = open(filename, O_RDWR|O_CREAT|O_NOATIME, 0664);
684         if(fd != -1) {
685                 if(lseek(fd, size, SEEK_SET) == (off_t)size) {
686                         if(write(fd, "", 1) == 1) {
687                                 if(ftruncate(fd, size))
688                                         error("Cannot truncate file '%s' to size %ld. Will use the larger file.", filename, size);
689
690 #ifdef MADV_MERGEABLE
691                                 if(flags & MAP_SHARED || !enable_ksm || !ksm) {
692 #endif
693                                         mem = mmap(NULL, size, PROT_READ|PROT_WRITE, flags, fd, 0);
694                                         if(mem != MAP_FAILED) {
695                                                 int advise = MADV_SEQUENTIAL|MADV_DONTFORK;
696                                                 if(flags & MAP_SHARED) advise |= MADV_WILLNEED;
697
698                                                 if(madvise(mem, size, advise) != 0)
699                                                         error("Cannot advise the kernel about the memory usage of file '%s'.", filename);
700                                         }
701 #ifdef MADV_MERGEABLE
702                                 }
703                                 else {
704                                         mem = mmap(NULL, size, PROT_READ|PROT_WRITE, flags|MAP_ANONYMOUS, -1, 0);
705                                         if(mem != MAP_FAILED) {
706                                                 if(lseek(fd, 0, SEEK_SET) == 0) {
707                                                         if(read(fd, mem, size) != (ssize_t)size)
708                                                                 error("Cannot read from file '%s'", filename);
709                                                 }
710                                                 else
711                                                         error("Cannot seek to beginning of file '%s'.", filename);
712
713                                                 // don't use MADV_SEQUENTIAL|MADV_DONTFORK, they disable MADV_MERGEABLE
714                                                 if(madvise(mem, size, MADV_SEQUENTIAL|MADV_DONTFORK) != 0)
715                                                         error("Cannot advise the kernel about the memory usage (MADV_SEQUENTIAL|MADV_DONTFORK) of file '%s'.", filename);
716
717                                                 if(madvise(mem, size, MADV_MERGEABLE) != 0)
718                                                         error("Cannot advise the kernel about the memory usage (MADV_MERGEABLE) of file '%s'.", filename);
719                                         }
720                                         else
721                                                 error("Cannot allocate PRIVATE ANONYMOUS memory for KSM for file '%s'.", filename);
722                                 }
723 #endif
724                         }
725                         else error("Cannot write to file '%s' at position %ld.", filename, size);
726                 }
727                 else error("Cannot seek file '%s' to size %ld.", filename, size);
728
729                 close(fd);
730         }
731         else error("Cannot create/open file '%s'.", filename);
732
733         return mem;
734 }
735
736 int savememory(const char *filename, void *mem, size_t size)
737 {
738         char tmpfilename[FILENAME_MAX + 1];
739
740         snprintfz(tmpfilename, FILENAME_MAX, "%s.%ld.tmp", filename, (long)getpid());
741
742         int fd = open(tmpfilename, O_RDWR|O_CREAT|O_NOATIME, 0664);
743         if(fd < 0) {
744                 error("Cannot create/open file '%s'.", filename);
745                 return -1;
746         }
747
748         if(write(fd, mem, size) != (ssize_t)size) {
749                 error("Cannot write to file '%s' %ld bytes.", filename, (long)size);
750                 close(fd);
751                 return -1;
752         }
753
754         close(fd);
755
756         if(rename(tmpfilename, filename)) {
757                 error("Cannot rename '%s' to '%s'", tmpfilename, filename);
758                 return -1;
759         }
760
761         return 0;
762 }
763
764 int fd_is_valid(int fd) {
765     return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
766 }
767
768 /*
769  ***************************************************************************
770  * Get number of clock ticks per second.
771  ***************************************************************************
772  */
773 unsigned int hz;
774
775 void get_HZ(void)
776 {
777         long ticks;
778
779         if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
780                 perror("sysconf");
781         }
782
783         hz = (unsigned int) ticks;
784 }
785
786 pid_t gettid(void)
787 {
788         return syscall(SYS_gettid);
789 }
790
791 char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) {
792         char *s = fgets(buf, buf_size, fp);
793         if(!s) return NULL;
794
795         char *t = s;
796         if(*t != '\0') {
797                 // find the string end
798                 while (*++t != '\0');
799
800                 // trim trailing spaces/newlines/tabs
801                 while (--t > s && *t == '\n')
802                         *t = '\0';
803         }
804
805         if(len)
806                 *len = t - s + 1;
807
808         return s;
809 }
810
811 char *strncpyz(char *dst, const char *src, size_t n) {
812         char *p = dst;
813
814         while(*src && n--)
815                 *dst++ = *src++;
816
817         *dst = '\0';
818
819         return p;
820 }
821
822 int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
823         int size;
824
825         size = vsnprintf(dst, n, fmt, args);
826
827         if(unlikely((size_t)size > n)) {
828                 // there is bug in vsnprintf() and it returns
829                 // a number higher to len, but it does not
830                 // overflow the buffer.
831                 size = n;
832         }
833
834         dst[size] = '\0';
835         return size;
836 }
837
838 int snprintfz(char *dst, size_t n, const char *fmt, ...) {
839         va_list args;
840
841         va_start(args, fmt);
842         return vsnprintfz(dst, n, fmt, args);
843         va_end(args);
844 }