Extended MOTD with GUI
[tomato.git] / release / src / router / shared / shutils.c
blob639bae2ff7087fd1e717f235ae6f6dff21fbdc2c
1 /*
2 Copyright 2005, Broadcom Corporation
3 All Rights Reserved.
5 THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
6 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
7 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
8 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 # ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 # endif
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <errno.h>
19 #include <error.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <termios.h>
29 #include <sys/ioctl.h>
30 #include <sys/time.h>
31 // #include <net/ethernet.h>
32 #include <syslog.h>
34 #include <wlioctl.h>
35 #include <bcmnvram.h>
37 #include "shutils.h"
38 #include "shared.h"
41 * Concatenates NULL-terminated list of arguments into a single
42 * commmand and executes it
43 * @param argv argument list
44 * @param path NULL, ">output", or ">>output"
45 * @param timeout seconds to wait before timing out or 0 for no timeout
46 * @param ppid NULL to wait for child termination or pointer to pid
47 * @return return value of executed command or errno
49 * Ref: http://www.open-std.org/jtc1/sc22/WG15/docs/rr/9945-2/9945-2-28.html
51 int _eval(char *const argv[], const char *path, int timeout, int *ppid)
53 sigset_t set, sigmask;
54 sighandler_t chld = SIG_IGN;
55 pid_t pid, w;
56 int status = 0;
57 int fd;
58 int flags;
59 int sig;
60 int n;
61 const char *p;
62 char s[256];
64 if (!ppid) {
65 // block SIGCHLD
66 sigemptyset(&set);
67 sigaddset(&set, SIGCHLD);
68 sigprocmask(SIG_BLOCK, &set, &sigmask);
69 // without this we cannot rely on waitpid() to tell what happened to our children
70 chld = signal(SIGCHLD, SIG_DFL);
73 pid = fork();
74 if (pid == -1) {
75 perror("fork");
76 status = errno;
77 goto EXIT;
79 if (pid != 0) {
80 // parent
81 if (ppid) {
82 *ppid = pid;
83 return 0;
85 do {
86 if ((w = waitpid(pid, &status, 0)) == -1) {
87 status = errno;
88 perror("waitpid");
89 goto EXIT;
91 } while (!WIFEXITED(status) && !WIFSIGNALED(status));
93 if (WIFEXITED(status)) status = WEXITSTATUS(status);
94 EXIT:
95 if (!ppid) {
96 // restore signals
97 sigprocmask(SIG_SETMASK, &sigmask, NULL);
98 signal(SIGCHLD, chld);
99 // reap zombies
100 chld_reap(0);
102 return status;
105 // child
107 // reset signal handlers
108 for (sig = 0; sig < (_NSIG - 1); sig++)
109 signal(sig, SIG_DFL);
111 // unblock signals if called from signal handler
112 sigemptyset(&set);
113 sigprocmask(SIG_SETMASK, &set, NULL);
115 setsid();
117 close(STDIN_FILENO);
118 close(STDOUT_FILENO);
119 close(STDERR_FILENO);
120 open("/dev/null", O_RDONLY);
121 open("/dev/null", O_WRONLY);
122 open("/dev/null", O_WRONLY);
124 if (nvram_match("debug_logeval", "1")) {
125 pid = getpid();
127 cprintf("_eval +%ld pid=%d ", get_uptime(), pid);
128 for (n = 0; argv[n]; ++n) cprintf("%s ", argv[n]);
129 cprintf("\n");
131 if ((fd = open("/dev/console", O_RDWR)) >= 0) {
132 dup2(fd, STDIN_FILENO);
133 dup2(fd, STDOUT_FILENO);
134 dup2(fd, STDERR_FILENO);
136 else {
137 sprintf(s, "/tmp/eval.%d", pid);
138 if ((fd = open(s, O_CREAT|O_RDWR, 0600)) >= 0) {
139 dup2(fd, STDOUT_FILENO);
140 dup2(fd, STDERR_FILENO);
143 if (fd > STDERR_FILENO) close(fd);
146 // Redirect stdout & stderr to <path>
147 if (path) {
148 flags = O_WRONLY | O_CREAT;
149 if (*path == '>') {
150 ++path;
151 if (*path == '>') {
152 ++path;
153 // >>path, append
154 flags |= O_APPEND;
156 else {
157 // >path, overwrite
158 flags |= O_TRUNC;
162 if ((fd = open(path, flags, 0644)) < 0) {
163 perror(path);
165 else {
166 dup2(fd, STDOUT_FILENO);
167 dup2(fd, STDERR_FILENO);
168 close(fd);
172 // execute command
174 p = nvram_safe_get("env_path");
175 snprintf(s, sizeof(s), "%s%s/sbin:/bin:/usr/sbin:/usr/bin:/opt/sbin:/opt/bin", *p ? p : "", *p ? ":" : "");
176 setenv("PATH", s, 1);
178 alarm(timeout);
179 execvp(argv[0], argv);
181 perror(argv[0]);
182 _exit(errno);
186 * fread() with automatic retry on syscall interrupt
187 * @param ptr location to store to
188 * @param size size of each element of data
189 * @param nmemb number of elements
190 * @param stream file stream
191 * @return number of items successfully read
193 int safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
195 size_t ret = 0;
196 do {
197 clearerr(stream);
198 ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
199 } while (ret < nmemb && ferror(stream) && errno == EINTR);
200 return ret;
204 * fwrite() with automatic retry on syscall interrupt
205 * @param ptr location to read from
206 * @param size size of each element of data
207 * @param nmemb number of elements
208 * @param stream file stream
209 * @return number of items successfully written
211 int safe_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
213 size_t ret = 0;
214 do {
215 clearerr(stream);
216 ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
217 } while (ret < nmemb && ferror(stream) && errno == EINTR);
219 return ret;
223 * Convert Ethernet address string representation to binary data
224 * @param a string in xx:xx:xx:xx:xx:xx notation
225 * @param e binary data
226 * @return TRUE if conversion was successful and FALSE otherwise
228 int ether_atoe(const char *a, unsigned char *e)
230 char *x;
231 int i;
233 i = 0;
234 while (1) {
235 e[i++] = (unsigned char) strtoul(a, &x, 16);
236 if (a == x) break;
237 if (i == ETHER_ADDR_LEN) return 1;
238 if (*x == 0) break;
239 a = x + 1;
241 memset(e, 0, sizeof(e));
242 return 0;
246 * Convert Ethernet address binary data to string representation
247 * @param e binary data
248 * @param a string in xx:xx:xx:xx:xx:xx notation
249 * @return a
251 char *ether_etoa(const unsigned char *e, char *a)
253 sprintf(a, "%02X:%02X:%02X:%02X:%02X:%02X", e[0], e[1], e[2], e[3], e[4], e[5]);
254 return a;
257 void cprintf(const char *format, ...)
259 FILE *f;
260 va_list args;
262 #ifdef DEBUG_NOISY
264 #else
265 if (nvram_match("debug_cprintf", "1")) {
266 #endif
267 if ((f = fopen("/dev/console", "w")) != NULL) {
268 va_start(args, format);
269 vfprintf(f, format, args);
270 va_end(args);
271 fclose(f);
274 #if 1
275 if (nvram_match("debug_cprintf_file", "1")) {
276 // char s[32];
277 // sprintf(s, "/tmp/cprintf.%d", getpid());
278 // if ((f = fopen(s, "a")) != NULL) {
279 if ((f = fopen("/tmp/cprintf", "a")) != NULL) {
280 va_start(args, format);
281 vfprintf(f, format, args);
282 va_end(args);
283 fclose(f);
286 #endif
287 #if 0
288 if (nvram_match("debug_cprintf_log", "1")) {
289 char s[512];
291 va_start(args, format);
292 vsnprintf(s, sizeof(s), format, args);
293 s[sizeof(s) - 1] = 0;
294 va_end(args);
296 if ((s[0] != '\n') || (s[1] != 0)) syslog(LOG_DEBUG, "%s", s);
298 #endif
302 #ifndef WL_BSS_INFO_VERSION
303 #error WL_BSS_INFO_VERSION
304 #endif
306 #if WL_BSS_INFO_VERSION >= 108
307 // xref (all): nas, wlconf
309 #ifndef MAX_NVPARSE
310 #define MAX_NVPARSE 255
311 #endif
313 #if 0
315 * Get the ip configuration index if it exists given the
316 * eth name.
318 * @param wl_ifname pointer to eth interface name
319 * @return index or -1 if not found
322 get_ipconfig_index(char *eth_ifname)
324 char varname[64];
325 char varval[64];
326 char *ptr;
327 char wl_ifname[NVRAM_MAX_PARAM_LEN];
328 int index;
330 /* Bail if we get a NULL or empty string */
332 if (!eth_ifname) return -1;
333 if (!*eth_ifname) return -1;
335 /* Look up wl name from the eth name */
336 if (osifname_to_nvifname(eth_ifname, wl_ifname, sizeof(wl_ifname)) != 0)
337 return -1;
339 snprintf(varname, sizeof(varname), "%s_ipconfig_index", wl_ifname);
341 ptr = nvram_get(varname);
343 if (ptr) {
344 /* Check ipconfig_index pointer to see if it is still pointing
345 * the correct lan config block
347 if (*ptr) {
348 int index;
349 char *ifname;
350 char buf[64];
351 index = atoi(ptr);
353 snprintf(buf, sizeof(buf), "lan%d_ifname", index);
355 ifname = nvram_get(buf);
357 if (ifname) {
358 if (!(strcmp(ifname, wl_ifname)))
359 return index;
361 nvram_unset(varname);
365 /* The index pointer may not have been configured if the
366 * user enters the variables manually. Do a brute force search
367 * of the lanXX_ifname variables
369 for (index = 0; index < MAX_NVPARSE; index++) {
370 snprintf(varname, sizeof(varname), "lan%d_ifname", index);
371 if (nvram_match(varname, wl_ifname)) {
372 /* if a match is found set up a corresponding index pointer for wlXX */
373 snprintf(varname, sizeof(varname), "%s_ipconfig_index", wl_ifname);
374 snprintf(varval, sizeof(varval), "%d", index);
375 nvram_set(varname, varval);
376 nvram_commit();
377 return index;
380 return -1;
384 * Set the ip configuration index given the eth name
385 * Updates both wlXX_ipconfig_index and lanYY_ifname.
387 * @param eth_ifname pointer to eth interface name
388 * @return 0 if successful -1 if not.
391 set_ipconfig_index(char *eth_ifname, int index)
393 char varname[255];
394 char varval[16];
395 char wl_ifname[NVRAM_MAX_PARAM_LEN];
397 /* Bail if we get a NULL or empty string */
399 if (!eth_ifname) return -1;
400 if (!*eth_ifname) return -1;
402 if (index >= MAX_NVPARSE) return -1;
404 /* Look up wl name from the eth name only if the name contains
408 if (osifname_to_nvifname(eth_ifname, wl_ifname, sizeof(wl_ifname)) != 0)
409 return -1;
411 snprintf(varname, sizeof(varname), "%s_ipconfig_index", wl_ifname);
412 snprintf(varval, sizeof(varval), "%d", index);
413 nvram_set(varname, varval);
415 snprintf(varname, sizeof(varname), "lan%d_ifname", index);
416 nvram_set(varname, wl_ifname);
418 nvram_commit();
420 return 0;
424 * Get interfaces belonging to a specific bridge.
426 * @param bridge_name pointer to bridge interface name
427 * @return list of interfaces belonging to the bridge or NULL
428 * if not found/empty
430 char *
431 get_bridged_interfaces(char *bridge_name)
433 static char interfaces[255];
434 char *ifnames = NULL;
435 char bridge[64];
437 if (!bridge_name) return NULL;
439 memset(interfaces, 0, sizeof(interfaces));
440 snprintf(bridge, sizeof(bridge), "%s_ifnames", bridge_name);
442 ifnames = nvram_get(bridge);
444 if (ifnames)
445 strncpy(interfaces, ifnames, sizeof(interfaces));
446 else
447 return NULL;
449 return interfaces;
453 #endif // 0
456 * Search a string backwards for a set of characters
457 * This is the reverse version of strspn()
459 * @param s string to search backwards
460 * @param accept set of chars for which to search
461 * @return number of characters in the trailing segment of s
462 * which consist only of characters from accept.
464 static size_t
465 sh_strrspn(const char *s, const char *accept)
467 const char *p;
468 size_t accept_len = strlen(accept);
469 int i;
472 if (s[0] == '\0')
473 return 0;
475 p = s + strlen(s);
476 i = 0;
478 do {
479 p--;
480 if (memchr(accept, *p, accept_len) == NULL)
481 break;
482 i++;
483 } while (p != s);
485 return i;
489 * Parse the unit and subunit from an interface string such as wlXX or wlXX.YY
491 * @param ifname interface string to parse
492 * @param unit pointer to return the unit number, may pass NULL
493 * @param subunit pointer to return the subunit number, may pass NULL
494 * @return Returns 0 if the string ends with digits or digits.digits, -1 otherwise.
495 * If ifname ends in digits.digits, then unit and subuint are set
496 * to the first and second values respectively. If ifname ends
497 * in just digits, unit is set to the value, and subunit is set
498 * to -1. On error both unit and subunit are -1. NULL may be passed
499 * for unit and/or subuint to ignore the value.
502 get_ifname_unit(const char* ifname, int *unit, int *subunit)
504 const char digits[] = "0123456789";
505 char str[64];
506 char *p;
507 size_t ifname_len = strlen(ifname);
508 size_t len;
509 unsigned long val;
511 if (unit)
512 *unit = -1;
513 if (subunit)
514 *subunit = -1;
516 if (ifname_len + 1 > sizeof(str))
517 return -1;
519 strcpy(str, ifname);
521 /* find the trailing digit chars */
522 len = sh_strrspn(str, digits);
524 /* fail if there were no trailing digits */
525 if (len == 0)
526 return -1;
528 /* point to the beginning of the last integer and convert */
529 p = str + (ifname_len - len);
530 val = strtoul(p, NULL, 10);
532 /* if we are at the beginning of the string, or the previous
533 * character is not a '.', then we have the unit number and
534 * we are done parsing
536 if (p == str || p[-1] != '.') {
537 if (unit)
538 *unit = val;
539 return 0;
540 } else {
541 if (subunit)
542 *subunit = val;
545 /* chop off the '.NNN' and get the unit number */
546 p--;
547 p[0] = '\0';
549 /* find the trailing digit chars */
550 len = sh_strrspn(str, digits);
552 /* fail if there were no trailing digits */
553 if (len == 0)
554 return -1;
556 /* point to the beginning of the last integer and convert */
557 p = p - len;
558 val = strtoul(p, NULL, 10);
560 /* save the unit number */
561 if (unit)
562 *unit = val;
564 return 0;
567 /* In the space-separated/null-terminated list(haystack), try to
568 * locate the string "needle"
570 char *find_in_list(const char *haystack, const char *needle)
572 const char *ptr = haystack;
573 int needle_len = 0;
574 int haystack_len = 0;
575 int len = 0;
577 if (!haystack || !needle || !*haystack || !*needle)
578 return NULL;
580 needle_len = strlen(needle);
581 haystack_len = strlen(haystack);
583 while (*ptr != 0 && ptr < &haystack[haystack_len])
585 /* consume leading spaces */
586 ptr += strspn(ptr, " ");
588 /* what's the length of the next word */
589 len = strcspn(ptr, " ");
591 if ((needle_len == len) && (!strncmp(needle, ptr, len)))
592 return (char*) ptr;
594 ptr += len;
596 return NULL;
601 * remove_from_list
602 * Remove the specified word from the list.
604 * @param name word to be removed from the list
605 * @param list Space separated list to modify
606 * @param listsize Max size the list can occupy
608 * @return error code
610 int remove_from_list(const char *name, char *list, int listsize)
612 int listlen = 0;
613 int namelen = 0;
614 char *occurrence = list;
616 if (!list || !name || (listsize <= 0))
617 return EINVAL;
619 listlen = strlen(list);
620 namelen = strlen(name);
622 occurrence = find_in_list(occurrence, name);
624 if (!occurrence)
625 return EINVAL;
627 /* last item in list? */
628 if (occurrence[namelen] == 0)
630 /* only item in list? */
631 if (occurrence != list)
632 occurrence--;
633 occurrence[0] = 0;
635 else if (occurrence[namelen] == ' ')
637 strncpy(occurrence, &occurrence[namelen+1 /* space */],
638 strlen(&occurrence[namelen+1 /* space */]) +1 /* terminate */);
641 return 0;
645 * add_to_list
646 * Add the specified interface(string) to the list as long as
647 * it will fit in the space left in the list.
649 * NOTE: If item is already in list, it won't be added again.
651 * @param name Name of interface to be added to the list
652 * @param list List to modify
653 * @param listsize Max size the list can occupy
655 * @return error code
657 int add_to_list(const char *name, char *list, int listsize)
659 int listlen = 0;
660 int namelen = 0;
662 if (!list || !name || (listsize <= 0))
663 return EINVAL;
665 listlen = strlen(list);
666 namelen = strlen(name);
668 /* is the item already in the list? */
669 if (find_in_list(list, name))
670 return 0;
672 if (listsize <= listlen + namelen + 1 /* space */ + 1 /* NULL */)
673 return EMSGSIZE;
675 /* add a space if the list isn't empty and it doesn't already have space */
676 if (list[0] != 0 && list[listlen-1] != ' ')
678 list[listlen++] = 0x20;
681 strncpy(&list[listlen], name, namelen + 1 /* terminate */);
683 return 0;
686 /* Utility function to remove duplicate entries in a space separated list */
688 char *remove_dups(char *inlist, int inlist_size)
690 char name[256], *next = NULL;
691 char *outlist;
693 if (!inlist_size) return NULL;
694 if (!inlist) return NULL;
696 outlist = (char *) malloc(inlist_size);
697 if (!outlist) return NULL;
698 memset(outlist, 0, inlist_size);
700 foreach(name, inlist, next) {
701 if (!find_in_list(outlist, name)) {
702 if (strlen(outlist) == 0) {
703 snprintf(outlist, inlist_size, "%s", name);
704 } else {
705 strncat(outlist, " ", inlist_size - strlen(outlist));
706 strncat(outlist, name, inlist_size - strlen(outlist));
710 strncpy(inlist, outlist, inlist_size);
712 free(outlist);
713 return inlist;
716 char *find_smallest_in_list(char *haystack) {
717 char *ptr = haystack;
718 char *smallest = ptr;
719 int haystack_len = strlen(haystack);
720 int len = 0;
722 if (!haystack || !*haystack || !haystack_len)
723 return NULL;
725 while (*ptr != 0 && ptr < &haystack[haystack_len]) {
726 /* consume leading spaces */
727 ptr += strspn(ptr, " ");
729 /* what's the length of the next word */
730 len = strcspn(ptr, " ");
732 /* if this item/word is 'smaller', update our pointer */
733 if ((strncmp(smallest, ptr, len) > 0)) {
734 smallest = ptr;
737 ptr += len;
739 return (char*) smallest;
742 char *sort_list(char *inlist, int inlist_size) {
743 char *tmplist;
744 char tmp[IFNAMSIZ];
746 if (!inlist_size) return NULL;
747 if (!inlist) return NULL;
749 tmplist = (char *) malloc(inlist_size);
750 if (!tmplist) return NULL;
751 memset(tmplist, 0, inlist_size);
753 char *b;
754 int len;
755 while ((b = find_smallest_in_list(inlist)) != NULL) {
756 len = strcspn(b, " ");
757 snprintf(tmp, len + 1, "%s", b);
759 add_to_list(tmp, tmplist, inlist_size);
760 remove_from_list(tmp, inlist, inlist_size);
763 strncpy(inlist, tmplist, inlist_size);
765 free(tmplist);
766 return inlist;
770 return true/false if any wireless interface has URE enabled.
773 ure_any_enabled(void)
775 char *temp;
776 char nv_param[NVRAM_MAX_PARAM_LEN];
778 sprintf(nv_param, "ure_disable");
779 temp = nvram_safe_get(nv_param);
780 if (temp && (strncmp(temp, "0", 1) == 0))
781 return 1;
782 else
783 return 0;
786 #define WLMBSS_DEV_NAME "wlmbss"
787 #define WL_DEV_NAME "wl"
788 #define WDS_DEV_NAME "wds"
791 * nvifname_to_osifname()
792 * The intent here is to provide a conversion between the OS interface name
793 * and the device name that we keep in NVRAM.
794 * This should eventually be placed in a Linux specific file with other
795 * OS abstraction functions.
797 * @param nvifname pointer to ifname to be converted
798 * @param osifname_buf storage for the converted osifname
799 * @param osifname_buf_len length of storage for osifname_buf
802 nvifname_to_osifname(const char *nvifname, char *osifname_buf,
803 int osifname_buf_len)
805 char varname[NVRAM_MAX_PARAM_LEN];
806 char *ptr;
808 memset(osifname_buf, 0, osifname_buf_len);
810 /* Bail if we get a NULL or empty string */
811 if ((!nvifname) || (!*nvifname) || (!osifname_buf)) {
812 return -1;
815 if (strstr(nvifname, "eth") || strstr(nvifname, ".")) {
816 strncpy(osifname_buf, nvifname, osifname_buf_len);
817 return 0;
820 snprintf(varname, sizeof(varname), "%s_ifname", nvifname);
821 ptr = nvram_get(varname);
822 if (ptr) {
823 /* Bail if the string is empty */
824 if (!*ptr) return -1;
825 strncpy(osifname_buf, ptr, osifname_buf_len);
826 return 0;
829 return -1;
832 /* osifname_to_nvifname()
833 * Convert the OS interface name to the name we use internally(NVRAM, GUI, etc.)
834 * This is the Linux version of this function
836 * @param osifname pointer to osifname to be converted
837 * @param nvifname_buf storage for the converted ifname
838 * @param nvifname_buf_len length of storage for nvifname_buf
841 osifname_to_nvifname(const char *osifname, char *nvifname_buf,
842 int nvifname_buf_len)
844 char varname[NVRAM_MAX_PARAM_LEN];
845 int pri, sec;
847 /* Bail if we get a NULL or empty string */
849 if ((!osifname) || (!*osifname) || (!nvifname_buf))
851 return -1;
854 memset(nvifname_buf, 0, nvifname_buf_len);
856 if (strstr(osifname, "wl") || strstr(osifname, "br") ||
857 strstr(osifname, "wds")) {
858 strncpy(nvifname_buf, osifname, nvifname_buf_len);
859 return 0;
862 /* look for interface name on the primary interfaces first */
863 for (pri = 0; pri < MAX_NVPARSE; pri++) {
864 snprintf(varname, sizeof(varname),
865 "wl%d_ifname", pri);
866 if (nvram_match(varname, (char *)osifname)) {
867 snprintf(nvifname_buf, nvifname_buf_len, "wl%d", pri);
868 return 0;
872 /* look for interface name on the multi-instance interfaces */
873 for (pri = 0; pri < MAX_NVPARSE; pri++)
874 for (sec = 0; sec < MAX_NVPARSE; sec++) {
875 snprintf(varname, sizeof(varname),
876 "wl%d.%d_ifname", pri, sec);
877 if (nvram_match(varname, (char *)osifname)) {
878 snprintf(nvifname_buf, nvifname_buf_len, "wl%d.%d", pri, sec);
879 return 0;
883 return -1;
886 #endif // #if WL_BSS_INFO_VERSION >= 108
892 // -----------------------------------------------------------------------------
897 #if 0
899 * Reads file and returns contents
900 * @param fd file descriptor
901 * @return contents of file or NULL if an error occurred
903 char *fd2str(int fd)
905 char *buf = NULL;
906 size_t count = 0, n;
908 do {
909 buf = realloc(buf, count + 512);
910 n = read(fd, buf + count, 512);
911 if (n < 0) {
912 free(buf);
913 buf = NULL;
915 count += n;
916 } while (n == 512);
918 close(fd);
919 if (buf)
920 buf[count] = '\0';
921 return buf;
925 * Reads file and returns contents
926 * @param path path to file
927 * @return contents of file or NULL if an error occurred
929 char *file2str(const char *path)
931 int fd;
933 if ((fd = open(path, O_RDONLY)) == -1) {
934 perror(path);
935 return NULL;
938 return fd2str(fd);
942 * Waits for a file descriptor to change status or unblocked signal
943 * @param fd file descriptor
944 * @param timeout seconds to wait before timing out or 0 for no timeout
945 * @return 1 if descriptor changed status or 0 if timed out or -1 on error
948 int waitfor(int fd, int timeout)
950 fd_set rfds;
951 struct timeval tv = { timeout, 0 };
953 FD_ZERO(&rfds);
954 FD_SET(fd, &rfds);
955 return select(fd + 1, &rfds, NULL, NULL, (timeout > 0) ? &tv : NULL);
959 * Kills process whose PID is stored in plaintext in pidfile
960 * @param pidfile PID file
961 * @return 0 on success and errno on failure
963 int kill_pidfile(char *pidfile)
965 FILE *fp;
966 char buf[256];
968 if ((fp = fopen(pidfile, "r")) != NULL) {
969 if (fgets(buf, sizeof(buf), fp)) {
970 pid_t pid = strtoul(buf, NULL, 0);
971 fclose(fp);
972 return kill(pid, SIGTERM);
974 fclose(fp);
976 return errno;
978 #endif // 0