2 * Part of Very Secure FTPd
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
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"
33 #include <sys/types.h>
34 #include <sys/socket.h>
38 #include <netinet/in.h>
42 #include <arpa/inet.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>
57 #include <sys/resource.h>
59 /* Private variables to this file */
61 static unsigned int s_current_umask
;
63 static struct timeval s_current_time
;
65 static int s_current_pid
= -1;
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
;
76 volatile sig_atomic_t pending
;
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
89 struct sockaddr u_sockaddr
;
90 struct sockaddr_in u_sockaddr_in
;
91 struct sockaddr_in6 u_sockaddr_in6
;
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
);
109 vsf_sysutil_alrm_sighandler(int signum
)
116 vsf_sysutil_common_sighandler(int signum
)
118 if (signum
< 0 || signum
>= NSIG
)
120 /* "cannot happen" */
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
)
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.
150 vsf_sysutil_check_pending_actions(
151 const enum EVSFSysUtilInterruptContext context
, int retval
, int fd
)
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
)
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;
181 vsf_sysutil_translate_sig(const enum EVSFSysUtilSignal sig
)
186 case kVSFSysUtilSigALRM
:
189 case kVSFSysUtilSigTERM
:
192 case kVSFSysUtilSigCHLD
:
195 case kVSFSysUtilSigPIPE
:
198 case kVSFSysUtilSigURG
:
201 case kVSFSysUtilSigHUP
:
205 bug("unknown signal in vsf_sysutil_translate_sig");
208 if (realsig
< 0 || realsig
>= NSIG
)
210 bug("signal out of range in vsf_sysutil_translate_sig");
216 vsf_sysutil_install_sighandler(const enum EVSFSysUtilSignal sig
,
217 vsf_sighandle_t handler
,
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
);
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
;
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
);
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
);
262 vsf_sysutil_set_sighandler(int sig
, void (*p_handlefunc
)(int))
265 struct sigaction sigact
;
266 vsf_sysutil_memclr(&sigact
, sizeof(sigact
));
267 sigact
.sa_handler
= p_handlefunc
;
268 retval
= sigfillset(&sigact
.sa_mask
);
273 retval
= sigaction(sig
, &sigact
, NULL
);
281 vsf_sysutil_block_sig(const enum EVSFSysUtilSignal sig
)
285 int realsig
= vsf_sysutil_translate_sig(sig
);
286 retval
= sigemptyset(&sset
);
291 retval
= sigaddset(&sset
, realsig
);
296 retval
= sigprocmask(SIG_BLOCK
, &sset
, NULL
);
304 vsf_sysutil_unblock_sig(const enum EVSFSysUtilSignal sig
)
308 int realsig
= vsf_sysutil_translate_sig(sig
);
309 retval
= sigemptyset(&sset
);
314 retval
= sigaddset(&sset
, realsig
);
319 retval
= sigprocmask(SIG_UNBLOCK
, &sset
, NULL
);
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
;
337 vsf_sysutil_uninstall_io_handler(void)
339 if (s_io_handler
== NULL
)
341 bug("no i/o handler to unregister!");
344 s_p_io_handler_private
= NULL
;
348 vsf_sysutil_set_alarm(const unsigned int trigger_seconds
)
350 (void) alarm(trigger_seconds
);
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
)
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
)
376 vsf_sysutil_write(const int fd
, const void* p_buf
, const unsigned int size
)
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
)
392 vsf_sysutil_read_loop(const int fd
, void* p_buf
, unsigned int size
)
398 die("size too big in vsf_sysutil_read_loop");
402 retval
= vsf_sysutil_read(fd
, (char*)p_buf
+ num_read
, size
);
407 else if (retval
== 0)
409 /* Read all we're going to read.. */
412 if ((unsigned int) retval
> size
)
414 die("retval too big in vsf_sysutil_read_loop");
417 size
-= (unsigned int) retval
;
420 /* Hit the read target, cool. */
427 vsf_sysutil_write_loop(const int fd
, const void* p_buf
, unsigned int size
)
433 die("size too big in vsf_sysutil_write_loop");
437 retval
= vsf_sysutil_write(fd
, (const char*)p_buf
+ num_written
, size
);
443 else if (retval
== 0)
445 /* Written all we're going to write.. */
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
;
456 /* Hit the write target, cool. */
463 vsf_sysutil_get_file_offset(const int file_fd
)
465 filesize_t retval
= lseek(file_fd
, 0, SEEK_CUR
);
474 vsf_sysutil_lseek_to(const int fd
, filesize_t seek_pos
)
479 die("negative seek_pos in vsf_sysutil_lseek_to");
481 retval
= lseek(fd
, seek_pos
, SEEK_SET
);
489 vsf_sysutil_lseek_end(const int fd
)
492 retval
= lseek(fd
, 0, SEEK_END
);
500 vsf_sysutil_malloc(unsigned int size
)
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
);
517 vsf_sysutil_realloc(void* p_ptr
, unsigned int size
)
520 if (size
== 0 || size
> INT_MAX
)
522 bug("zero or big size in vsf_sysutil_realloc");
524 p_ret
= realloc(p_ptr
, size
);
533 vsf_sysutil_free(void* p_ptr
)
537 bug("vsf_sysutil_free got a null pointer");
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();
564 vsf_sysutil_fork_failok(void)
570 vsf_sysutil_post_fork();
576 vsf_sysutil_set_exit_func(exitfunc_t exitfunc
)
578 s_exit_func
= exitfunc
;
582 vsf_sysutil_exit(int exit_code
)
586 exitfunc_t curr_func
= s_exit_func
;
587 /* Prevent recursion */
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
));
601 int sys_ret
= wait(&retval
.exit_status
);
602 if (sys_ret
< 0 && errno
== EINTR
)
604 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown
, 0, 0);
607 retval
.syscall_retval
= sys_ret
;
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 */
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
)
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
);
656 vsf_sysutil_activate_keepalive(int fd
)
659 int retval
= setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &keepalive
,
663 die("setsockopt: keepalive");
668 vsf_sysutil_activate_reuseaddr(int fd
)
671 int retval
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &reuseaddr
,
675 die("setsockopt: reuseaddr");
680 vsf_sysutil_set_nodelay(int fd
)
683 int retval
= setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &nodelay
,
687 die("setsockopt: nodelay");
692 vsf_sysutil_activate_sigurg(int fd
)
694 int retval
= fcntl(fd
, F_SETOWN
, vsf_sysutil_getpid());
702 vsf_sysutil_activate_oobinline(int fd
)
705 int retval
= setsockopt(fd
, SOL_SOCKET
, SO_OOBINLINE
, &oob_inline
,
709 die("setsockopt: oobinline");
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
));
722 vsf_sysutil_activate_linger(int fd
)
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
,
733 die("setsockopt: linger");
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
));
747 vsf_sysutil_activate_noblock(int fd
)
750 int curr_flags
= fcntl(fd
, F_GETFL
);
751 if (vsf_sysutil_retval_is_error(curr_flags
))
755 curr_flags
|= O_NONBLOCK
;
756 retval
= fcntl(fd
, F_SETFL
, curr_flags
);
764 vsf_sysutil_deactivate_noblock(int fd
)
767 int curr_flags
= fcntl(fd
, F_GETFL
);
768 if (vsf_sysutil_retval_is_error(curr_flags
))
772 curr_flags
&= ~O_NONBLOCK
;
773 retval
= fcntl(fd
, F_SETFL
, curr_flags
);
781 vsf_sysutil_recv_peek(const int fd
, void* p_buf
, unsigned int len
)
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
)
797 vsf_sysutil_atoi(const char* p_str
)
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;
810 unsigned int len
= vsf_sysutil_strlen(p_str
);
812 /* Bail if the number is excessively big (petabytes!) */
817 for (i
=0; i
<len
; ++i
)
819 char the_char
= p_str
[len
-(i
+1)];
821 if (the_char
< '0' || the_char
> '9')
825 val
= the_char
- '0';
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
);
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
);
853 (void) snprintf(filesize_buf
, sizeof(filesize_buf
), "%lld", the_filesize
);
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
);
867 vsf_sysutil_uint_to_octal(unsigned int the_uint
)
869 static char octal_buf
[32];
877 (void) snprintf(octal_buf
, sizeof(octal_buf
), "0%o", the_uint
);
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')
891 if (!isdigit(digit
) || digit
> '7')
897 seen_non_zero_digit
= 1;
899 if (seen_non_zero_digit
)
902 result
+= (digit
- '0');
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
;
936 if (uc
>= 128 && uc
<= 159)
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
);
956 vsf_sysutil_getcwd(char* p_dest
, const unsigned int buf_size
)
962 p_retval
= getcwd(p_dest
, buf_size
);
963 p_dest
[buf_size
- 1] = '\0';
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
);
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
);
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
)
1017 return p_dirent
->d_name
;
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");
1033 vsf_sysutil_strdup(const char* p_str
)
1035 return strdup(p_str
);
1039 vsf_sysutil_memclr(void* p_dest
, unsigned int size
)
1046 memset(p_dest
, '\0', size
);
1050 vsf_sysutil_memcpy(void* p_dest
, const void* p_src
, const unsigned int size
)
1057 /* Defense in depth */
1060 die("possible negative value to memcpy?");
1062 memcpy(p_dest
, p_src
, size
);
1066 vsf_sysutil_strcpy(char* p_dest
, const char* p_src
, unsigned int maxsize
)
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
)
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
);
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)
1109 vsf_sysutil_translate_memprot(const enum EVSFSysUtilMapPermission perm
)
1114 case kVSFSysUtilMapProtReadOnly
:
1117 case kVSFSysUtilMapProtNone
:
1121 bug("bad value in vsf_sysutil_translate_memprot");
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
);
1140 vsf_sysutil_memunmap(void* p_start
, unsigned int length
)
1142 int retval
= munmap(p_start
, length
);
1150 vsf_sysutil_translate_openmode(const enum EVSFSysUtilOpenMode mode
)
1155 case kVSFSysUtilOpenReadOnly
:
1158 case kVSFSysUtilOpenWriteOnly
:
1161 case kVSFSysUtilOpenReadWrite
:
1165 bug("bad mode in vsf_sysutil_translate_openmode");
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
,
1196 return open(p_filename
, O_CREAT
| O_WRONLY
| O_NONBLOCK
| O_APPEND
, mode
);
1200 vsf_sysutil_dupfd2(int old_fd
, int new_fd
)
1203 if (old_fd
== new_fd
)
1207 retval
= dup2(old_fd
, new_fd
);
1208 if (retval
!= new_fd
)
1215 vsf_sysutil_close(int fd
)
1219 int retval
= close(fd
);
1224 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown
, 0, 0);
1234 vsf_sysutil_close_failok(int 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);
1253 vsf_sysutil_alloc_statbuf(struct vsf_sysutil_statbuf
** p_ptr
)
1257 *p_ptr
= vsf_sysutil_malloc(sizeof(struct stat
));
1262 vsf_sysutil_fstat(int fd
, struct vsf_sysutil_statbuf
** p_ptr
)
1265 vsf_sysutil_alloc_statbuf(p_ptr
);
1266 retval
= fstat(fd
, (struct stat
*) (*p_ptr
));
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
));
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
);
1324 vsf_sysutil_statbuf_get_perms(const struct vsf_sysutil_statbuf
* p_statbuf
)
1326 static char perms
[11];
1328 const struct stat
* p_stat
= (const struct stat
*) p_statbuf
;
1329 for (i
=0; i
<10; i
++)
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';
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];
1367 const struct stat
* p_stat
= (const struct stat
*) p_statbuf
;
1368 const char* p_date_format
= "%b %d %H:%M";
1371 p_tm
= gmtime(&p_stat
->st_mtime
);
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';
1393 vsf_sysutil_statbuf_get_numeric_date(
1394 const struct vsf_sysutil_statbuf
* p_statbuf
,
1397 static char datebuf
[15];
1398 const struct stat
* p_stat
= (const struct stat
*) p_statbuf
;
1403 p_tm
= gmtime(&p_stat
->st_mtime
);
1407 p_tm
= localtime(&p_stat
->st_mtime
);
1409 retval
= strftime(datebuf
, sizeof(datebuf
), "%Y%m%d%H%M%S", p_tm
);
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
;
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
)
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
);
1476 vsf_sysutil_fchown(const int fd
, const int uid
, const int gid
)
1478 if (fchown(fd
, uid
, gid
) != 0)
1485 vsf_sysutil_fchmod(const int fd
, unsigned int mode
)
1488 if (fchmod(fd
, mode
))
1495 vsf_sysutil_chmod(const char* p_filename
, unsigned int mode
)
1497 /* Safety: mask "mode" to just access permissions, e.g. no suid setting! */
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
);
1515 lock_internal(int fd
, int lock_type
)
1517 struct flock the_lock
;
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;
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
);
1536 vsf_sysutil_unlock_file(int fd
)
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;
1545 retval
= fcntl(fd
, F_SETLK
, &the_lock
);
1553 vsf_sysutil_readlink(const char* p_filename
, char* p_dest
, unsigned int bufsiz
)
1559 retval
= readlink(p_filename
, p_dest
, bufsiz
- 1);
1564 /* Ensure buffer is NULL terminated; readlink(2) doesn't do that */
1565 p_dest
[retval
] = '\0';
1570 vsf_sysutil_retval_is_error(int retval
)
1579 enum EVSFSysUtilError
1580 vsf_sysutil_get_error(void)
1582 enum EVSFSysUtilError retval
= kVSFSysUtilErrUnknown
;
1586 retval
= kVSFSysUtilErrADDRINUSE
;
1589 retval
= kVSFSysUtilErrNOSYS
;
1592 retval
= kVSFSysUtilErrINTR
;
1595 retval
= kVSFSysUtilErrINVAL
;
1598 retval
= kVSFSysUtilErrOPNOTSUPP
;
1601 retval
= kVSFSysUtilErrACCES
;
1604 retval
= kVSFSysUtilErrNOENT
;
1611 vsf_sysutil_get_ipv4_sock(void)
1613 int retval
= socket(PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
1622 vsf_sysutil_get_ipv6_sock(void)
1624 int retval
= socket(PF_INET6
, SOCK_STREAM
, IPPROTO_TCP
);
1632 struct vsf_sysutil_socketpair_retval
1633 vsf_sysutil_unix_stream_socketpair(void)
1635 struct vsf_sysutil_socketpair_retval retval
;
1637 int sys_retval
= socketpair(PF_UNIX
, SOCK_STREAM
, 0, the_sockets
);
1638 if (sys_retval
!= 0)
1642 retval
.socket_one
= the_sockets
[0];
1643 retval
.socket_two
= the_sockets
[1];
1648 vsf_sysutil_bind(int fd
, const struct vsf_sysutil_sockaddr
* p_sockptr
)
1650 const struct sockaddr
* p_sockaddr
= &p_sockptr
->u
.u_sockaddr
;
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
);
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
)
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
;
1689 fd_set accept_fdset
;
1690 struct timeval timeout
;
1691 socklen_t socklen
= sizeof(remote_addr
);
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
);
1714 retval
= accept(fd
, &remote_addr
.u
.u_sockaddr
, &socklen
);
1715 vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown
, 0, 0);
1720 /* FreeBSD bug / paranoia: ai32@drexel.edu */
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");
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
));
1741 vsf_sysutil_memcpy(p_sockaddr
, &remote_addr
.u
.u_sockaddr_in6
,
1742 sizeof(remote_addr
.u
.u_sockaddr_in6
));
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;
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
);
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
);
1795 socklen_t socklen
= sizeof(retval
);
1796 int sockoptret
= getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &retval
, &socklen
);
1797 if (sockoptret
!= 0)
1803 if (wait_seconds
> 0)
1805 vsf_sysutil_deactivate_noblock(fd
);
1811 vsf_sysutil_getsockname(int fd
, struct vsf_sysutil_sockaddr
** p_sockptr
)
1813 struct vsf_sysutil_sockaddr the_addr
;
1815 socklen_t socklen
= sizeof(the_addr
);
1816 vsf_sysutil_sockaddr_clear(p_sockptr
);
1817 retval
= getsockname(fd
, &the_addr
.u
.u_sockaddr
, &socklen
);
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
);
1836 vsf_sysutil_getpeername(int fd
, struct vsf_sysutil_sockaddr
** p_sockptr
)
1838 struct vsf_sysutil_sockaddr the_addr
;
1840 socklen_t socklen
= sizeof(the_addr
);
1841 vsf_sysutil_sockaddr_clear(p_sockptr
);
1842 retval
= getpeername(fd
, &the_addr
.u
.u_sockaddr
, &socklen
);
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
);
1861 vsf_sysutil_shutdown_failok(int fd
)
1863 /* SHUT_RDWR is a relatively new addition */
1867 (void) shutdown(fd
, SHUT_RDWR
);
1871 vsf_sysutil_shutdown_read_failok(int fd
)
1873 /* SHUT_RD is a relatively new addition */
1877 (void) shutdown(fd
, SHUT_RD
);
1881 vsf_sysutil_sockaddr_clear(struct vsf_sysutil_sockaddr
** p_sockptr
)
1883 if (*p_sockptr
!= NULL
)
1885 vsf_sysutil_free(*p_sockptr
);
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
));
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
;
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
;
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
;
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
);
1953 !vsf_sysutil_memcmp(p_ipv4_addr
, &p1
->u
.u_sockaddr_in
.sin_addr
,
1954 sizeof(p1
->u
.u_sockaddr_in
.sin_addr
)))
1959 else if (family1
== AF_INET6
&& family2
== AF_INET
)
1961 const void* p_ipv4_addr
= vsf_sysutil_sockaddr_ipv6_v4(p1
);
1963 !vsf_sysutil_memcmp(p_ipv4_addr
, &p2
->u
.u_sockaddr_in
.sin_addr
,
1964 sizeof(p2
->u
.u_sockaddr_in
.sin_addr
)))
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)
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)
1993 vsf_sysutil_sockaddr_is_ipv6(const struct vsf_sysutil_sockaddr
* p_sockaddr
)
1995 if (p_sockaddr
->u
.u_sockaddr
.sa_family
== AF_INET6
)
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
));
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
));
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
)
2051 if (vsf_sysutil_memcmp(pattern
, &p_addr
->u
.u_sockaddr_in6
.sin6_addr
, 12))
2055 p_addr_start
= (const unsigned char*)&p_addr
->u
.u_sockaddr_in6
.sin6_addr
;
2056 return &p_addr_start
[12];
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
)
2067 vsf_sysutil_memcpy(&ret
[12], &p_addr
->u
.u_sockaddr_in
.sin_addr
, 4);
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
;
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
);
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();
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
));
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
);
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
);
2177 vsf_sysutil_is_port_reserved(unsigned short the_port
)
2179 if (the_port
< IPPORT_RESERVED
)
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';
2203 inaddr_buf
[0] = '\0';
2209 die("can only support ipv4 and ipv6 currently");
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
)
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
));
2241 vsf_sysutil_dns_resolve(struct vsf_sysutil_sockaddr
** p_sockptr
,
2244 struct hostent
* hent
= gethostbyname(p_name
);
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
);
2274 die("gethostbyname(): neither IPv4 nor IPv6");
2278 struct vsf_sysutil_user
*
2279 vsf_sysutil_getpwuid(const int uid
)
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
)
2292 static char line_buff
[256 /*PWD_BUFFER_SIZE*/];
2293 static struct passwd pwdbuf
;
2296 if (tunable_passwd_file
== NULL
)
2298 if (getpwnam_r(name
, &pwdbuf
, line_buff
, sizeof(line_buff
), &pwd
) == 0) {
2304 f
= fopen(tunable_passwd_file
, "r");
2307 while (fgetpwent_r(f
, &pwdbuf
, line_buff
, sizeof(line_buff
), &pwd
) == 0) {
2308 if (!strncmp(pwdbuf
.pw_name
, name
, 256)) {
2319 struct vsf_sysutil_user
*
2320 vsf_sysutil_getpwnam(const char* p_user
)
2322 return (struct vsf_sysutil_user
*) getpwnam(p_user
);
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
;
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
)
2358 die("negative gid in vsf_sysutil_getgrgid");
2360 return (struct vsf_sysutil_group
*) getgrgid((unsigned int) gid
);
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
;
2371 vsf_sysutil_get_random_byte(void)
2374 unsigned int uint_res
;
2375 unsigned char c1
, c2
, c3
, c4
;
2379 int retval
= gettimeofday(&tv
, NULL
);
2382 die("gettimeofday");
2384 srand((unsigned)tv
.tv_usec
);
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);
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
);
2409 vsf_sysutil_setuid_numeric(int uid
)
2411 int retval
= setuid(uid
);
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
);
2426 vsf_sysutil_setgid_numeric(int gid
)
2428 int retval
= setgid(gid
);
2436 vsf_sysutil_geteuid(void)
2438 int retval
= geteuid();
2447 vsf_sysutil_getegid(void)
2449 int retval
= getegid();
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
);
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
);
2472 vsf_sysutil_seteuid_numeric(int uid
)
2474 /* setreuid() would seem to be more portable than seteuid() */
2475 int retval
= setreuid(-1, uid
);
2483 vsf_sysutil_setegid_numeric(int gid
)
2485 /* setregid() would seem to be more portable than setegid() */
2486 int retval
= setregid(-1, gid
);
2494 vsf_sysutil_clear_supp_groups(void)
2496 int retval
= setgroups(0, NULL
);
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
);
2515 vsf_sysutil_chroot(const char* p_root_path
)
2517 int retval
= chroot(p_root_path
);
2525 vsf_sysutil_get_umask(void)
2527 return s_current_umask
;
2531 vsf_sysutil_set_umask(unsigned int new_umask
)
2533 s_current_umask
= (new_umask
& 0777);
2534 (void) umask(s_current_umask
);
2538 vsf_sysutil_make_session_leader(void)
2540 /* This makes us the leader if we are not already */
2542 /* Check we're the leader */
2543 if ((int) vsf_sysutil_getpid() != getpgrp())
2545 die("not session leader");
2550 vsf_sysutil_reopen_standard_fds(void)
2552 /* This reopens STDIN, STDOUT and STDERR to /dev/null */
2554 if ((fd
= open("/dev/null", O_RDWR
, 0)) < 0)
2558 vsf_sysutil_dupfd2(fd
, STDIN_FILENO
);
2559 vsf_sysutil_dupfd2(fd
, STDOUT_FILENO
);
2560 vsf_sysutil_dupfd2(fd
, STDERR_FILENO
);
2563 vsf_sysutil_close(fd
);
2568 die("reopening standard file descriptors to /dev/null failed");
2572 vsf_sysutil_tzset(void)
2575 char tzbuf
[sizeof("+HHMM!")];
2576 time_t the_time
= time(NULL
);
2579 p_tm
= localtime(&the_time
);
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
2588 retval
= strftime(tzbuf
, sizeof(tzbuf
), "%z", p_tm
);
2589 tzbuf
[sizeof(tzbuf
) - 1] = '\0';
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];
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] == '+')
2609 snprintf(envtz
, sizeof(envtz
), "TZ=UTC%s", tzbuf
);
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] == '-')
2621 vsf_sysutil_get_current_date(void)
2623 static char datebuf
[64];
2625 const struct tm
* p_tm
;
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)
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')
2639 if (datebuf
[i
] == '!')
2642 if (datebuf
[i
+1] == '0')
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
;
2661 vsf_sysutil_get_time_usec(void)
2663 return s_current_time
.tv_usec
;
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
);
2674 vsf_sysutil_sleep(double seconds
)
2681 secs
= (time_t) seconds
;
2682 fractional
= seconds
- (double) 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
);
2694 vsf_sysutil_getenv(const char* p_var
)
2696 return getenv(p_var
);
2700 vsf_sysutil_openlog(int force
)
2702 int facility
= LOG_DAEMON
;
2703 int option
= LOG_PID
;
2706 option
|= LOG_NDELAY
;
2711 openlog("vsftpd", option
, facility
);
2715 vsf_sysutil_closelog(void)
2721 vsf_sysutil_syslog(const char* p_text
, int severe
)
2723 int prio
= LOG_INFO
;
2728 syslog(prio
, "%s", p_text
);
2732 vsf_sysutil_parse_time(const char* p_text
)
2735 unsigned int len
= vsf_sysutil_strlen(p_text
);
2736 vsf_sysutil_memclr(&the_time
, sizeof(the_time
));
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
);
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
;
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
);
2779 vsf_sysutil_ftruncate(int fd
)
2781 int ret
= ftruncate(fd
, 0);
2789 vsf_sysutil_getuid(void)
2795 vsf_sysutil_set_address_space_limit(long bytes
)
2797 /* Unfortunately, OpenBSD is missing RLIMIT_AS. */
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
)
2811 #endif /* RLIMIT_AS */
2816 vsf_sysutil_set_no_fds()
2822 ret
= setrlimit(RLIMIT_NOFILE
, &rlim
);
2825 die("setrlimit NOFILE");
2830 vsf_sysutil_set_no_procs()
2837 ret
= setrlimit(RLIMIT_NPROC
, &rlim
);
2840 die("setrlimit NPROC");
2846 vsf_sysutil_post_fork()
2849 /* Don't inherit any exit function. */
2851 /* Uncached the current PID. */
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;