Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / vsftpd / sysutil.c
blob1162f0b9fc4c397c2d8ba0780591d3a4bdff3240
1 /*
2 * Part of Very Secure FTPd
3 * Licence: GPL v2
4 * Author: Chris Evans
5 *
6 * sysutil.c
8 * Routines to make the libc/syscall API more pleasant to use. Long term,
9 * more libc/syscalls will go in here to reduce the number of .c files with
10 * dependencies on libc or syscalls.
13 #define PRIVATE_HANDS_OFF_syscall_retval syscall_retval
14 #define PRIVATE_HANDS_OFF_exit_status exit_status
15 #include "sysutil.h"
16 #include "utility.h"
17 #include "tunables.h"
18 #include "sysdeputil.h"
20 /* Activate 64-bit file support on Linux/32bit plus others */
21 #define _FILE_OFFSET_BITS 64
22 #define _LARGEFILE_SOURCE 1
23 #define _LARGEFILE64_SOURCE 1
24 #define _LARGE_FILES 1
26 /* For Linux, this adds nothing :-) */
27 #include "port/porting_junk.h"
29 #include <signal.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/mman.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <netinet/in.h>
39 #include <stdio.h>
40 #include <dirent.h>
41 #include <time.h>
42 #include <arpa/inet.h>
43 #include <errno.h>
44 #include <pwd.h>
45 #include <grp.h>
46 #include <ctype.h>
47 #include <sys/wait.h>
48 #include <sys/time.h>
49 /* Must be before netinet/ip.h. Found on FreeBSD, Solaris */
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #include <netinet/tcp.h>
53 #include <limits.h>
54 #include <syslog.h>
55 #include <utime.h>
56 #include <netdb.h>
57 #include <sys/resource.h>
59 /* Private variables to this file */
60 /* Current umask() */
61 static unsigned int s_current_umask;
62 /* Cached time */
63 static struct timeval s_current_time;
64 /* Current pid */
65 static int s_current_pid = -1;
66 /* Exit function */
67 static exitfunc_t s_exit_func;
68 /* Difference in timezone from GMT in seconds */
69 static long s_timezone;
71 /* Our internal signal handling implementation details */
72 static struct vsf_sysutil_sig_details
74 vsf_sighandle_t sync_sig_handler;
75 void* p_private;
76 volatile sig_atomic_t pending;
77 int running;
78 int use_alarm;
79 } s_sig_details[NSIG];
81 static vsf_context_io_t s_io_handler;
82 static void* s_p_io_handler_private;
83 static int s_io_handler_running;
85 struct vsf_sysutil_sockaddr
87 union
89 struct sockaddr u_sockaddr;
90 struct sockaddr_in u_sockaddr_in;
91 struct sockaddr_in6 u_sockaddr_in6;
92 } u;
95 /* File locals */
96 static void vsf_sysutil_common_sighandler(int signum);
97 static void vsf_sysutil_alrm_sighandler(int signum);
98 static int vsf_sysutil_translate_sig(const enum EVSFSysUtilSignal sig);
99 static void vsf_sysutil_set_sighandler(int sig, void (*p_handlefunc)(int));
100 static int vsf_sysutil_translate_memprot(
101 const enum EVSFSysUtilMapPermission perm);
102 static int vsf_sysutil_translate_openmode(
103 const enum EVSFSysUtilOpenMode mode);
104 static void vsf_sysutil_alloc_statbuf(struct vsf_sysutil_statbuf** p_ptr);
105 void vsf_sysutil_sockaddr_alloc(struct vsf_sysutil_sockaddr** p_sockptr);
106 static int lock_internal(int fd, int lock_type);
108 static void
109 vsf_sysutil_alrm_sighandler(int signum)
111 (void) signum;
112 alarm(1);
115 static void
116 vsf_sysutil_common_sighandler(int signum)
118 if (signum < 0 || signum >= NSIG)
120 /* "cannot happen" */
121 return;
123 if (s_sig_details[signum].sync_sig_handler)
125 s_sig_details[signum].pending = 1;
126 /* Since this synchronous signal framework has a small race (signal coming
127 * in just before we start a blocking call), there's the option to fire an
128 * alarm repeatedly until the signal is handled.
130 if (s_sig_details[signum].use_alarm)
132 alarm(1);
137 /* Notes. This signal check is evaluated after potentially blocking system
138 * calls, i.e. at highly defined points in the code. Since we only interrupt
139 * at these definite locations, the signal handlers can be non-trivial
140 * without us having to worry about re-entrancy.
142 * We guarantee that a handler for a given signal is not re-entrant. This
143 * is taken care of by the "running" flag.
145 * This call itself can only be re-entered once we dereference the actual
146 * hander function pointer, so we are safe with respect to races modifying
147 * the "running" flag.
149 void
150 vsf_sysutil_check_pending_actions(
151 const enum EVSFSysUtilInterruptContext context, int retval, int fd)
153 unsigned int i;
154 /* Check the i/o handler before the signal handlers */
155 if (s_io_handler && !s_io_handler_running && context == kVSFSysUtilIO)
157 s_io_handler_running = 1;
158 (*s_io_handler)(retval, fd, s_p_io_handler_private);
159 s_io_handler_running = 0;
161 for (i=0; i < NSIG; ++i)
163 if (s_sig_details[i].pending && !s_sig_details[i].running)
165 s_sig_details[i].running = 1;
166 if (s_sig_details[i].use_alarm)
168 alarm(0);
170 if (s_sig_details[i].sync_sig_handler)
172 s_sig_details[i].pending = 0;
173 (*(s_sig_details[i].sync_sig_handler))(s_sig_details[i].p_private);
175 s_sig_details[i].running = 0;
180 static int
181 vsf_sysutil_translate_sig(const enum EVSFSysUtilSignal sig)
183 int realsig = 0;
184 switch (sig)
186 case kVSFSysUtilSigALRM:
187 realsig = SIGALRM;
188 break;
189 case kVSFSysUtilSigTERM:
190 realsig = SIGTERM;
191 break;
192 case kVSFSysUtilSigCHLD:
193 realsig = SIGCHLD;
194 break;
195 case kVSFSysUtilSigPIPE:
196 realsig = SIGPIPE;
197 break;
198 case kVSFSysUtilSigURG:
199 realsig = SIGURG;
200 break;
201 case kVSFSysUtilSigHUP:
202 realsig = SIGHUP;
203 break;
204 default:
205 bug("unknown signal in vsf_sysutil_translate_sig");
206 break;
208 if (realsig < 0 || realsig >= NSIG)
210 bug("signal out of range in vsf_sysutil_translate_sig");
212 return realsig;
215 void
216 vsf_sysutil_install_sighandler(const enum EVSFSysUtilSignal sig,
217 vsf_sighandle_t handler,
218 void* p_private,
219 int use_alarm)
221 int realsig = vsf_sysutil_translate_sig(sig);
222 s_sig_details[realsig].p_private = p_private;
223 s_sig_details[realsig].sync_sig_handler = handler;
224 s_sig_details[realsig].use_alarm = use_alarm;
225 vsf_sysutil_set_sighandler(realsig, vsf_sysutil_common_sighandler);
226 if (use_alarm && realsig != SIGALRM)
228 vsf_sysutil_set_sighandler(SIGALRM, vsf_sysutil_alrm_sighandler);
232 void
233 vsf_sysutil_default_sig(const enum EVSFSysUtilSignal sig)
235 int realsig = vsf_sysutil_translate_sig(sig);
236 vsf_sysutil_set_sighandler(realsig, SIG_DFL);
237 s_sig_details[realsig].p_private = NULL;
238 s_sig_details[realsig].sync_sig_handler = NULL;
241 void
242 vsf_sysutil_install_null_sighandler(const enum EVSFSysUtilSignal sig)
244 int realsig = vsf_sysutil_translate_sig(sig);
245 s_sig_details[realsig].p_private = NULL;
246 s_sig_details[realsig].sync_sig_handler = NULL;
247 vsf_sysutil_set_sighandler(realsig, vsf_sysutil_common_sighandler);
250 void
251 vsf_sysutil_install_async_sighandler(const enum EVSFSysUtilSignal sig,
252 vsf_async_sighandle_t handler)
254 int realsig = vsf_sysutil_translate_sig(sig);
255 s_sig_details[realsig].p_private = NULL;
256 s_sig_details[realsig].sync_sig_handler = NULL;
257 vsf_sysutil_block_sig(sig);
258 vsf_sysutil_set_sighandler(realsig, handler);
261 static void
262 vsf_sysutil_set_sighandler(int sig, void (*p_handlefunc)(int))
264 int retval;
265 struct sigaction sigact;
266 vsf_sysutil_memclr(&sigact, sizeof(sigact));
267 sigact.sa_handler = p_handlefunc;
268 retval = sigfillset(&sigact.sa_mask);
269 if (retval != 0)
271 die("sigfillset");
273 retval = sigaction(sig, &sigact, NULL);
274 if (retval != 0)
276 die("sigaction");
280 void
281 vsf_sysutil_block_sig(const enum EVSFSysUtilSignal sig)
283 sigset_t sset;
284 int retval;
285 int realsig = vsf_sysutil_translate_sig(sig);
286 retval = sigemptyset(&sset);
287 if (retval != 0)
289 die("sigemptyset");
291 retval = sigaddset(&sset, realsig);
292 if (retval != 0)
294 die("sigaddset");
296 retval = sigprocmask(SIG_BLOCK, &sset, NULL);
297 if (retval != 0)
299 die("sigprocmask");
303 void
304 vsf_sysutil_unblock_sig(const enum EVSFSysUtilSignal sig)
306 sigset_t sset;
307 int retval;
308 int realsig = vsf_sysutil_translate_sig(sig);
309 retval = sigemptyset(&sset);
310 if (retval != 0)
312 die("sigemptyset");
314 retval = sigaddset(&sset, realsig);
315 if (retval != 0)
317 die("sigaddset");
319 retval = sigprocmask(SIG_UNBLOCK, &sset, NULL);
320 if (retval != 0)
322 die("sigprocmask");
325 void
326 vsf_sysutil_install_io_handler(vsf_context_io_t handler, void* p_private)
328 if (s_io_handler != NULL)
330 bug("double register of i/o handler");
332 s_io_handler = handler;
333 s_p_io_handler_private = p_private;
336 void
337 vsf_sysutil_uninstall_io_handler(void)
339 if (s_io_handler == NULL)
341 bug("no i/o handler to unregister!");
343 s_io_handler = NULL;
344 s_p_io_handler_private = NULL;
347 void
348 vsf_sysutil_set_alarm(const unsigned int trigger_seconds)
350 (void) alarm(trigger_seconds);
353 void
354 vsf_sysutil_clear_alarm(void)
356 vsf_sysutil_set_alarm(0);
360 vsf_sysutil_read(const int fd, void* p_buf, const unsigned int size)
362 while (1)
364 int retval = read(fd, p_buf, size);
365 int saved_errno = errno;
366 vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, fd);
367 if (retval < 0 && saved_errno == EINTR)
369 continue;
371 return retval;
376 vsf_sysutil_write(const int fd, const void* p_buf, const unsigned int size)
378 while (1)
380 int retval = write(fd, p_buf, size);
381 int saved_errno = errno;
382 vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, fd);
383 if (retval < 0 && saved_errno == EINTR)
385 continue;
387 return retval;
392 vsf_sysutil_read_loop(const int fd, void* p_buf, unsigned int size)
394 int retval;
395 int num_read = 0;
396 if (size > INT_MAX)
398 die("size too big in vsf_sysutil_read_loop");
400 while (1)
402 retval = vsf_sysutil_read(fd, (char*)p_buf + num_read, size);
403 if (retval < 0)
405 return retval;
407 else if (retval == 0)
409 /* Read all we're going to read.. */
410 return num_read;
412 if ((unsigned int) retval > size)
414 die("retval too big in vsf_sysutil_read_loop");
416 num_read += retval;
417 size -= (unsigned int) retval;
418 if (size == 0)
420 /* Hit the read target, cool. */
421 return num_read;
427 vsf_sysutil_write_loop(const int fd, const void* p_buf, unsigned int size)
429 int retval;
430 int num_written = 0;
431 if (size > INT_MAX)
433 die("size too big in vsf_sysutil_write_loop");
435 while (1)
437 retval = vsf_sysutil_write(fd, (const char*)p_buf + num_written, size);
438 if (retval < 0)
440 /* Error */
441 return retval;
443 else if (retval == 0)
445 /* Written all we're going to write.. */
446 return num_written;
448 if ((unsigned int) retval > size)
450 die("retval too big in vsf_sysutil_write_loop");
452 num_written += retval;
453 size -= (unsigned int) retval;
454 if (size == 0)
456 /* Hit the write target, cool. */
457 return num_written;
462 filesize_t
463 vsf_sysutil_get_file_offset(const int file_fd)
465 filesize_t retval = lseek(file_fd, 0, SEEK_CUR);
466 if (retval < 0)
468 die("lseek");
470 return retval;
473 void
474 vsf_sysutil_lseek_to(const int fd, filesize_t seek_pos)
476 filesize_t retval;
477 if (seek_pos < 0)
479 die("negative seek_pos in vsf_sysutil_lseek_to");
481 retval = lseek(fd, seek_pos, SEEK_SET);
482 if (retval < 0)
484 die("lseek");
488 void
489 vsf_sysutil_lseek_end(const int fd)
491 filesize_t retval;
492 retval = lseek(fd, 0, SEEK_END);
493 if (retval < 0)
495 die("lseek");
499 void*
500 vsf_sysutil_malloc(unsigned int size)
502 void* p_ret;
503 /* Paranoia - what if we got an integer overflow/underflow? */
504 if (size == 0 || size > INT_MAX)
506 bug("zero or big size in vsf_sysutil_malloc");
508 p_ret = malloc(size);
509 if (p_ret == NULL)
511 die("malloc");
513 return p_ret;
516 void*
517 vsf_sysutil_realloc(void* p_ptr, unsigned int size)
519 void* p_ret;
520 if (size == 0 || size > INT_MAX)
522 bug("zero or big size in vsf_sysutil_realloc");
524 p_ret = realloc(p_ptr, size);
525 if (p_ret == NULL)
527 die("realloc");
529 return p_ret;
532 void
533 vsf_sysutil_free(void* p_ptr)
535 if (p_ptr == NULL)
537 bug("vsf_sysutil_free got a null pointer");
539 free(p_ptr);
542 unsigned int
543 vsf_sysutil_getpid(void)
545 if (s_current_pid == -1)
547 s_current_pid = vsf_sysutil_getpid_nocache();
549 return (unsigned int) s_current_pid;
553 vsf_sysutil_fork(void)
555 int retval = vsf_sysutil_fork_failok();
556 if (retval < 0)
558 die("fork");
560 return retval;
564 vsf_sysutil_fork_failok(void)
566 int retval;
567 retval = fork();
568 if (retval == 0)
570 vsf_sysutil_post_fork();
572 return retval;
575 void
576 vsf_sysutil_set_exit_func(exitfunc_t exitfunc)
578 s_exit_func = exitfunc;
581 void
582 vsf_sysutil_exit(int exit_code)
584 if (s_exit_func)
586 exitfunc_t curr_func = s_exit_func;
587 /* Prevent recursion */
588 s_exit_func = 0;
589 (*curr_func)();
591 _exit(exit_code);
594 struct vsf_sysutil_wait_retval
595 vsf_sysutil_wait(void)
597 struct vsf_sysutil_wait_retval retval;
598 vsf_sysutil_memclr(&retval, sizeof(retval));
599 while (1)
601 int sys_ret = wait(&retval.exit_status);
602 if (sys_ret < 0 && errno == EINTR)
604 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
605 continue;
607 retval.syscall_retval = sys_ret;
608 return retval;
613 vsf_sysutil_wait_reap_one(void)
615 int retval = waitpid(-1, NULL, WNOHANG);
616 if (retval == 0 || (retval < 0 && errno == ECHILD))
618 /* No more children */
619 return 0;
621 if (retval < 0)
623 die("waitpid");
625 /* Got one */
626 return retval;
630 vsf_sysutil_wait_get_retval(const struct vsf_sysutil_wait_retval* p_waitret)
632 return p_waitret->syscall_retval;
636 vsf_sysutil_wait_exited_normally(
637 const struct vsf_sysutil_wait_retval* p_waitret)
639 int status = ((struct vsf_sysutil_wait_retval*) p_waitret)->exit_status;
640 return WIFEXITED(status);
644 vsf_sysutil_wait_get_exitcode(const struct vsf_sysutil_wait_retval* p_waitret)
646 int status;
647 if (!vsf_sysutil_wait_exited_normally(p_waitret))
649 bug("not a normal exit in vsf_sysutil_wait_get_exitcode");
651 status = ((struct vsf_sysutil_wait_retval*) p_waitret)->exit_status;
652 return WEXITSTATUS(status);
655 void
656 vsf_sysutil_activate_keepalive(int fd)
658 int keepalive = 1;
659 int retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive,
660 sizeof(keepalive));
661 if (retval != 0)
663 die("setsockopt: keepalive");
667 void
668 vsf_sysutil_activate_reuseaddr(int fd)
670 int reuseaddr = 1;
671 int retval = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
672 sizeof(reuseaddr));
673 if (retval != 0)
675 die("setsockopt: reuseaddr");
679 void
680 vsf_sysutil_set_nodelay(int fd)
682 int nodelay = 1;
683 int retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay,
684 sizeof(nodelay));
685 if (retval != 0)
687 die("setsockopt: nodelay");
691 void
692 vsf_sysutil_activate_sigurg(int fd)
694 int retval = fcntl(fd, F_SETOWN, vsf_sysutil_getpid());
695 if (retval != 0)
697 die("fcntl");
701 void
702 vsf_sysutil_activate_oobinline(int fd)
704 int oob_inline = 1;
705 int retval = setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &oob_inline,
706 sizeof(oob_inline));
707 if (retval != 0)
709 die("setsockopt: oobinline");
713 void
714 vsf_sysutil_set_iptos_throughput(int fd)
716 int tos = IPTOS_THROUGHPUT;
717 /* Ignore failure to set (maybe this IP stack demands privilege for this) */
718 (void) setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
721 void
722 vsf_sysutil_activate_linger(int fd)
724 int retval;
725 struct linger the_linger;
726 vsf_sysutil_memclr(&the_linger, sizeof(the_linger));
727 the_linger.l_onoff = 1;
728 the_linger.l_linger = 32767;
729 retval = setsockopt(fd, SOL_SOCKET, SO_LINGER, &the_linger,
730 sizeof(the_linger));
731 if (retval != 0)
733 die("setsockopt: linger");
737 void
738 vsf_sysutil_deactivate_linger_failok(int fd)
740 struct linger the_linger;
741 the_linger.l_onoff = 0;
742 the_linger.l_linger = 0;
743 (void) setsockopt(fd, SOL_SOCKET, SO_LINGER, &the_linger, sizeof(the_linger));
746 void
747 vsf_sysutil_activate_noblock(int fd)
749 int retval;
750 int curr_flags = fcntl(fd, F_GETFL);
751 if (vsf_sysutil_retval_is_error(curr_flags))
753 die("fcntl");
755 curr_flags |= O_NONBLOCK;
756 retval = fcntl(fd, F_SETFL, curr_flags);
757 if (retval != 0)
759 die("fcntl");
763 void
764 vsf_sysutil_deactivate_noblock(int fd)
766 int retval;
767 int curr_flags = fcntl(fd, F_GETFL);
768 if (vsf_sysutil_retval_is_error(curr_flags))
770 die("fcntl");
772 curr_flags &= ~O_NONBLOCK;
773 retval = fcntl(fd, F_SETFL, curr_flags);
774 if (retval != 0)
776 die("fcntl");
781 vsf_sysutil_recv_peek(const int fd, void* p_buf, unsigned int len)
783 while (1)
785 int retval = recv(fd, p_buf, len, MSG_PEEK);
786 int saved_errno = errno;
787 vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, fd);
788 if (retval < 0 && saved_errno == EINTR)
790 continue;
792 return retval;
797 vsf_sysutil_atoi(const char* p_str)
799 return atoi(p_str);
802 filesize_t
803 vsf_sysutil_a_to_filesize_t(const char* p_str)
805 /* atoll() is C99 standard - but even modern FreeBSD, OpenBSD don't have
806 * it, so we'll supply our own
808 filesize_t result = 0;
809 filesize_t mult = 1;
810 unsigned int len = vsf_sysutil_strlen(p_str);
811 unsigned int i;
812 /* Bail if the number is excessively big (petabytes!) */
813 if (len > 15)
815 return 0;
817 for (i=0; i<len; ++i)
819 char the_char = p_str[len-(i+1)];
820 filesize_t val;
821 if (the_char < '0' || the_char > '9')
823 return 0;
825 val = the_char - '0';
826 val *= mult;
827 result += val;
828 mult *= 10;
830 return result;
833 const char*
834 vsf_sysutil_ulong_to_str(unsigned long the_ulong)
836 static char ulong_buf[32];
837 (void) snprintf(ulong_buf, sizeof(ulong_buf), "%lu", the_ulong);
838 return ulong_buf;
841 const char*
842 vsf_sysutil_filesize_t_to_str(filesize_t the_filesize)
844 static char filesize_buf[32];
845 if (sizeof(long) == 8)
847 /* Avoid using non-standard %ll if we can */
848 (void) snprintf(filesize_buf, sizeof(filesize_buf), "%ld",
849 (long) the_filesize);
851 else
853 (void) snprintf(filesize_buf, sizeof(filesize_buf), "%lld", the_filesize);
855 return filesize_buf;
858 const char*
859 vsf_sysutil_double_to_str(double the_double)
861 static char double_buf[32];
862 (void) snprintf(double_buf, sizeof(double_buf), "%.2f", the_double);
863 return double_buf;
866 const char*
867 vsf_sysutil_uint_to_octal(unsigned int the_uint)
869 static char octal_buf[32];
870 if (the_uint == 0)
872 octal_buf[0] = '0';
873 octal_buf[1] = '\0';
875 else
877 (void) snprintf(octal_buf, sizeof(octal_buf), "0%o", the_uint);
879 return octal_buf;
882 unsigned int
883 vsf_sysutil_octal_to_uint(const char* p_str)
885 /* NOTE - avoiding using sscanf() parser */
886 unsigned int result = 0;
887 int seen_non_zero_digit = 0;
888 while (*p_str != '\0')
890 int digit = *p_str;
891 if (!isdigit(digit) || digit > '7')
893 break;
895 if (digit != '0')
897 seen_non_zero_digit = 1;
899 if (seen_non_zero_digit)
901 result <<= 3;
902 result += (digit - '0');
904 p_str++;
906 return result;
910 vsf_sysutil_toupper(int the_char)
912 return toupper(the_char);
916 vsf_sysutil_isspace(int the_char)
918 return isspace(the_char);
922 vsf_sysutil_isprint(int the_char)
924 /* From Solar - we know better than some libc's! Don't let any potential
925 * control chars through
927 unsigned char uc = (unsigned char) the_char;
928 if (uc <= 31)
930 return 0;
932 if (uc == 177)
934 return 0;
936 if (uc >= 128 && uc <= 159)
938 return 0;
940 return isprint(the_char);
944 vsf_sysutil_isalnum(int the_char)
946 return isalnum(the_char);
950 vsf_sysutil_isdigit(int the_char)
952 return isdigit(the_char);
955 char*
956 vsf_sysutil_getcwd(char* p_dest, const unsigned int buf_size)
958 char* p_retval;
959 if (buf_size == 0) {
960 return p_dest;
962 p_retval = getcwd(p_dest, buf_size);
963 p_dest[buf_size - 1] = '\0';
964 return p_retval;
968 vsf_sysutil_mkdir(const char* p_dirname, const unsigned int mode)
970 return mkdir(p_dirname, mode);
974 vsf_sysutil_rmdir(const char* p_dirname)
976 return rmdir(p_dirname);
980 vsf_sysutil_chdir(const char* p_dirname)
982 return chdir(p_dirname);
986 vsf_sysutil_rename(const char* p_from, const char* p_to)
988 return rename(p_from, p_to);
991 struct vsf_sysutil_dir*
992 vsf_sysutil_opendir(const char* p_dirname)
994 return (struct vsf_sysutil_dir*) opendir(p_dirname);
997 void
998 vsf_sysutil_closedir(struct vsf_sysutil_dir* p_dir)
1000 DIR* p_real_dir = (DIR*) p_dir;
1001 int retval = closedir(p_real_dir);
1002 if (retval != 0)
1004 die("closedir");
1008 const char*
1009 vsf_sysutil_next_dirent(struct vsf_sysutil_dir* p_dir)
1011 DIR* p_real_dir = (DIR*) p_dir;
1012 struct dirent* p_dirent = readdir(p_real_dir);
1013 if (p_dirent == NULL)
1015 return NULL;
1017 return p_dirent->d_name;
1020 unsigned int
1021 vsf_sysutil_strlen(const char* p_text)
1023 unsigned int ret = strlen(p_text);
1024 /* A defense in depth measure. */
1025 if (ret > INT_MAX / 8)
1027 die("string suspiciously long");
1029 return ret;
1032 char*
1033 vsf_sysutil_strdup(const char* p_str)
1035 return strdup(p_str);
1038 void
1039 vsf_sysutil_memclr(void* p_dest, unsigned int size)
1041 /* Safety */
1042 if (size == 0)
1044 return;
1046 memset(p_dest, '\0', size);
1049 void
1050 vsf_sysutil_memcpy(void* p_dest, const void* p_src, const unsigned int size)
1052 /* Safety */
1053 if (size == 0)
1055 return;
1057 /* Defense in depth */
1058 if (size > INT_MAX)
1060 die("possible negative value to memcpy?");
1062 memcpy(p_dest, p_src, size);
1065 void
1066 vsf_sysutil_strcpy(char* p_dest, const char* p_src, unsigned int maxsize)
1068 if (maxsize == 0)
1070 return;
1072 strncpy(p_dest, p_src, maxsize);
1073 p_dest[maxsize - 1] = '\0';
1077 vsf_sysutil_memcmp(const void* p_src1, const void* p_src2, unsigned int size)
1079 /* Safety */
1080 if (size == 0)
1082 return 0;
1084 return memcmp(p_src1, p_src2, size);
1088 vsf_sysutil_strcmp(const char* p_src1, const char* p_src2)
1090 return strcmp(p_src1, p_src2);
1093 unsigned int
1094 vsf_sysutil_getpagesize(void)
1096 static unsigned int s_page_size;
1097 if (s_page_size == 0)
1099 s_page_size = getpagesize();
1100 if (s_page_size == 0)
1102 die("getpagesize");
1105 return s_page_size;
1108 static int
1109 vsf_sysutil_translate_memprot(const enum EVSFSysUtilMapPermission perm)
1111 int retval = 0;
1112 switch (perm)
1114 case kVSFSysUtilMapProtReadOnly:
1115 retval = PROT_READ;
1116 break;
1117 case kVSFSysUtilMapProtNone:
1118 retval = PROT_NONE;
1119 break;
1120 default:
1121 bug("bad value in vsf_sysutil_translate_memprot");
1122 break;
1124 return retval;
1127 void
1128 vsf_sysutil_memprotect(void* p_addr, unsigned int len,
1129 const enum EVSFSysUtilMapPermission perm)
1131 int prot = vsf_sysutil_translate_memprot(perm);
1132 int retval = mprotect(p_addr, len, prot);
1133 if (retval != 0)
1135 die("mprotect");
1139 void
1140 vsf_sysutil_memunmap(void* p_start, unsigned int length)
1142 int retval = munmap(p_start, length);
1143 if (retval != 0)
1145 die("munmap");
1149 static int
1150 vsf_sysutil_translate_openmode(const enum EVSFSysUtilOpenMode mode)
1152 int retval = 0;
1153 switch (mode)
1155 case kVSFSysUtilOpenReadOnly:
1156 retval = O_RDONLY;
1157 break;
1158 case kVSFSysUtilOpenWriteOnly:
1159 retval = O_WRONLY;
1160 break;
1161 case kVSFSysUtilOpenReadWrite:
1162 retval = O_RDWR;
1163 break;
1164 default:
1165 bug("bad mode in vsf_sysutil_translate_openmode");
1166 break;
1168 return retval;
1172 vsf_sysutil_open_file(const char* p_filename,
1173 const enum EVSFSysUtilOpenMode mode)
1175 return open(p_filename, vsf_sysutil_translate_openmode(mode) | O_NONBLOCK);
1179 vsf_sysutil_create_file_exclusive(const char* p_filename)
1181 /* umask() also contributes to end mode */
1182 return open(p_filename, O_CREAT | O_EXCL | O_WRONLY | O_APPEND,
1183 tunable_file_open_mode);
1187 vsf_sysutil_create_or_open_file(const char* p_filename, unsigned int mode)
1189 return open(p_filename, O_CREAT | O_WRONLY | O_NONBLOCK, mode);
1193 vsf_sysutil_create_or_open_file_append(const char* p_filename,
1194 unsigned int mode)
1196 return open(p_filename, O_CREAT | O_WRONLY | O_NONBLOCK | O_APPEND, mode);
1199 void
1200 vsf_sysutil_dupfd2(int old_fd, int new_fd)
1202 int retval;
1203 if (old_fd == new_fd)
1205 return;
1207 retval = dup2(old_fd, new_fd);
1208 if (retval != new_fd)
1210 die("dup2");
1214 void
1215 vsf_sysutil_close(int fd)
1217 while (1)
1219 int retval = close(fd);
1220 if (retval != 0)
1222 if (errno == EINTR)
1224 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
1225 continue;
1227 die("close");
1229 return;
1234 vsf_sysutil_close_failok(int fd)
1236 return close(fd);
1240 vsf_sysutil_unlink(const char* p_dead)
1242 return unlink(p_dead);
1246 vsf_sysutil_write_access(const char* p_filename)
1248 int retval = access(p_filename, W_OK);
1249 return (retval == 0);
1252 static void
1253 vsf_sysutil_alloc_statbuf(struct vsf_sysutil_statbuf** p_ptr)
1255 if (*p_ptr == NULL)
1257 *p_ptr = vsf_sysutil_malloc(sizeof(struct stat));
1261 void
1262 vsf_sysutil_fstat(int fd, struct vsf_sysutil_statbuf** p_ptr)
1264 int retval;
1265 vsf_sysutil_alloc_statbuf(p_ptr);
1266 retval = fstat(fd, (struct stat*) (*p_ptr));
1267 if (retval != 0)
1269 die("fstat");
1274 vsf_sysutil_stat(const char* p_name, struct vsf_sysutil_statbuf** p_ptr)
1276 vsf_sysutil_alloc_statbuf(p_ptr);
1277 return stat(p_name, (struct stat*) (*p_ptr));
1281 vsf_sysutil_lstat(const char* p_name, struct vsf_sysutil_statbuf** p_ptr)
1283 vsf_sysutil_alloc_statbuf(p_ptr);
1284 return lstat(p_name, (struct stat*) (*p_ptr));
1287 void
1288 vsf_sysutil_dir_stat(const struct vsf_sysutil_dir* p_dir,
1289 struct vsf_sysutil_statbuf** p_ptr)
1291 int fd = dirfd((DIR*) p_dir);
1292 vsf_sysutil_fstat(fd, p_ptr);
1296 vsf_sysutil_statbuf_is_regfile(const struct vsf_sysutil_statbuf* p_stat)
1298 const struct stat* p_realstat = (const struct stat*) p_stat;
1299 return S_ISREG(p_realstat->st_mode);
1303 vsf_sysutil_statbuf_is_symlink(const struct vsf_sysutil_statbuf* p_stat)
1305 const struct stat* p_realstat = (const struct stat*) p_stat;
1306 return S_ISLNK(p_realstat->st_mode);
1310 vsf_sysutil_statbuf_is_socket(const struct vsf_sysutil_statbuf* p_stat)
1312 const struct stat* p_realstat = (const struct stat*) p_stat;
1313 return S_ISSOCK(p_realstat->st_mode);
1317 vsf_sysutil_statbuf_is_dir(const struct vsf_sysutil_statbuf* p_stat)
1319 const struct stat* p_realstat = (const struct stat*) p_stat;
1320 return S_ISDIR(p_realstat->st_mode);
1323 const char*
1324 vsf_sysutil_statbuf_get_perms(const struct vsf_sysutil_statbuf* p_statbuf)
1326 static char perms[11];
1327 int i;
1328 const struct stat* p_stat = (const struct stat*) p_statbuf;
1329 for (i=0; i<10; i++)
1331 perms[i] = '-';
1333 perms[0] = '?';
1334 switch (p_stat->st_mode & S_IFMT)
1336 case S_IFREG: perms[0] = '-'; break;
1337 case S_IFDIR: perms[0] = 'd'; break;
1338 case S_IFLNK: perms[0] = 'l'; break;
1339 case S_IFIFO: perms[0] = 'p'; break;
1340 case S_IFSOCK: perms[0] = 's'; break;
1341 case S_IFCHR: perms[0] = 'c'; break;
1342 case S_IFBLK: perms[0] = 'b'; break;
1344 if (p_stat->st_mode & S_IRUSR) perms[1] = 'r';
1345 if (p_stat->st_mode & S_IWUSR) perms[2] = 'w';
1346 if (p_stat->st_mode & S_IXUSR) perms[3] = 'x';
1347 if (p_stat->st_mode & S_IRGRP) perms[4] = 'r';
1348 if (p_stat->st_mode & S_IWGRP) perms[5] = 'w';
1349 if (p_stat->st_mode & S_IXGRP) perms[6] = 'x';
1350 if (p_stat->st_mode & S_IROTH) perms[7] = 'r';
1351 if (p_stat->st_mode & S_IWOTH) perms[8] = 'w';
1352 if (p_stat->st_mode & S_IXOTH) perms[9] = 'x';
1353 if (p_stat->st_mode & S_ISUID) perms[3] = (perms[3] == 'x') ? 's' : 'S';
1354 if (p_stat->st_mode & S_ISGID) perms[6] = (perms[6] == 'x') ? 's' : 'S';
1355 if (p_stat->st_mode & S_ISVTX) perms[9] = (perms[9] == 'x') ? 't' : 'T';
1356 perms[10] = '\0';
1357 return perms;
1360 const char*
1361 vsf_sysutil_statbuf_get_date(const struct vsf_sysutil_statbuf* p_statbuf,
1362 int use_localtime, long curr_time)
1364 static char datebuf[64];
1365 int retval;
1366 struct tm* p_tm;
1367 const struct stat* p_stat = (const struct stat*) p_statbuf;
1368 const char* p_date_format = "%b %d %H:%M";
1369 if (!use_localtime)
1371 p_tm = gmtime(&p_stat->st_mtime);
1373 else
1375 p_tm = localtime(&p_stat->st_mtime);
1377 /* Is this a future or 6 months old date? If so, we drop to year format */
1378 if (p_stat->st_mtime > curr_time ||
1379 (curr_time - p_stat->st_mtime) > 60*60*24*182)
1381 p_date_format = "%b %d %Y";
1383 retval = strftime(datebuf, sizeof(datebuf), p_date_format, p_tm);
1384 datebuf[sizeof(datebuf)-1] = '\0';
1385 if (retval == 0)
1387 die("strftime");
1389 return datebuf;
1392 const char*
1393 vsf_sysutil_statbuf_get_numeric_date(
1394 const struct vsf_sysutil_statbuf* p_statbuf,
1395 int use_localtime)
1397 static char datebuf[15];
1398 const struct stat* p_stat = (const struct stat*) p_statbuf;
1399 struct tm* p_tm;
1400 int retval;
1401 if (!use_localtime)
1403 p_tm = gmtime(&p_stat->st_mtime);
1405 else
1407 p_tm = localtime(&p_stat->st_mtime);
1409 retval = strftime(datebuf, sizeof(datebuf), "%Y%m%d%H%M%S", p_tm);
1410 if (retval == 0)
1412 die("strftime");
1414 return datebuf;
1417 filesize_t
1418 vsf_sysutil_statbuf_get_size(const struct vsf_sysutil_statbuf* p_statbuf)
1420 const struct stat* p_stat = (const struct stat*) p_statbuf;
1421 if (p_stat->st_size < 0)
1423 die("invalid inode size in vsf_sysutil_statbuf_get_size");
1425 return p_stat->st_size;
1429 vsf_sysutil_statbuf_get_uid(const struct vsf_sysutil_statbuf* p_statbuf)
1431 const struct stat* p_stat = (const struct stat*) p_statbuf;
1432 return p_stat->st_uid;
1436 vsf_sysutil_statbuf_get_gid(const struct vsf_sysutil_statbuf* p_statbuf)
1438 const struct stat* p_stat = (const struct stat*) p_statbuf;
1439 return p_stat->st_gid;
1442 unsigned int
1443 vsf_sysutil_statbuf_get_links(const struct vsf_sysutil_statbuf* p_statbuf)
1445 const struct stat* p_stat = (const struct stat*) p_statbuf;
1446 return p_stat->st_nlink;
1450 vsf_sysutil_statbuf_is_readable_other(
1451 const struct vsf_sysutil_statbuf* p_statbuf)
1453 const struct stat* p_stat = (const struct stat*) p_statbuf;
1454 if (p_stat->st_mode & S_IROTH)
1456 return 1;
1458 return 0;
1461 const char*
1462 vsf_sysutil_statbuf_get_sortkey_mtime(
1463 const struct vsf_sysutil_statbuf* p_statbuf)
1465 static char intbuf[32];
1466 const struct stat* p_stat = (const struct stat*) p_statbuf;
1467 /* This slight hack function must return a character date format such that
1468 * more recent dates appear later in the alphabet! Most notably, we must
1469 * make sure we pad to the same length with 0's
1471 snprintf(intbuf, sizeof(intbuf), "%030ld", (long) p_stat->st_mtime);
1472 return intbuf;
1475 void
1476 vsf_sysutil_fchown(const int fd, const int uid, const int gid)
1478 if (fchown(fd, uid, gid) != 0)
1480 die("fchown");
1484 void
1485 vsf_sysutil_fchmod(const int fd, unsigned int mode)
1487 mode = mode & 0777;
1488 if (fchmod(fd, mode))
1490 die("fchmod");
1495 vsf_sysutil_chmod(const char* p_filename, unsigned int mode)
1497 /* Safety: mask "mode" to just access permissions, e.g. no suid setting! */
1498 mode = mode & 0777;
1499 return chmod(p_filename, mode);
1503 vsf_sysutil_lock_file_write(int fd)
1505 return lock_internal(fd, F_WRLCK);
1509 vsf_sysutil_lock_file_read(int fd)
1511 return lock_internal(fd, F_RDLCK);
1514 static int
1515 lock_internal(int fd, int lock_type)
1517 struct flock the_lock;
1518 int retval;
1519 int saved_errno;
1520 vsf_sysutil_memclr(&the_lock, sizeof(the_lock));
1521 the_lock.l_type = lock_type;
1522 the_lock.l_whence = SEEK_SET;
1523 the_lock.l_start = 0;
1524 the_lock.l_len = 0;
1527 retval = fcntl(fd, F_SETLKW, &the_lock);
1528 saved_errno = errno;
1529 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
1531 while (retval < 0 && saved_errno == EINTR);
1532 return retval;
1535 void
1536 vsf_sysutil_unlock_file(int fd)
1538 int retval;
1539 struct flock the_lock;
1540 vsf_sysutil_memclr(&the_lock, sizeof(the_lock));
1541 the_lock.l_type = F_UNLCK;
1542 the_lock.l_whence = SEEK_SET;
1543 the_lock.l_start = 0;
1544 the_lock.l_len = 0;
1545 retval = fcntl(fd, F_SETLK, &the_lock);
1546 if (retval != 0)
1548 die("fcntl");
1553 vsf_sysutil_readlink(const char* p_filename, char* p_dest, unsigned int bufsiz)
1555 int retval;
1556 if (bufsiz == 0) {
1557 return -1;
1559 retval = readlink(p_filename, p_dest, bufsiz - 1);
1560 if (retval < 0)
1562 return retval;
1564 /* Ensure buffer is NULL terminated; readlink(2) doesn't do that */
1565 p_dest[retval] = '\0';
1566 return retval;
1570 vsf_sysutil_retval_is_error(int retval)
1572 if (retval < 0)
1574 return 1;
1576 return 0;
1579 enum EVSFSysUtilError
1580 vsf_sysutil_get_error(void)
1582 enum EVSFSysUtilError retval = kVSFSysUtilErrUnknown;
1583 switch (errno)
1585 case EADDRINUSE:
1586 retval = kVSFSysUtilErrADDRINUSE;
1587 break;
1588 case ENOSYS:
1589 retval = kVSFSysUtilErrNOSYS;
1590 break;
1591 case EINTR:
1592 retval = kVSFSysUtilErrINTR;
1593 break;
1594 case EINVAL:
1595 retval = kVSFSysUtilErrINVAL;
1596 break;
1597 case EOPNOTSUPP:
1598 retval = kVSFSysUtilErrOPNOTSUPP;
1599 break;
1600 case EACCES:
1601 retval = kVSFSysUtilErrACCES;
1602 break;
1603 case ENOENT:
1604 retval = kVSFSysUtilErrNOENT;
1605 break;
1607 return retval;
1611 vsf_sysutil_get_ipv4_sock(void)
1613 int retval = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
1614 if (retval < 0)
1616 die("socket");
1618 return retval;
1622 vsf_sysutil_get_ipv6_sock(void)
1624 int retval = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
1625 if (retval < 0)
1627 die("socket");
1629 return retval;
1632 struct vsf_sysutil_socketpair_retval
1633 vsf_sysutil_unix_stream_socketpair(void)
1635 struct vsf_sysutil_socketpair_retval retval;
1636 int the_sockets[2];
1637 int sys_retval = socketpair(PF_UNIX, SOCK_STREAM, 0, the_sockets);
1638 if (sys_retval != 0)
1640 die("socketpair");
1642 retval.socket_one = the_sockets[0];
1643 retval.socket_two = the_sockets[1];
1644 return retval;
1648 vsf_sysutil_bind(int fd, const struct vsf_sysutil_sockaddr* p_sockptr)
1650 const struct sockaddr* p_sockaddr = &p_sockptr->u.u_sockaddr;
1651 int len = 0;
1652 if (p_sockaddr->sa_family == AF_INET)
1654 len = sizeof(struct sockaddr_in);
1656 else if (p_sockaddr->sa_family == AF_INET6)
1658 len = sizeof(struct sockaddr_in6);
1660 else
1662 die("can only support ipv4 and ipv6 currently");
1664 return bind(fd, p_sockaddr, len);
1668 vsf_sysutil_listen(int fd, const unsigned int backlog)
1670 int retval = listen(fd, backlog);
1671 if (vsf_sysutil_retval_is_error(retval) &&
1672 vsf_sysutil_get_error() != kVSFSysUtilErrADDRINUSE)
1674 die("listen");
1676 return retval;
1679 /* Warning: callers of this function assume it does NOT make use of any
1680 * non re-entrant calls such as malloc().
1683 vsf_sysutil_accept_timeout(int fd, struct vsf_sysutil_sockaddr* p_sockaddr,
1684 unsigned int wait_seconds)
1686 struct vsf_sysutil_sockaddr remote_addr;
1687 int retval;
1688 int saved_errno;
1689 fd_set accept_fdset;
1690 struct timeval timeout;
1691 socklen_t socklen = sizeof(remote_addr);
1692 if (p_sockaddr)
1694 vsf_sysutil_memclr(p_sockaddr, sizeof(*p_sockaddr));
1696 if (wait_seconds > 0)
1698 FD_ZERO(&accept_fdset);
1699 FD_SET(fd, &accept_fdset);
1700 timeout.tv_sec = wait_seconds;
1701 timeout.tv_usec = 0;
1704 retval = select(fd + 1, &accept_fdset, NULL, NULL, &timeout);
1705 saved_errno = errno;
1706 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
1707 } while (retval < 0 && saved_errno == EINTR);
1708 if (retval == 0)
1710 errno = EAGAIN;
1711 return -1;
1714 retval = accept(fd, &remote_addr.u.u_sockaddr, &socklen);
1715 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
1716 if (retval < 0)
1718 return retval;
1720 /* FreeBSD bug / paranoia: ai32@drexel.edu */
1721 if (socklen == 0)
1723 return -1;
1725 if (remote_addr.u.u_sockaddr.sa_family != AF_INET &&
1726 remote_addr.u.u_sockaddr.sa_family != AF_INET6)
1728 die("can only support ipv4 and ipv6 currently");
1730 if (p_sockaddr)
1732 if (remote_addr.u.u_sockaddr.sa_family == AF_INET)
1734 vsf_sysutil_memclr(&remote_addr.u.u_sockaddr_in.sin_zero,
1735 sizeof(remote_addr.u.u_sockaddr_in.sin_zero));
1736 vsf_sysutil_memcpy(p_sockaddr, &remote_addr.u.u_sockaddr_in,
1737 sizeof(remote_addr.u.u_sockaddr_in));
1739 else
1741 vsf_sysutil_memcpy(p_sockaddr, &remote_addr.u.u_sockaddr_in6,
1742 sizeof(remote_addr.u.u_sockaddr_in6));
1745 return retval;
1749 vsf_sysutil_connect_timeout(int fd, const struct vsf_sysutil_sockaddr* p_addr,
1750 unsigned int wait_seconds)
1752 const struct sockaddr* p_sockaddr = &p_addr->u.u_sockaddr;
1753 unsigned int addrlen = 0;
1754 int retval;
1755 int saved_errno;
1756 if (p_sockaddr->sa_family == AF_INET)
1758 addrlen = sizeof(p_addr->u.u_sockaddr_in);
1760 else if (p_sockaddr->sa_family == AF_INET6)
1762 addrlen = sizeof(p_addr->u.u_sockaddr_in6);
1764 else
1766 die("can only support ipv4 and ipv6 currently");
1768 if (wait_seconds > 0)
1770 vsf_sysutil_activate_noblock(fd);
1772 retval = connect(fd, p_sockaddr, addrlen);
1773 if (retval < 0 && errno == EINPROGRESS)
1775 fd_set connect_fdset;
1776 struct timeval timeout;
1777 FD_ZERO(&connect_fdset);
1778 FD_SET(fd, &connect_fdset);
1779 timeout.tv_sec = wait_seconds;
1780 timeout.tv_usec = 0;
1783 retval = select(fd + 1, NULL, &connect_fdset, NULL, &timeout);
1784 saved_errno = errno;
1785 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
1787 while (retval < 0 && saved_errno == EINTR);
1788 if (retval == 0)
1790 retval = -1;
1791 errno = EAGAIN;
1793 else
1795 socklen_t socklen = sizeof(retval);
1796 int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &retval, &socklen);
1797 if (sockoptret != 0)
1799 die("getsockopt");
1803 if (wait_seconds > 0)
1805 vsf_sysutil_deactivate_noblock(fd);
1807 return retval;
1810 void
1811 vsf_sysutil_getsockname(int fd, struct vsf_sysutil_sockaddr** p_sockptr)
1813 struct vsf_sysutil_sockaddr the_addr;
1814 int retval;
1815 socklen_t socklen = sizeof(the_addr);
1816 vsf_sysutil_sockaddr_clear(p_sockptr);
1817 retval = getsockname(fd, &the_addr.u.u_sockaddr, &socklen);
1818 if (retval != 0)
1820 die("getsockname");
1822 if (the_addr.u.u_sockaddr.sa_family != AF_INET &&
1823 the_addr.u.u_sockaddr.sa_family != AF_INET6)
1825 die("can only support ipv4 and ipv6 currently");
1827 vsf_sysutil_sockaddr_alloc(p_sockptr);
1828 if (socklen > sizeof(the_addr))
1830 socklen = sizeof(the_addr);
1832 vsf_sysutil_memcpy(*p_sockptr, &the_addr, socklen);
1835 void
1836 vsf_sysutil_getpeername(int fd, struct vsf_sysutil_sockaddr** p_sockptr)
1838 struct vsf_sysutil_sockaddr the_addr;
1839 int retval;
1840 socklen_t socklen = sizeof(the_addr);
1841 vsf_sysutil_sockaddr_clear(p_sockptr);
1842 retval = getpeername(fd, &the_addr.u.u_sockaddr, &socklen);
1843 if (retval != 0)
1845 die("getpeername");
1847 if (the_addr.u.u_sockaddr.sa_family != AF_INET &&
1848 the_addr.u.u_sockaddr.sa_family != AF_INET6)
1850 die("can only support ipv4 and ipv6 currently");
1852 vsf_sysutil_sockaddr_alloc(p_sockptr);
1853 if (socklen > sizeof(the_addr))
1855 socklen = sizeof(the_addr);
1857 vsf_sysutil_memcpy(*p_sockptr, &the_addr, socklen);
1860 void
1861 vsf_sysutil_shutdown_failok(int fd)
1863 /* SHUT_RDWR is a relatively new addition */
1864 #ifndef SHUT_RDWR
1865 #define SHUT_RDWR 2
1866 #endif
1867 (void) shutdown(fd, SHUT_RDWR);
1870 void
1871 vsf_sysutil_shutdown_read_failok(int fd)
1873 /* SHUT_RD is a relatively new addition */
1874 #ifndef SHUT_RD
1875 #define SHUT_RD 0
1876 #endif
1877 (void) shutdown(fd, SHUT_RD);
1880 void
1881 vsf_sysutil_sockaddr_clear(struct vsf_sysutil_sockaddr** p_sockptr)
1883 if (*p_sockptr != NULL)
1885 vsf_sysutil_free(*p_sockptr);
1886 *p_sockptr = NULL;
1890 void
1891 vsf_sysutil_sockaddr_alloc(struct vsf_sysutil_sockaddr** p_sockptr)
1893 vsf_sysutil_sockaddr_clear(p_sockptr);
1894 *p_sockptr = vsf_sysutil_malloc(sizeof(**p_sockptr));
1895 vsf_sysutil_memclr(*p_sockptr, sizeof(**p_sockptr));
1898 void
1899 vsf_sysutil_sockaddr_alloc_ipv4(struct vsf_sysutil_sockaddr** p_sockptr)
1901 vsf_sysutil_sockaddr_alloc(p_sockptr);
1902 (*p_sockptr)->u.u_sockaddr.sa_family = AF_INET;
1905 void
1906 vsf_sysutil_sockaddr_alloc_ipv6(struct vsf_sysutil_sockaddr** p_sockptr)
1908 vsf_sysutil_sockaddr_alloc(p_sockptr);
1909 (*p_sockptr)->u.u_sockaddr.sa_family = AF_INET6;
1912 void
1913 vsf_sysutil_sockaddr_clone(struct vsf_sysutil_sockaddr** p_sockptr,
1914 const struct vsf_sysutil_sockaddr* p_src)
1916 struct vsf_sysutil_sockaddr* p_sockaddr = 0;
1917 vsf_sysutil_sockaddr_alloc(p_sockptr);
1918 p_sockaddr = *p_sockptr;
1919 if (p_src->u.u_sockaddr.sa_family == AF_INET)
1921 p_sockaddr->u.u_sockaddr.sa_family = AF_INET;
1922 vsf_sysutil_memcpy(&p_sockaddr->u.u_sockaddr_in.sin_addr,
1923 &p_src->u.u_sockaddr_in.sin_addr,
1924 sizeof(p_sockaddr->u.u_sockaddr_in.sin_addr));
1926 else if (p_src->u.u_sockaddr.sa_family == AF_INET6)
1928 p_sockaddr->u.u_sockaddr.sa_family = AF_INET6;
1929 vsf_sysutil_memcpy(&p_sockaddr->u.u_sockaddr_in6.sin6_addr,
1930 &p_src->u.u_sockaddr_in6.sin6_addr,
1931 sizeof(p_sockaddr->u.u_sockaddr_in6.sin6_addr));
1932 p_sockaddr->u.u_sockaddr_in6.sin6_scope_id =
1933 p_src->u.u_sockaddr_in6.sin6_scope_id;
1935 else
1937 die("can only support ipv4 and ipv6 currently");
1942 vsf_sysutil_sockaddr_addr_equal(const struct vsf_sysutil_sockaddr* p1,
1943 const struct vsf_sysutil_sockaddr* p2)
1945 int family1 = p1->u.u_sockaddr.sa_family;
1946 int family2 = p2->u.u_sockaddr.sa_family;
1947 if (family1 != family2)
1949 if (family1 == AF_INET && family2 == AF_INET6)
1951 const void* p_ipv4_addr = vsf_sysutil_sockaddr_ipv6_v4(p2);
1952 if (p_ipv4_addr &&
1953 !vsf_sysutil_memcmp(p_ipv4_addr, &p1->u.u_sockaddr_in.sin_addr,
1954 sizeof(p1->u.u_sockaddr_in.sin_addr)))
1956 return 1;
1959 else if (family1 == AF_INET6 && family2 == AF_INET)
1961 const void* p_ipv4_addr = vsf_sysutil_sockaddr_ipv6_v4(p1);
1962 if (p_ipv4_addr &&
1963 !vsf_sysutil_memcmp(p_ipv4_addr, &p2->u.u_sockaddr_in.sin_addr,
1964 sizeof(p2->u.u_sockaddr_in.sin_addr)))
1966 return 1;
1969 return 0;
1971 if (family1 == AF_INET)
1973 if (vsf_sysutil_memcmp(&p1->u.u_sockaddr_in.sin_addr,
1974 &p2->u.u_sockaddr_in.sin_addr,
1975 sizeof(p1->u.u_sockaddr_in.sin_addr)) == 0)
1977 return 1;
1980 else if (family1 == AF_INET6)
1982 if (vsf_sysutil_memcmp(&p1->u.u_sockaddr_in6.sin6_addr,
1983 &p2->u.u_sockaddr_in6.sin6_addr,
1984 sizeof(p1->u.u_sockaddr_in6.sin6_addr)) == 0)
1986 return 1;
1989 return 0;
1993 vsf_sysutil_sockaddr_is_ipv6(const struct vsf_sysutil_sockaddr* p_sockaddr)
1995 if (p_sockaddr->u.u_sockaddr.sa_family == AF_INET6)
1997 return 1;
1999 return 0;
2002 void
2003 vsf_sysutil_sockaddr_set_ipv4addr(struct vsf_sysutil_sockaddr* p_sockptr,
2004 const unsigned char* p_raw)
2006 if (p_sockptr->u.u_sockaddr.sa_family == AF_INET)
2008 vsf_sysutil_memcpy(&p_sockptr->u.u_sockaddr_in.sin_addr, p_raw,
2009 sizeof(p_sockptr->u.u_sockaddr_in.sin_addr));
2011 else if (p_sockptr->u.u_sockaddr.sa_family == AF_INET6)
2013 static struct vsf_sysutil_sockaddr* s_p_sockaddr;
2014 vsf_sysutil_sockaddr_alloc_ipv4(&s_p_sockaddr);
2015 vsf_sysutil_memcpy(&s_p_sockaddr->u.u_sockaddr_in.sin_addr, p_raw,
2016 sizeof(s_p_sockaddr->u.u_sockaddr_in.sin_addr));
2017 vsf_sysutil_memcpy(&p_sockptr->u.u_sockaddr_in6.sin6_addr,
2018 vsf_sysutil_sockaddr_ipv4_v6(s_p_sockaddr),
2019 sizeof(p_sockptr->u.u_sockaddr_in6.sin6_addr));
2021 else
2023 bug("bad family");
2027 void
2028 vsf_sysutil_sockaddr_set_ipv6addr(struct vsf_sysutil_sockaddr* p_sockptr,
2029 const unsigned char* p_raw)
2031 if (p_sockptr->u.u_sockaddr.sa_family == AF_INET6)
2033 vsf_sysutil_memcpy(&p_sockptr->u.u_sockaddr_in6.sin6_addr, p_raw,
2034 sizeof(p_sockptr->u.u_sockaddr_in6.sin6_addr));
2036 else
2038 bug("bad family");
2042 const void*
2043 vsf_sysutil_sockaddr_ipv6_v4(const struct vsf_sysutil_sockaddr* p_addr)
2045 static char pattern[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
2046 const unsigned char* p_addr_start;
2047 if (p_addr->u.u_sockaddr.sa_family != AF_INET6)
2049 return 0;
2051 if (vsf_sysutil_memcmp(pattern, &p_addr->u.u_sockaddr_in6.sin6_addr, 12))
2053 return 0;
2055 p_addr_start = (const unsigned char*)&p_addr->u.u_sockaddr_in6.sin6_addr;
2056 return &p_addr_start[12];
2059 const void*
2060 vsf_sysutil_sockaddr_ipv4_v6(const struct vsf_sysutil_sockaddr* p_addr)
2062 static char ret[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
2063 if (p_addr->u.u_sockaddr.sa_family != AF_INET)
2065 return 0;
2067 vsf_sysutil_memcpy(&ret[12], &p_addr->u.u_sockaddr_in.sin_addr, 4);
2068 return ret;
2071 void*
2072 vsf_sysutil_sockaddr_get_raw_addr(struct vsf_sysutil_sockaddr* p_sockptr)
2074 if (p_sockptr->u.u_sockaddr.sa_family == AF_INET)
2076 return &p_sockptr->u.u_sockaddr_in.sin_addr;
2078 else if (p_sockptr->u.u_sockaddr.sa_family == AF_INET6)
2080 return &p_sockptr->u.u_sockaddr_in6.sin6_addr;
2082 else
2084 bug("bad family");
2086 return 0;
2089 unsigned int
2090 vsf_sysutil_get_ipaddr_size(void)
2092 struct vsf_sysutil_sockaddr addr;
2093 unsigned int size = sizeof(addr.u.u_sockaddr_in.sin_addr);
2094 unsigned int size2 = sizeof(addr.u.u_sockaddr_in6.sin6_addr);
2095 if (size2 > size)
2097 size = size2;
2099 return size;
2103 vsf_sysutil_get_ipsock(const struct vsf_sysutil_sockaddr* p_addr)
2105 if (p_addr->u.u_sockaddr.sa_family == AF_INET)
2107 return vsf_sysutil_get_ipv4_sock();
2109 else if (p_addr->u.u_sockaddr.sa_family == AF_INET6)
2111 return vsf_sysutil_get_ipv6_sock();
2113 else
2115 bug("bad family");
2117 return -1;
2120 void
2121 vsf_sysutil_sockaddr_set_any(struct vsf_sysutil_sockaddr* p_sockaddr)
2123 if (p_sockaddr->u.u_sockaddr.sa_family == AF_INET)
2125 vsf_sysutil_memclr(&p_sockaddr->u.u_sockaddr_in.sin_addr,
2126 sizeof(p_sockaddr->u.u_sockaddr_in.sin_addr));
2128 else if (p_sockaddr->u.u_sockaddr.sa_family == AF_INET6)
2130 vsf_sysutil_memclr(&p_sockaddr->u.u_sockaddr_in6.sin6_addr,
2131 sizeof(p_sockaddr->u.u_sockaddr_in6.sin6_addr));
2133 else
2135 bug("bad family");
2139 unsigned short
2140 vsf_sysutil_sockaddr_get_port(const struct vsf_sysutil_sockaddr* p_sockptr)
2142 if (p_sockptr->u.u_sockaddr.sa_family == AF_INET)
2144 return ntohs(p_sockptr->u.u_sockaddr_in.sin_port);
2146 else if (p_sockptr->u.u_sockaddr.sa_family == AF_INET6)
2148 return ntohs(p_sockptr->u.u_sockaddr_in6.sin6_port);
2150 else
2152 bug("bad family");
2154 /* NOTREACHED */
2155 return 0;
2158 void
2159 vsf_sysutil_sockaddr_set_port(struct vsf_sysutil_sockaddr* p_sockptr,
2160 unsigned short the_port)
2162 if (p_sockptr->u.u_sockaddr.sa_family == AF_INET)
2164 p_sockptr->u.u_sockaddr_in.sin_port = htons(the_port);
2166 else if (p_sockptr->u.u_sockaddr.sa_family == AF_INET6)
2168 p_sockptr->u.u_sockaddr_in6.sin6_port = htons(the_port);
2170 else
2172 bug("bad family");
2177 vsf_sysutil_is_port_reserved(unsigned short the_port)
2179 if (the_port < IPPORT_RESERVED)
2181 return 1;
2183 return 0;
2186 const char*
2187 vsf_sysutil_inet_ntop(const struct vsf_sysutil_sockaddr* p_sockptr)
2189 const struct sockaddr* p_sockaddr = &p_sockptr->u.u_sockaddr;
2190 if (p_sockaddr->sa_family == AF_INET)
2192 return inet_ntoa(p_sockptr->u.u_sockaddr_in.sin_addr);
2194 else if (p_sockaddr->sa_family == AF_INET6)
2196 static char inaddr_buf[64];
2197 const char* p_ret = inet_ntop(AF_INET6,
2198 &p_sockptr->u.u_sockaddr_in6.sin6_addr,
2199 inaddr_buf, sizeof(inaddr_buf));
2200 inaddr_buf[sizeof(inaddr_buf) - 1] = '\0';
2201 if (p_ret == NULL)
2203 inaddr_buf[0] = '\0';
2205 return inaddr_buf;
2207 else
2209 die("can only support ipv4 and ipv6 currently");
2210 return 0;
2214 const char*
2215 vsf_sysutil_inet_ntoa(const void* p_raw_addr)
2217 return inet_ntoa(*((struct in_addr*)p_raw_addr));
2221 vsf_sysutil_inet_aton(const char* p_text, struct vsf_sysutil_sockaddr* p_addr)
2223 struct in_addr sin_addr;
2224 if (p_addr->u.u_sockaddr.sa_family != AF_INET)
2226 bug("bad family");
2228 if (inet_aton(p_text, &sin_addr))
2230 vsf_sysutil_memcpy(&p_addr->u.u_sockaddr_in.sin_addr,
2231 &sin_addr, sizeof(p_addr->u.u_sockaddr_in.sin_addr));
2232 return 1;
2234 else
2236 return 0;
2240 void
2241 vsf_sysutil_dns_resolve(struct vsf_sysutil_sockaddr** p_sockptr,
2242 const char* p_name)
2244 struct hostent* hent = gethostbyname(p_name);
2245 if (hent == NULL)
2247 die2("cannot resolve host:", p_name);
2249 vsf_sysutil_sockaddr_clear(p_sockptr);
2250 if (hent->h_addrtype == AF_INET)
2252 unsigned int len = hent->h_length;
2253 if (len > sizeof((*p_sockptr)->u.u_sockaddr_in.sin_addr))
2255 len = sizeof((*p_sockptr)->u.u_sockaddr_in.sin_addr);
2257 vsf_sysutil_sockaddr_alloc_ipv4(p_sockptr);
2258 vsf_sysutil_memcpy(&(*p_sockptr)->u.u_sockaddr_in.sin_addr,
2259 hent->h_addr_list[0], len);
2261 else if (hent->h_addrtype == AF_INET6)
2263 unsigned int len = hent->h_length;
2264 if (len > sizeof((*p_sockptr)->u.u_sockaddr_in6.sin6_addr))
2266 len = sizeof((*p_sockptr)->u.u_sockaddr_in6.sin6_addr);
2268 vsf_sysutil_sockaddr_alloc_ipv6(p_sockptr);
2269 vsf_sysutil_memcpy(&(*p_sockptr)->u.u_sockaddr_in6.sin6_addr,
2270 hent->h_addr_list[0], len);
2272 else
2274 die("gethostbyname(): neither IPv4 nor IPv6");
2278 struct vsf_sysutil_user*
2279 vsf_sysutil_getpwuid(const int uid)
2281 if (uid < 0)
2283 bug("negative uid in vsf_sysutil_getpwuid");
2285 return (struct vsf_sysutil_user*) getpwuid((unsigned int) uid);
2288 /* hack to reload getpwnam -- uClibc implementation alike */
2289 struct passwd *getpwnam(const char *name)
2291 FILE *f;
2292 static char line_buff[256 /*PWD_BUFFER_SIZE*/];
2293 static struct passwd pwdbuf;
2294 struct passwd *pwd;
2296 if (tunable_passwd_file == NULL)
2298 if (getpwnam_r(name, &pwdbuf, line_buff, sizeof(line_buff), &pwd) == 0) {
2299 return &pwdbuf;
2301 return NULL;
2304 f = fopen(tunable_passwd_file, "r");
2305 if (f != NULL)
2307 while (fgetpwent_r(f, &pwdbuf, line_buff, sizeof(line_buff), &pwd) == 0) {
2308 if (!strncmp(pwdbuf.pw_name, name, 256)) {
2309 fclose(f);
2310 return &pwdbuf;
2313 fclose(f);
2316 return NULL;
2319 struct vsf_sysutil_user*
2320 vsf_sysutil_getpwnam(const char* p_user)
2322 return (struct vsf_sysutil_user*) getpwnam(p_user);
2325 const char*
2326 vsf_sysutil_user_getname(const struct vsf_sysutil_user* p_user)
2328 const struct passwd* p_passwd = (const struct passwd*) p_user;
2329 return p_passwd->pw_name;
2332 const char*
2333 vsf_sysutil_user_get_homedir(const struct vsf_sysutil_user* p_user)
2335 const struct passwd* p_passwd = (const struct passwd*) p_user;
2336 return p_passwd->pw_dir;
2340 vsf_sysutil_user_getuid(const struct vsf_sysutil_user* p_user)
2342 const struct passwd* p_passwd = (const struct passwd*) p_user;
2343 return p_passwd->pw_uid;
2347 vsf_sysutil_user_getgid(const struct vsf_sysutil_user* p_user)
2349 const struct passwd* p_passwd = (const struct passwd*) p_user;
2350 return p_passwd->pw_gid;
2353 struct vsf_sysutil_group*
2354 vsf_sysutil_getgrgid(const int gid)
2356 if (gid < 0)
2358 die("negative gid in vsf_sysutil_getgrgid");
2360 return (struct vsf_sysutil_group*) getgrgid((unsigned int) gid);
2363 const char*
2364 vsf_sysutil_group_getname(const struct vsf_sysutil_group* p_group)
2366 const struct group* p_grp = (const struct group*) p_group;
2367 return p_grp->gr_name;
2370 unsigned char
2371 vsf_sysutil_get_random_byte(void)
2373 static int seeded;
2374 unsigned int uint_res;
2375 unsigned char c1, c2, c3, c4;
2376 if (!seeded)
2378 struct timeval tv;
2379 int retval = gettimeofday(&tv, NULL);
2380 if (retval != 0)
2382 die("gettimeofday");
2384 srand((unsigned)tv.tv_usec);
2385 seeded = 1;
2387 uint_res = rand();
2388 c1 = uint_res & 0x000000ff;
2389 c2 = (uint_res >> 8) & 0x000000ff;
2390 c3 = (uint_res >> 16) & 0x000000ff;
2391 c4 = (uint_res >> 24) & 0x000000ff;
2392 return c1 ^ c2 ^ c3 ^ c4;
2396 vsf_sysutil_running_as_root(void)
2398 return (getuid() == 0);
2401 void
2402 vsf_sysutil_setuid(const struct vsf_sysutil_user* p_user)
2404 const struct passwd* p_passwd = (const struct passwd*) p_user;
2405 vsf_sysutil_setuid_numeric(p_passwd->pw_uid);
2408 void
2409 vsf_sysutil_setuid_numeric(int uid)
2411 int retval = setuid(uid);
2412 if (retval != 0)
2414 die("setuid");
2418 void
2419 vsf_sysutil_setgid(const struct vsf_sysutil_user* p_user)
2421 const struct passwd* p_passwd = (const struct passwd*) p_user;
2422 vsf_sysutil_setgid_numeric(p_passwd->pw_gid);
2425 void
2426 vsf_sysutil_setgid_numeric(int gid)
2428 int retval = setgid(gid);
2429 if (retval != 0)
2431 die("setgid");
2436 vsf_sysutil_geteuid(void)
2438 int retval = geteuid();
2439 if (retval < 0)
2441 die("geteuid");
2443 return retval;
2447 vsf_sysutil_getegid(void)
2449 int retval = getegid();
2450 if (retval < 0)
2452 die("getegid");
2454 return retval;
2457 void
2458 vsf_sysutil_seteuid(const struct vsf_sysutil_user* p_user)
2460 const struct passwd* p_passwd = (const struct passwd*) p_user;
2461 vsf_sysutil_seteuid_numeric(p_passwd->pw_uid);
2464 void
2465 vsf_sysutil_setegid(const struct vsf_sysutil_user* p_user)
2467 const struct passwd* p_passwd = (const struct passwd*) p_user;
2468 vsf_sysutil_setegid_numeric(p_passwd->pw_gid);
2471 void
2472 vsf_sysutil_seteuid_numeric(int uid)
2474 /* setreuid() would seem to be more portable than seteuid() */
2475 int retval = setreuid(-1, uid);
2476 if (retval != 0)
2478 die("seteuid");
2482 void
2483 vsf_sysutil_setegid_numeric(int gid)
2485 /* setregid() would seem to be more portable than setegid() */
2486 int retval = setregid(-1, gid);
2487 if (retval != 0)
2489 die("setegid");
2493 void
2494 vsf_sysutil_clear_supp_groups(void)
2496 int retval = setgroups(0, NULL);
2497 if (retval != 0)
2499 die("setgroups");
2503 void
2504 vsf_sysutil_initgroups(const struct vsf_sysutil_user* p_user)
2506 const struct passwd* p_passwd = (const struct passwd*) p_user;
2507 int retval = initgroups(p_passwd->pw_name, p_passwd->pw_gid);
2508 if (retval != 0)
2510 die("initgroups");
2514 void
2515 vsf_sysutil_chroot(const char* p_root_path)
2517 int retval = chroot(p_root_path);
2518 if (retval != 0)
2520 die("chroot");
2524 unsigned int
2525 vsf_sysutil_get_umask(void)
2527 return s_current_umask;
2530 void
2531 vsf_sysutil_set_umask(unsigned int new_umask)
2533 s_current_umask = (new_umask & 0777);
2534 (void) umask(s_current_umask);
2537 void
2538 vsf_sysutil_make_session_leader(void)
2540 /* This makes us the leader if we are not already */
2541 (void) setsid();
2542 /* Check we're the leader */
2543 if ((int) vsf_sysutil_getpid() != getpgrp())
2545 die("not session leader");
2549 void
2550 vsf_sysutil_reopen_standard_fds(void)
2552 /* This reopens STDIN, STDOUT and STDERR to /dev/null */
2553 int fd;
2554 if ((fd = open("/dev/null", O_RDWR, 0)) < 0)
2556 goto error;
2558 vsf_sysutil_dupfd2(fd, STDIN_FILENO);
2559 vsf_sysutil_dupfd2(fd, STDOUT_FILENO);
2560 vsf_sysutil_dupfd2(fd, STDERR_FILENO);
2561 if ( fd > 2 )
2563 vsf_sysutil_close(fd);
2565 return;
2567 error:
2568 die("reopening standard file descriptors to /dev/null failed");
2571 void
2572 vsf_sysutil_tzset(void)
2574 int retval;
2575 char tzbuf[sizeof("+HHMM!")];
2576 time_t the_time = time(NULL);
2577 struct tm* p_tm;
2578 tzset();
2579 p_tm = localtime(&the_time);
2580 if (p_tm == NULL)
2582 die("localtime");
2584 /* Set our timezone in the TZ environment variable to cater for the fact
2585 * that modern glibc does not cache /etc/localtime (which becomes inaccessible
2586 * when we chroot().
2588 retval = strftime(tzbuf, sizeof(tzbuf), "%z", p_tm);
2589 tzbuf[sizeof(tzbuf) - 1] = '\0';
2590 if (retval == 5)
2592 /* Static because putenv() does not copy the string. */
2593 static char envtz[sizeof("TZ=UTC-hh:mm")];
2594 /* Insert a colon so we have e.g. -05:00 instead of -0500 */
2595 tzbuf[5] = tzbuf[4];
2596 tzbuf[4] = tzbuf[3];
2597 tzbuf[3] = ':';
2598 /* Invert the sign - we just got the offset _from_ UTC but for TZ, we need
2599 * the offset _to_ UTC.
2601 if (tzbuf[0] == '+')
2603 tzbuf[0] = '-';
2605 else
2607 tzbuf[0] = '+';
2609 snprintf(envtz, sizeof(envtz), "TZ=UTC%s", tzbuf);
2610 putenv(envtz);
2611 s_timezone = ((tzbuf[1] - '0') * 10 + (tzbuf[2] - '0')) * 60 * 60;
2612 s_timezone += ((tzbuf[4] - '0') * 10 + (tzbuf[5] - '0')) * 60;
2613 if (tzbuf[0] == '-')
2615 s_timezone *= -1;
2620 const char*
2621 vsf_sysutil_get_current_date(void)
2623 static char datebuf[64];
2624 time_t curr_time;
2625 const struct tm* p_tm;
2626 int i = 0;
2627 curr_time = vsf_sysutil_get_time_sec();
2628 p_tm = localtime(&curr_time);
2629 if (strftime(datebuf, sizeof(datebuf), "%a %b!%d %H:%M:%S %Y", p_tm) == 0)
2631 die("strftime");
2633 datebuf[sizeof(datebuf) - 1] = '\0';
2634 /* This hack is because %e in strftime() isn't so portable */
2635 while (datebuf[i] != '!' && datebuf[i] != '\0')
2637 ++i;
2639 if (datebuf[i] == '!')
2641 datebuf[i] = ' ';
2642 if (datebuf[i+1] == '0')
2644 datebuf[i+1] = ' ';
2647 return datebuf;
2650 long
2651 vsf_sysutil_get_time_sec(void)
2653 if (gettimeofday(&s_current_time, NULL) != 0)
2655 die("gettimeofday");
2657 return s_current_time.tv_sec;
2660 long
2661 vsf_sysutil_get_time_usec(void)
2663 return s_current_time.tv_usec;
2666 void
2667 vsf_sysutil_qsort(void* p_base, unsigned int num_elem, unsigned int elem_size,
2668 int (*p_compar)(const void *, const void *))
2670 qsort(p_base, num_elem, elem_size, p_compar);
2673 void
2674 vsf_sysutil_sleep(double seconds)
2676 int retval;
2677 int saved_errno;
2678 double fractional;
2679 time_t secs;
2680 struct timespec ts;
2681 secs = (time_t) seconds;
2682 fractional = seconds - (double) secs;
2683 ts.tv_sec = secs;
2684 ts.tv_nsec = (long) (fractional * (double) 1000000000);
2687 retval = nanosleep(&ts, &ts);
2688 saved_errno = errno;
2689 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
2690 } while (retval == -1 && saved_errno == EINTR);
2693 char*
2694 vsf_sysutil_getenv(const char* p_var)
2696 return getenv(p_var);
2699 void
2700 vsf_sysutil_openlog(int force)
2702 int facility = LOG_DAEMON;
2703 int option = LOG_PID;
2704 if (!force)
2706 option |= LOG_NDELAY;
2708 #ifdef LOG_FTP
2709 facility = LOG_FTP;
2710 #endif
2711 openlog("vsftpd", option, facility);
2714 void
2715 vsf_sysutil_closelog(void)
2717 closelog();
2720 void
2721 vsf_sysutil_syslog(const char* p_text, int severe)
2723 int prio = LOG_INFO;
2724 if (severe)
2726 prio = LOG_WARNING;
2728 syslog(prio, "%s", p_text);
2731 long
2732 vsf_sysutil_parse_time(const char* p_text)
2734 struct tm the_time;
2735 unsigned int len = vsf_sysutil_strlen(p_text);
2736 vsf_sysutil_memclr(&the_time, sizeof(the_time));
2737 if (len >= 8)
2739 char yr[5];
2740 char mon[3];
2741 char day[3];
2742 vsf_sysutil_strcpy(yr, p_text, 5);
2743 vsf_sysutil_strcpy(mon, p_text + 4, 3);
2744 vsf_sysutil_strcpy(day, p_text + 6, 3);
2745 the_time.tm_year = vsf_sysutil_atoi(yr) - 1900;
2746 the_time.tm_mon = vsf_sysutil_atoi(mon) - 1;
2747 the_time.tm_mday = vsf_sysutil_atoi(day);
2749 if (len >= 14)
2751 char hr[3];
2752 char mins[3];
2753 char sec[3];
2754 vsf_sysutil_strcpy(hr, p_text + 8, 3);
2755 vsf_sysutil_strcpy(mins, p_text + 10, 3);
2756 vsf_sysutil_strcpy(sec, p_text + 12, 3);
2757 the_time.tm_hour = vsf_sysutil_atoi(hr);
2758 the_time.tm_min = vsf_sysutil_atoi(mins);
2759 the_time.tm_sec = vsf_sysutil_atoi(sec);
2761 return mktime(&the_time);
2765 vsf_sysutil_setmodtime(const char* p_file, long the_time, int is_localtime)
2767 struct utimbuf new_times;
2768 if (!is_localtime)
2770 the_time -= s_timezone;
2772 vsf_sysutil_memclr(&new_times, sizeof(new_times));
2773 new_times.actime = the_time;
2774 new_times.modtime = the_time;
2775 return utime(p_file, &new_times);
2778 void
2779 vsf_sysutil_ftruncate(int fd)
2781 int ret = ftruncate(fd, 0);
2782 if (ret != 0)
2784 die("ftruncate");
2789 vsf_sysutil_getuid(void)
2791 return getuid();
2794 void
2795 vsf_sysutil_set_address_space_limit(long bytes)
2797 /* Unfortunately, OpenBSD is missing RLIMIT_AS. */
2798 #ifdef RLIMIT_AS
2799 int ret;
2800 struct rlimit rlim;
2801 rlim.rlim_cur = bytes;
2802 rlim.rlim_max = bytes;
2803 ret = setrlimit(RLIMIT_AS, &rlim);
2804 /* Permit EPERM as this could indicate that the shell launching vsftpd already
2805 * has a lower limit.
2807 if (ret != 0 && errno != EPERM)
2809 die("setrlimit");
2811 #endif /* RLIMIT_AS */
2812 (void) bytes;
2815 void
2816 vsf_sysutil_set_no_fds()
2818 int ret;
2819 struct rlimit rlim;
2820 rlim.rlim_cur = 0;
2821 rlim.rlim_max = 0;
2822 ret = setrlimit(RLIMIT_NOFILE, &rlim);
2823 if (ret != 0)
2825 die("setrlimit NOFILE");
2829 void
2830 vsf_sysutil_set_no_procs()
2832 #ifdef RLIMIT_NPROC
2833 int ret;
2834 struct rlimit rlim;
2835 rlim.rlim_cur = 0;
2836 rlim.rlim_max = 0;
2837 ret = setrlimit(RLIMIT_NPROC, &rlim);
2838 if (ret != 0)
2840 die("setrlimit NPROC");
2842 #endif
2845 void
2846 vsf_sysutil_post_fork()
2848 int i;
2849 /* Don't inherit any exit function. */
2850 s_exit_func = NULL;
2851 /* Uncached the current PID. */
2852 s_current_pid = -1;
2853 /* Don't inherit anything relating to the synchronous signal system */
2854 s_io_handler = NULL;
2855 for (i=0; i < NSIG; ++i)
2857 s_sig_details[i].sync_sig_handler = NULL;
2859 for (i=0; i < NSIG; ++i)
2861 s_sig_details[i].pending = 0;