2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
21 #if !defined(OS_OS2) && !defined(OS_WIN32)
38 #ifdef HAVE_SYS_SYSMACROS_H
39 #include <sys/sysmacros.h>
41 #ifdef HAVE_LINUX_FALLOC_H
42 #include <linux/falloc.h>
47 #ifdef HAVE_SYS_SELECT_H
48 #include <sys/select.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
59 #include <sys/ioctl.h>
60 #if defined(HAVE_SYS_PARAM_H)
61 #include <sys/param.h>
63 #if defined(HAVE_SYS_UCRED_H)
64 #include <sys/ucred.h>
66 #if defined(HAVE_SYS_MOUNT_H)
67 #include <sys/mount.h>
69 #if defined(HAVE_LINUX_FS_H) && !defined(__TINYC__)
73 #define SOCKADDR_MAX_LEN 65535
74 #define SOCKADDR_ALIGN 16
76 #ifndef wake_up_wait_list
77 void u_name(wake_up_wait_list
)(struct list
*wait_list
, mutex_t
*mutex_to_lock
, bool can_allocate_memory
);
78 void c_name(wake_up_wait_list
)(struct list
*wait_list
, mutex_t
*mutex_to_lock
, bool can_allocate_memory
);
81 #if !defined(THREAD_NONE) && defined(USE_SIGPROCMASK) && defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SIGMASK)
83 #define USE_PTHREAD_SIGMASK
86 #ifdef OS_USE_LARGEFILE64_SOURCE
88 #define fstatvfs fstatvfs64
89 #define ftruncate ftruncate64
95 #define pwrite pwrite64
97 #define statvfs statvfs64
98 #define truncate truncate64
101 static rwmutex_t fork_lock
;
102 static bool os_threads_initialized
= false;
104 #if !defined(NO_DIR_HANDLES) && !defined(OS_USE_LARGEFILE64_SOURCE) && defined(O_CLOEXEC) && defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_READLINKAT) && defined(HAVE_UNLINKAT) && defined(HAVE_MKDIRAT) && defined(HAVE_MKNODAT) && defined(HAVE_SYMLINKAT) && defined(HAVE_LINKAT) && defined(HAVE_RENAMEAT) && defined(HAVE_FCHMODAT) && defined(HAVE_FCHOWNAT) && defined(HAVE_UTIMENSAT)
105 static bool have_O_CLOEXEC_openat
= false;
106 #define HAVE_AT_FUNCTIONS
112 #include "os_com.inc"
115 static void os_lock_fork(bool for_write
)
117 if (os_threads_initialized
) {
119 rwmutex_lock_read(&fork_lock
);
121 rwmutex_lock_write(&fork_lock
);
125 static void os_unlock_fork(bool for_write
)
127 if (os_threads_initialized
) {
129 rwmutex_unlock_read(&fork_lock
);
131 rwmutex_unlock_write(&fork_lock
);
135 uint32_t os_get_last_error(void)
140 uint32_t os_get_last_socket_error(void)
147 int os_getpagesize(void)
149 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
152 EINTR_LOOP(ps
, sysconf(_SC_PAGESIZE
));
153 if (unlikely(ps
== -1)) {
155 warning("sysconf(_SC_PAGESIZE) returned error: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
160 #elif defined(HAVE_GETPAGESIZE)
163 EINTR_LOOP(ps
, getpagesize());
164 if (unlikely(ps
== -1)) {
166 warning("getpagesize() returned error: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
175 void *os_mmap(void *ptr
, size_t size
, int prot
, int flags
, int h
, os_off_t off
, ajla_error_t
*err
)
179 prot
|= PROT_MPROTECT(PROT_EXEC
);
181 #ifndef HAVE_MPROTECT
184 EINTR_LOOP_VAL(p
, MAP_FAILED
, mmap(ptr
, size
, prot
, flags
, h
, off
));
185 if (unlikely(p
== MAP_FAILED
)) {
186 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
187 fatal_mayfail(e
, err
, "can't map memory: %s", error_decode(e
));
193 void os_munmap(void *ptr
, size_t size
, bool attr_unused file
)
196 EINTR_LOOP(r
, munmap(ptr
, size
));
197 if (unlikely(r
== -1)) {
199 internal(file_line
, "os_munmap: munmap(%p, %"PRIxMAX
") returned error: %d, %s", ptr
, (uintmax_t)size
, er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
203 bool os_mprotect(void attr_unused
*ptr
, size_t attr_unused size
, int attr_unused prot
, ajla_error_t
*err
)
207 EINTR_LOOP(r
, mprotect(ptr
, size
, prot
));
208 if (unlikely(r
== -1)) {
209 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
210 fatal_mayfail(e
, err
, "can't protect memory: %s", error_decode(e
));
215 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "the system doesn't support mprotect");
221 void *os_mremap(void *old_ptr
, size_t old_size
, size_t new_size
, int flags
, void attr_unused
*new_ptr
, ajla_error_t
*err
)
225 EINTR_LOOP_VAL(p
, MAP_FAILED
, mremap(old_ptr
, old_size
, new_size
, flags
, new_ptr
));
227 EINTR_LOOP_VAL(p
, MAP_FAILED
, mremap(old_ptr
, old_size
, new_size
, flags
));
229 if (unlikely(p
== MAP_FAILED
)) {
230 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
231 fatal_mayfail(e
, err
, "can't remap memory: %s", error_decode(e
));
241 void os_code_invalidate_cache(uint8_t attr_unused
*code
, size_t attr_unused code_size
, bool attr_unused set_exec
)
243 #if defined(ARCH_PARISC) && defined(HAVE_GCC_ASSEMBLER)
245 size_t cl_size
= cpu_test_feature(CPU_FEATURE_pa20
) ? 64 : 16;
246 size_t align
= ptr_to_num(code
) & (cl_size
- 1);
249 __asm__
volatile ("sync" : : : "memory");
250 for (i
= 0; i
< code_size
; i
+= cl_size
) {
251 __asm__
volatile ("fdc %%r0(%0)" : : "r"(code
+ i
) : "memory");
253 __asm__
volatile ("sync");
254 #if defined(ARCH_PARISC32)
257 __asm__
volatile("ldsid (%1), %0\n mtsp %0, %%sr0" : "=r"(reg
) : "r"(code
) : "memory");
260 for (i
= 0; i
< code_size
; i
+= cl_size
) {
261 #if defined(ARCH_PARISC32)
263 __asm__
volatile ("fic %%r0(%%sr0, %0)" : : "r"(code
+ i
) : "memory");
265 __asm__
volatile ("fic %%r0(%%sr4, %0)" : : "r"(code
+ i
) : "memory");
268 __asm__
volatile ("fic %%r0(%0)" : : "r"(code
+ i
) : "memory");
271 __asm__
volatile ("sync" : : : "memory");
272 #elif defined(ARCH_ALPHA)
273 /* imb doesn't work on SMP systems */
274 #elif defined(ARCH_SPARC64) && defined(HAVE_GCC_ASSEMBLER)
276 __asm__
volatile ("membar #StoreStore" : : : "memory");
277 for (i
= 0; i
< code_size
; i
+= 8) {
278 __asm__
volatile ("flush %0" : : "r"(code
+ i
) : "memory");
280 #elif defined(HAVE___BUILTIN___CLEAR_CACHE)
281 __builtin___clear_cache(cast_ptr(void *, code
), cast_ptr(char *, code
) + code_size
);
283 #if defined(OS_HAS_MMAP) && defined(HAVE_MPROTECT)
285 int prot_flags
= PROT_READ
| PROT_EXEC
286 #ifdef CODEGEN_USE_HEAP
290 int page_size
= os_getpagesize();
291 int front_pad
= ptr_to_num(code
) & (page_size
- 1);
292 uint8_t *mem_region
= code
- front_pad
;
293 size_t mem_length
= code_size
+ front_pad
;
294 mem_length
= round_up(mem_length
, page_size
);
295 os_mprotect(mem_region
, mem_length
, prot_flags
, NULL
);
300 void *os_code_map(uint8_t *code
, size_t code_size
, ajla_error_t attr_unused
*err
)
302 #ifdef CODEGEN_USE_HEAP
303 os_code_invalidate_cache(code
, code_size
, !amalloc_enabled
);
306 size_t rounded_size
= round_up(code_size
, os_getpagesize());
307 void *ptr
= os_mmap(NULL
, rounded_size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANONYMOUS
, handle_none
, 0, err
);
308 if (unlikely(ptr
== MAP_FAILED
)) {
312 memcpy(ptr
, code
, code_size
);
313 os_code_invalidate_cache(ptr
, code_size
, true);
319 void os_code_unmap(void *mapped_code
, size_t attr_unused code_size
)
321 #ifdef CODEGEN_USE_HEAP
322 mem_free(mapped_code
);
324 size_t rounded_size
= round_up(code_size
, os_getpagesize());
325 os_munmap(mapped_code
, rounded_size
, false);
330 void os_block_signals(sig_state_t attr_unused
*set
)
332 #ifdef USE_SIGPROCMASK
336 sigdelset(&block
, SIGFPE
);
337 sigdelset(&block
, SIGTRAP
);
338 #ifdef USE_PTHREAD_SIGMASK
339 er
= pthread_sigmask(SIG_BLOCK
, &block
, set
);
341 fatal("pthread_sigmask failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
343 if (unlikely(sigprocmask(SIG_BLOCK
, &block
, set
))) {
345 fatal("sigprocmask failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
348 #elif defined(HAVE_SIGBLOCK) && defined(HAVE_SIGSETMASK)
349 sig_state_t s
= sigblock(~(sigmask(SIGFPE
) | sigmask(SIGTRAP
)));
355 void os_unblock_signals(const sig_state_t attr_unused
*set
)
357 #ifdef USE_SIGPROCMASK
359 #ifdef USE_PTHREAD_SIGMASK
360 er
= pthread_sigmask(SIG_SETMASK
, set
, NULL
);
362 fatal("pthread_sigmask failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
364 if (unlikely(sigprocmask(SIG_SETMASK
, set
, NULL
))) {
366 fatal("sigprocmask failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
369 #elif defined(HAVE_SIGBLOCK) && defined(HAVE_SIGSETMASK)
375 static void os_unblock_all_signals(void)
378 #ifdef USE_SIGPROCMASK
379 sigemptyset(&unblock
);
380 #elif defined(HAVE_SIGBLOCK) && defined(HAVE_SIGSETMASK)
383 os_unblock_signals(&unblock
);
388 void attr_cold
os_stop(void)
391 kill(getpid(), SIGSTOP
);
393 warning("stop not supported");
397 static inline void u_sleep(unsigned us
)
400 tv
.tv_sec
= us
/ 1000000;
401 tv
.tv_usec
= us
% 1000000;
402 select(0, NULL
, NULL
, NULL
, &tv
);
405 void os_background(void)
416 os_block_signals(&set
);
418 EINTR_LOOP(p
, fork());
420 os_unblock_signals(&set
);
425 * Note that this is racy. If we send SIGCONT too
426 * quickly, the ajla process will not be put to
433 os_unlock_fork(true);
438 * Another race - we must not send SIGKILL too quickly
442 EINTR_LOOP(r
, waitpid(p
, NULL
, 0));
446 bool os_foreground(void)
448 int sigttin
, sigttou
;
453 sigttin
= os_signal_handle("SIGTTIN", &seq
, NULL
);
454 sigttou
= os_signal_handle("SIGTTOU", &seq
, NULL
);
455 r
= tcgetattr(0, &tc
);
457 r
= tcsetattr(0, TCSANOW
, &tc
);
458 os_signal_unhandle(sigttin
);
459 os_signal_unhandle(sigttou
);
464 void os_set_cloexec(handle_t h
)
467 EINTR_LOOP(r
, fcntl(h
, F_SETFD
, FD_CLOEXEC
));
468 if (unlikely(r
== -1)) {
470 fatal("fcntl(F_SETFD, FD_CLOEXEC) failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
474 static char *os_call_getcwd(ajla_error_t
*err
)
478 size_t buf_size
= 32;
481 h
= mem_alloc_mayfail(char *, buf_size
, err
);
484 EINTR_LOOP_VAL(r
, NULL
, getcwd(h
, buf_size
));
486 if (errno
== ERANGE
) {
489 if (unlikely(!buf_size
)) {
490 fatal_mayfail(error_ajla(EC_ASYNC
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "overflow when allocating directory buffer");
495 e
= error_from_errno(EC_SYSCALL
, errno
);
496 fatal_mayfail(e
, err
, "can't get working directory: %s", error_decode(e
));
501 if (unlikely(h
[0] != '/')) {
502 e
= error_from_errno(EC_SYSCALL
, ENOENT
);
503 fatal_mayfail(e
, err
, "can't get working directory: %s", error_decode(e
));
512 static dir_handle_t
os_get_cwd(ajla_error_t
*err
)
514 #ifndef NO_DIR_HANDLES
516 #ifdef HAVE_AT_FUNCTIONS
517 if (likely(have_O_CLOEXEC_openat
)) {
518 EINTR_LOOP(h
, open(".", O_RDONLY
| O_CLOEXEC
, 0));
519 if (unlikely(h
== -1)) {
520 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
521 fatal_mayfail(e
, err
, "can't open the current directory: %s", error_decode(e
));
523 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
528 EINTR_LOOP(h
, open(".", O_RDONLY
, 0));
529 if (unlikely(h
== -1)) {
530 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
531 fatal_mayfail(e
, err
, "cam't open the current directory: %s", error_decode(e
));
533 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
539 return os_call_getcwd(err
);
543 bool os_set_cwd(dir_handle_t h
, ajla_error_t
*err
)
545 #ifndef NO_DIR_HANDLES
547 EINTR_LOOP(r
, fchdir(h
));
548 if (unlikely(r
== -1)) {
549 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
550 fatal_mayfail(e
, err
, "can't set directory: %s", error_decode(e
));
555 EINTR_LOOP(r
, chdir(h
));
556 if (unlikely(r
== -1)) {
557 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
558 fatal_mayfail(e
, err
, "can't set directory '%s': %s", h
, error_decode(e
));
565 void os_set_original_cwd(void)
569 if (likely(os_set_cwd(os_cwd
, &sink
)))
571 EINTR_LOOP(r
, chdir("/"));
572 if (unlikely(r
== -1)) {
574 fatal("unable to select root directory: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
578 static handle_t
os_open_internal(dir_handle_t dir
, const char *path
, int flags
, int mode
, bool want_dir
, ajla_error_t
*err
)
581 bool abs_path
= os_path_is_absolute(path
);
583 if (unlikely(!os_test_absolute_path(dir
, abs_path
, err
)))
588 flags
|= O_DIRECTORY
;
591 #ifdef HAVE_AT_FUNCTIONS
592 if (likely(have_O_CLOEXEC_openat
)) {
593 if (!dir_handle_is_valid(dir
)) {
594 EINTR_LOOP(h
, open(path
, flags
| O_CLOEXEC
, mode
));
596 EINTR_LOOP(h
, openat(dir
, path
, flags
| O_CLOEXEC
, mode
));
599 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
601 if (errno
== EACCES
&& want_dir
) {
602 EINTR_LOOP(h
, openat(dir
, path
, flags
| O_CLOEXEC
| O_PATH
, mode
));
607 fatal_mayfail(e
, err
, "can't open file '%s': %s", path
, error_decode(e
));
611 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
616 os_lock_fork(!abs_path
);
619 if (unlikely(!os_set_cwd(dir
, err
))) {
621 goto restore_dir_ret
;
625 EINTR_LOOP(h
, open(path
, flags
, mode
));
626 if (unlikely(h
== -1)) {
627 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
628 fatal_mayfail(e
, err
, "can't open file '%s': %s", path
, error_decode(e
));
629 goto restore_dir_ret
;
631 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
637 os_set_original_cwd();
640 os_unlock_fork(!abs_path
);
642 #ifdef HAVE_AT_FUNCTIONS
645 if (likely(h
!= -1)) {
648 if (!(flags
& (O_WRONLY
| O_RDWR
))) {
649 if (unlikely(!os_fstat(h
, &st
, err
))) {
650 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
651 fatal_mayfail(e
, err
, "fstat on file '%s' failed", path
);
654 } else if (unlikely(S_ISDIR(st
.st_mode
))) {
655 ajla_error_t e
= error_from_errno(EC_SYSCALL
, EISDIR
);
656 fatal_mayfail(e
, err
, "file '%s' is a directory", path
);
663 if (unlikely(!os_fstat(h
, &st
, err
))) {
664 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
665 fatal_mayfail(e
, err
, "fstat on file '%s' failed", path
);
668 } else if (unlikely(!S_ISDIR(st
.st_mode
))) {
669 ajla_error_t e
= error_from_errno(EC_SYSCALL
, ENOTDIR
);
670 fatal_mayfail(e
, err
, "file '%s' is not a directory", path
);
680 handle_t
os_open(dir_handle_t dir
, const char *path
, int flags
, int mode
, ajla_error_t
*err
)
685 return os_open_internal(dir
, path
, flags
, mode
, false, err
);
688 bool os_pipe(handle_t result
[2], int nonblock_flags
, ajla_error_t
*err
)
692 EINTR_LOOP(r
, pipe2(result
, O_CLOEXEC
| (nonblock_flags
== 3 ? O_NONBLOCK
: 0)));
693 if (likely(r
!= -1)) {
694 if (nonblock_flags
== 3) {
695 obj_registry_insert(OBJ_TYPE_HANDLE
, result
[0], file_line
);
696 obj_registry_insert(OBJ_TYPE_HANDLE
, result
[1], file_line
);
701 if (errno
!= ENOSYS
) {
702 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
703 fatal_mayfail(e
, err
, "can't create pipe: %s", error_decode(e
));
709 EINTR_LOOP(r
, pipe(result
));
710 if (unlikely(r
== -1)) {
711 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
712 os_unlock_fork(false);
713 fatal_mayfail(e
, err
, "can't create pipe: %s", error_decode(e
));
716 for (i
= 0; i
< 2; i
++)
717 os_set_cloexec(result
[i
]);
718 os_unlock_fork(false);
723 for (i
= 0; i
< 2; i
++) {
724 obj_registry_insert(OBJ_TYPE_HANDLE
, result
[i
], file_line
);
725 if (nonblock_flags
& (1 << i
)) {
726 EINTR_LOOP(r
, fcntl(result
[i
], F_SETFL
, O_NONBLOCK
));
727 if (unlikely(r
== -1)) {
729 fatal("fcntl(F_SETFL, O_NONBLOCK) on a pipe failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
736 void os_close_handle(handle_t h
)
740 internal(file_line
, "os_close: attempting to close invalid handle %d", h
);
741 EINTR_LOOP(r
, close(h
));
742 if (unlikely(r
== -1) && errno
== EBADF
)
743 internal(file_line
, "os_close: closing invalid handle %d", h
);
746 void os_close(handle_t h
)
748 obj_registry_remove(OBJ_TYPE_HANDLE
, h
, file_line
);
752 static unsigned n_std_handles
;
754 unsigned os_n_std_handles(void)
756 return n_std_handles
;
759 handle_t
os_get_std_handle(unsigned h
)
764 handle_t
os_number_to_handle(uintptr_t n
, bool attr_unused sckt
, ajla_error_t
*err
)
766 if (unlikely(n
!= (uintptr_t)(int)n
) || unlikely((int)n
< 0)) {
767 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), err
, "invalid handle");
770 obj_registry_insert(OBJ_TYPE_HANDLE
, (int)n
, file_line
);
775 static ssize_t
os_rdwr_return(int r
, const char *msg
, ajla_error_t
*err
)
777 if (unlikely(r
== -1)) {
779 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
780 return OS_RW_WOULDBLOCK
;
781 e
= error_from_errno(EC_SYSCALL
, errno
);
782 fatal_mayfail(e
, err
, "error %s data: %s", msg
, error_decode(e
));
788 ssize_t
os_read(handle_t h
, char *buffer
, int size
, ajla_error_t
*err
)
791 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
792 EINTR_LOOP(r
, read(h
, buffer
, size
));
793 return os_rdwr_return(r
, "reading", err
);
796 ssize_t
os_write(handle_t h
, const char *buffer
, int size
, ajla_error_t
*err
)
799 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
800 EINTR_LOOP(r
, write(h
, buffer
, size
));
802 * https://stackoverflow.com/questions/5656628/what-should-i-do-when-writefd-buf-count-returns-0
803 * Long, long ago, pre-POSIX, some systems returned 0 instead of EAGAIN.
805 if (unlikely(!r
) && size
)
806 return OS_RW_WOULDBLOCK
;
807 return os_rdwr_return(r
, "writing", err
);
810 ssize_t
os_pread(handle_t h
, char *buffer
, int size
, os_off_t off
, ajla_error_t
*err
)
813 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
814 #ifndef DO_LOCK_HANDLES
815 EINTR_LOOP(r
, pread(h
, buffer
, size
, off
));
817 address_lock(num_to_ptr(h
), DEPTH_HANDLE
);
818 EINTR_LOOP(off
, lseek(h
, off
, SEEK_SET
));
819 if (unlikely(off
== -1)) {
823 EINTR_LOOP(r
, read(h
, buffer
, size
));
825 address_unlock(num_to_ptr(h
), DEPTH_HANDLE
);
827 return os_rdwr_return(r
, "preading", err
);
830 ssize_t
os_pwrite(handle_t h
, const char *buffer
, int size
, os_off_t off
, ajla_error_t
*err
)
833 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
834 #ifndef DO_LOCK_HANDLES
835 EINTR_LOOP(r
, pwrite(h
, buffer
, size
, off
));
837 address_lock(num_to_ptr(h
), DEPTH_HANDLE
);
838 EINTR_LOOP(off
, lseek(h
, off
, SEEK_SET
));
839 if (unlikely(off
== -1)) {
843 EINTR_LOOP(r
, write(h
, buffer
, size
));
845 address_unlock(num_to_ptr(h
), DEPTH_HANDLE
);
847 return os_rdwr_return(r
, "pwriting", err
);
850 bool os_lseek(handle_t h
, unsigned mode
, os_off_t off
, os_off_t
*result
, ajla_error_t
*err
)
854 #ifdef DO_LOCK_HANDLES
855 address_lock(num_to_ptr(h
), DEPTH_HANDLE
);
872 EINTR_LOOP(res
, lseek(h
, 0, SEEK_END
));
873 if (unlikely(res
== -1))
875 if (unlikely(off
> res
))
889 default:internal(file_line
, "os_lseek: unsupported mode %u", mode
);
892 EINTR_LOOP(res
, lseek(h
, off
, whence
));
893 if (unlikely(res
== -1)) {
895 if (errno
== EINVAL
) {
906 if (errno
== ENXIO
&& mode
>= 3) {
913 e
= error_from_errno(EC_SYSCALL
, errno
);
914 fatal_mayfail(e
, err
, "can't lseek: %s", error_decode(e
));
919 #ifdef DO_LOCK_HANDLES
920 address_unlock(num_to_ptr(h
), DEPTH_HANDLE
);
924 #ifdef DO_LOCK_HANDLES
925 address_unlock(num_to_ptr(h
), DEPTH_HANDLE
);
930 bool os_ftruncate(handle_t h
, os_off_t size
, ajla_error_t
*err
)
933 EINTR_LOOP(r
, ftruncate(h
, size
));
934 if (unlikely(r
== -1)) {
935 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
936 fatal_mayfail(e
, err
, "ftruncate returned an error: %s", error_decode(e
));
942 bool os_fallocate(handle_t attr_unused h
, os_off_t attr_unused position
, os_off_t attr_unused size
, ajla_error_t attr_unused
*err
)
944 #ifdef HAVE_FALLOCATE
948 /* EINTR may cause infinite loop */
952 os_block_signals(&set
);
953 EINTR_LOOP(r
, fallocate(h
, FALLOC_FL_KEEP_SIZE
, position
, size
));
954 os_unblock_signals(&set
);
957 r
= fallocate(h
, FALLOC_FL_KEEP_SIZE
, position
, size
);
958 if (unlikely(r
== -1) && errno
== EINTR
)
959 r
= fallocate(h
, FALLOC_FL_KEEP_SIZE
, position
, size
);
961 if (unlikely(r
== -1) && errno
!= EINTR
&& errno
!= ENOSYS
&& errno
!= EOPNOTSUPP
) {
962 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
963 fatal_mayfail(e
, err
, "fallocate returned an error: %s", error_decode(e
));
970 bool os_clone_range(handle_t attr_unused src_h
, os_off_t attr_unused src_pos
, handle_t attr_unused dst_h
, os_off_t attr_unused dst_pos
, os_off_t attr_unused len
, ajla_error_t
*err
)
974 struct file_clone_range c
;
976 c
.src_offset
= src_pos
;
978 c
.dest_offset
= dst_pos
;
979 EINTR_LOOP(r
, ioctl(dst_h
, FICLONERANGE
, &c
));
980 if (unlikely(r
== -1)) {
981 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
982 fatal_mayfail(e
, err
, "clone range returned an error: %s", error_decode(e
));
987 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "clone not supported");
990 bool os_fsync(handle_t h
, unsigned mode
, ajla_error_t
*err
)
994 if (mode
== 0 || mode
== 1) {
995 EINTR_LOOP(r
, fcntl(h
, F_FULLFSYNC
));
1000 #if defined(HAVE_FDATASYNC) && !defined(__APPLE__)
1002 EINTR_LOOP(r
, fdatasync(h
));
1006 if (mode
== 0 || mode
== 1) {
1007 EINTR_LOOP(r
, fsync(h
));
1012 EINTR_LOOP(r
, syncfs(h
));
1016 if (mode
== 2 || mode
== 3) {
1020 internal(file_line
, "os_fsync: invalid mode %u", mode
);
1022 if (unlikely(r
== -1)) {
1023 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1024 fatal_mayfail(e
, err
, "fsync returned an error: %s", error_decode(e
));
1030 #if !defined(OS_DOS)
1031 ssize_t
os_read_console_packet(handle_t attr_unused h
, struct console_read_packet attr_unused
*result
, ajla_error_t
*err
)
1033 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "console packets not supported");
1037 bool os_write_console_packet(handle_t attr_unused h
, struct console_write_packet attr_unused
*packet
, ajla_error_t
*err
)
1039 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "console packets not supported");
1043 dir_handle_t
os_dir_root(ajla_error_t
*err
)
1045 const char *root
= "/";
1046 #ifndef NO_DIR_HANDLES
1047 return os_dir_open(dir_none
, root
, 0, err
);
1049 return str_dup(root
, -1, err
);
1054 dir_handle_t
os_dir_cwd(ajla_error_t
*err
)
1056 return os_dir_open(os_cwd
, ".", 0, err
);
1059 dir_handle_t
os_dir_open(dir_handle_t dir
, const char *path
, int attr_unused flags
, ajla_error_t
*err
)
1061 #ifndef NO_DIR_HANDLES
1062 return os_open_internal(dir
, path
, O_RDONLY
| flags
, 0, true, err
);
1066 if (unlikely(!os_test_absolute_path(dir
, os_path_is_absolute(path
), err
)))
1071 if (dir_handle_is_valid(dir
)) {
1072 if (unlikely(!os_set_cwd(dir
, err
))) {
1078 if (unlikely(!os_set_cwd((dir_handle_t
)path
, err
))) {
1083 ret
= os_get_cwd(err
);
1086 os_set_original_cwd();
1088 os_unlock_fork(true);
1093 void os_dir_close(dir_handle_t h
)
1095 #ifndef NO_DIR_HANDLES
1102 char *os_dir_path(dir_handle_t h
, ajla_error_t
*err
)
1104 #ifndef NO_DIR_HANDLES
1109 snprintf(lnk
, sizeof(lnk
), "/proc/self/fd/%u", h
);
1110 path
= os_readlink(dir_none
, lnk
, &sink
);
1111 if (likely(path
!= NULL
)) {
1113 char *deleted
= " (deleted)";
1114 if (unlikely(path
[0] != '/')) {
1116 goto skip_optimization
;
1119 dl
= strlen(deleted
);
1120 if (sl
>= dl
&& unlikely(!memcmp(path
+ sl
- dl
, deleted
, dl
))) {
1122 goto skip_optimization
;
1129 if (unlikely(!os_set_cwd(h
, err
))) {
1133 path
= os_call_getcwd(err
);
1134 os_set_original_cwd();
1136 os_unlock_fork(true);
1139 return str_dup(h
, -1, err
);
1143 static void os_close_DIR(DIR *d
)
1146 EINTR_LOOP(r
, closedir(d
));
1148 internal(file_line
, "os_close_DIR: closing invalid directory handle: %s", error_decode(error_from_errno(EC_SYSCALL
, errno
)));
1151 bool os_dir_read(dir_handle_t h
, char ***files
, size_t *n_files
, ajla_error_t
*err
)
1155 #if !defined(NO_DIR_HANDLES)
1158 if (unlikely(!os_set_cwd(h
, err
))) {
1159 os_set_original_cwd();
1160 os_unlock_fork(true);
1163 EINTR_LOOP_VAL(d
, NULL
, opendir("."));
1165 os_set_original_cwd();
1166 os_unlock_fork(true);
1169 EINTR_LOOP_VAL(d
, NULL
, opendir(h
));
1172 e
= error_from_errno(EC_SYSCALL
, errno
);
1173 fatal_mayfail(e
, err
, "can't open directory: %s", error_decode(e
));
1176 if (unlikely(!array_init_mayfail(char *, files
, n_files
, err
))) {
1186 if (unlikely(!de
)) {
1189 e
= error_from_errno(EC_SYSCALL
, errno
);
1190 fatal_mayfail(e
, err
, "error reading directory directory: %s", error_decode(e
));
1191 os_dir_free(*files
, *n_files
);
1195 if (unlikely(!strcmp(de
->d_name
, ".")) ||
1196 unlikely(!strcmp(de
->d_name
, "..")))
1198 fn
= mem_alloc_mayfail(char *, strlen(de
->d_name
) + 1, err
);
1199 if (unlikely(!fn
)) {
1200 os_dir_free(*files
, *n_files
);
1204 strcpy(fn
, de
->d_name
);
1205 array_add(char *, files
, n_files
, fn
);
1211 void os_dir_free(char **files
, size_t n_files
)
1214 for (i
= 0; i
< n_files
; i
++)
1220 unsigned os_dev_t_major(dev_t dev
)
1222 #if defined(HAVE_SYS_SYSMACROS_H) || defined(major)
1225 return (dev
>> 8) & 0xff;
1229 unsigned os_dev_t_minor(dev_t dev
)
1231 #if defined(HAVE_SYS_SYSMACROS_H) || defined(minor)
1238 bool os_fstat(handle_t h
, os_stat_t
*st
, ajla_error_t
*err
)
1241 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
1242 EINTR_LOOP(r
, fstat(h
, st
));
1243 if (unlikely(r
== -1)) {
1245 if (unlikely(errno
== EBADF
))
1246 internal(file_line
, "os_fstat: invalid handle %d", h
);
1247 e
= error_from_errno(EC_SYSCALL
, errno
);
1248 fatal_mayfail(e
, err
, "can't stat file handle: %s", error_decode(e
));
1254 bool os_stat(dir_handle_t dir
, const char *path
, bool attr_unused lnk
, os_stat_t
*st
, ajla_error_t
*err
)
1257 bool abs_path
= os_path_is_absolute(path
);
1259 if (unlikely(!os_test_absolute_path(dir
, abs_path
, err
)))
1262 #ifdef HAVE_AT_FUNCTIONS
1263 if (likely(have_O_CLOEXEC_openat
) && dir_handle_is_valid(dir
)) {
1264 EINTR_LOOP(r
, fstatat(dir
, path
, st
, lnk
? AT_SYMLINK_NOFOLLOW
: 0));
1265 if (unlikely(r
== -1)) {
1266 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1267 fatal_mayfail(e
, err
, "can't open file '%s': %s", path
, error_decode(e
));
1274 if (unlikely(!os_set_cwd(dir
, err
))) {
1281 EINTR_LOOP(r
, (!lnk
? stat
: lstat
)(path
, st
));
1283 EINTR_LOOP(r
, stat(path
, st
));
1285 if (unlikely(r
== -1)) {
1286 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1287 fatal_mayfail(e
, err
, "can't open file '%s': %s", path
, error_decode(e
));
1292 os_set_original_cwd();
1293 os_unlock_fork(true);
1299 #if (defined(HAVE_FSTATFS) && !defined(HAVE_FSTATVFS)) || (defined(HAVE_STATFS) && !defined(HAVE_STATVFS))
1300 static inline void attr_unused
statfs_2_statvfs(struct statfs
*stfs
, os_statvfs_t
*st
)
1302 memset(st
, 0, sizeof(os_statvfs_t
));
1303 #if defined(__linux__)
1304 st
->f_bsize
= stfs
->f_bsize
;
1305 st
->f_frsize
= stfs
->f_bsize
;
1306 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
1307 st
->f_bsize
= stfs
->f_iosize
;
1308 st
->f_frsize
= stfs
->f_bsize
;
1310 st
->f_bsize
= stfs
->f_bsize
;
1311 st
->f_frsize
= stfs
->f_bsize
;
1313 st
->f_blocks
= stfs
->f_blocks
;
1314 st
->f_bfree
= stfs
->f_bfree
;
1315 st
->f_bavail
= stfs
->f_bavail
;
1316 st
->f_files
= stfs
->f_files
;
1317 st
->f_ffree
= stfs
->f_ffree
;
1318 st
->f_favail
= stfs
->f_ffree
;
1319 memcpy(&st
->f_fsid
, &stfs
->f_fsid
, minimum(sizeof(st
->f_fsid
), sizeof(stfs
->f_fsid
)));
1320 #if defined(__linux__)
1321 st
->f_namemax
= stfs
->f_namelen
;
1322 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
1323 st
->f_namemax
= stfs
->f_namemax
;
1325 st
->f_namemax
= 255;
1330 bool os_fstatvfs(handle_t h
, os_statvfs_t
*st
, ajla_error_t
*err
)
1334 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
1335 #if defined(HAVE_FSTATVFS)
1336 EINTR_LOOP(r
, fstatvfs(h
, st
));
1337 if (unlikely(r
== -1))
1340 #elif defined(HAVE_FSTATFS)
1343 EINTR_LOOP(r
, fstatfs(h
, &stfs
));
1344 if (unlikely(r
== -1))
1346 statfs_2_statvfs(&stfs
, st
);
1350 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "the system doesn't support mprotect");
1355 if (unlikely(errno
== EBADF
))
1356 internal(file_line
, "os_fstatvfs: invalid handle %d", h
);
1357 e
= error_from_errno(EC_SYSCALL
, errno
);
1358 fatal_mayfail(e
, err
, "can't fstatvfs file handle: %s", error_decode(e
));
1362 bool os_dstatvfs(dir_handle_t dir
, os_statvfs_t
*st
, ajla_error_t
*err
)
1364 ajla_error_t attr_unused e
;
1366 #ifndef NO_DIR_HANDLES
1367 return os_fstatvfs(dir
, st
, err
);
1368 #elif defined(HAVE_STATVFS)
1369 EINTR_LOOP(r
, statvfs(dir
, st
));
1370 if (unlikely(r
== -1))
1373 #elif defined(HAVE_STATFS)
1376 EINTR_LOOP(r
, statfs(dir
, &stfs
));
1377 if (unlikely(r
== -1))
1379 statfs_2_statvfs(&stfs
, st
);
1383 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "the system doesn't support mprotect");
1388 e
= error_from_errno(EC_SYSCALL
, errno
);
1389 fatal_mayfail(e
, err
, "can't statvfs directory: %s", error_decode(e
));
1393 char *os_readlink(dir_handle_t attr_unused dir
, const char attr_unused
*path
, ajla_error_t
*err
)
1395 #ifdef HAVE_READLINK
1396 size_t buf_size
= 32;
1399 bool abs_path
= os_path_is_absolute(path
);
1401 if (unlikely(!os_test_absolute_path(dir
, abs_path
, err
)))
1405 buf
= mem_alloc_mayfail(char *, buf_size
, err
);
1409 #ifdef HAVE_AT_FUNCTIONS
1410 if (likely(have_O_CLOEXEC_openat
)) {
1411 EINTR_LOOP(r
, readlinkat(dir
, path
, buf
, buf_size
));
1417 if (unlikely(!os_set_cwd(dir
, err
))) {
1418 os_unlock_fork(true);
1424 EINTR_LOOP(r
, readlink(path
, buf
, buf_size
));
1428 os_set_original_cwd();
1429 os_unlock_fork(true);
1433 #ifdef HAVE_AT_FUNCTIONS
1436 if (unlikely(r
== -1)) {
1437 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1438 fatal_mayfail(e
, err
, "can't read link '%s': %s", path
, error_decode(e
));
1442 if (unlikely((size_t)r
== buf_size
)) {
1445 if (unlikely((buf_size
* 2) == 0)) {
1446 fatal_mayfail(error_ajla(EC_ASYNC
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "overflow when allocating readlink buffer");
1456 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "readlink not supported");
1461 bool os_dir_action(dir_handle_t dir
, const char *path
, int action
, int mode
, ajla_time_t attr_unused dev_major
, ajla_time_t attr_unused dev_minor
, const char *syml
, ajla_error_t
*err
)
1464 bool abs_path
= os_path_is_absolute(path
);
1466 if (unlikely((mode
& ~07777) != 0)) {
1467 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), err
, "invalid mode: %d", mode
);
1471 if (unlikely(!os_test_absolute_path(dir
, abs_path
, err
)))
1474 #ifdef HAVE_AT_FUNCTIONS
1475 if (likely(have_O_CLOEXEC_openat
)) {
1476 if (!dir_handle_is_valid(dir
))
1480 EINTR_LOOP(r
, unlinkat(dir
, path
, 0));
1482 case IO_Action_Rm_Dir
:
1483 EINTR_LOOP(r
, unlinkat(dir
, path
, AT_REMOVEDIR
));
1485 case IO_Action_Mk_Dir
:
1486 EINTR_LOOP(r
, mkdirat(dir
, path
, mode
));
1488 case IO_Action_Mk_Pipe
:
1489 EINTR_LOOP(r
, mknodat(dir
, path
, mode
| S_IFIFO
, 0));
1491 case IO_Action_Mk_Socket
:
1492 EINTR_LOOP(r
, mknodat(dir
, path
, mode
| S_IFSOCK
, 0));
1494 case IO_Action_Mk_CharDev
:
1495 #if defined(HAVE_SYS_SYSMACROS_H) || defined(makedev)
1496 EINTR_LOOP(r
, mknodat(dir
, path
, mode
| S_IFCHR
, makedev(dev_major
, dev_minor
)));
1498 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkchardev not supported");
1502 case IO_Action_Mk_BlockDev
:
1503 #if defined(HAVE_SYS_SYSMACROS_H) || defined(makedev)
1504 EINTR_LOOP(r
, mknodat(dir
, path
, mode
| S_IFBLK
, makedev(dev_major
, dev_minor
)));
1506 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkblockdev not supported");
1510 case IO_Action_Mk_SymLink
:
1511 EINTR_LOOP(r
, symlinkat(syml
, dir
, path
));
1513 case IO_Action_ChMod
:
1514 EINTR_LOOP(r
, fchmodat(dir
, path
, mode
, 0));
1516 case IO_Action_ChOwn
:
1517 EINTR_LOOP(r
, fchownat(dir
, path
, dev_major
, dev_minor
, 0));
1519 case IO_Action_LChOwn
:
1520 EINTR_LOOP(r
, fchownat(dir
, path
, dev_major
, dev_minor
, AT_SYMLINK_NOFOLLOW
));
1522 case IO_Action_UTime
:
1523 case IO_Action_LUTime
: {
1524 struct timespec ts
[2];
1525 ts
[0].tv_sec
= dev_minor
/ 1000000;
1526 ts
[0].tv_nsec
= dev_minor
% 1000000 * 1000;
1527 ts
[1].tv_sec
= dev_major
/ 1000000;
1528 ts
[1].tv_nsec
= dev_major
% 1000000 * 1000;
1529 EINTR_LOOP(r
, utimensat(dir
, path
, ts
, action
== IO_Action_UTime
? 0 : AT_SYMLINK_NOFOLLOW
));
1533 internal(file_line
, "os_dir_action: invalid action %d", action
);
1541 if (unlikely(!os_set_cwd(dir
, err
))) {
1542 os_unlock_fork(true);
1549 EINTR_LOOP(r
, unlink(path
));
1551 case IO_Action_Rm_Dir
:
1552 EINTR_LOOP(r
, rmdir(path
));
1554 case IO_Action_Mk_Dir
:
1555 EINTR_LOOP(r
, mkdir(path
, mode
));
1558 * Minix 3 returns EACCES when attempting to make the
1559 * home directory. So we test if the directory exists
1560 * and return EEXIST if it does.
1562 if (r
== -1 && errno
== EACCES
) {
1565 EINTR_LOOP(rr
, stat(path
, &st
));
1573 case IO_Action_Mk_Pipe
:
1575 EINTR_LOOP(r
, mknod(path
, mode
| S_IFIFO
, 0));
1577 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkpipe not supported");
1581 case IO_Action_Mk_Socket
:
1582 #if defined(HAVE_MKNOD) && defined(S_IFSOCK)
1583 EINTR_LOOP(r
, mknod(path
, mode
| S_IFSOCK
, 0));
1585 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mksocket not supported");
1589 case IO_Action_Mk_CharDev
:
1590 #if defined(HAVE_MKNOD) && (defined(HAVE_SYS_SYSMACROS_H) || defined(makedev))
1591 EINTR_LOOP(r
, mknod(path
, mode
| S_IFCHR
, makedev(dev_major
, dev_minor
)));
1593 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkchardev not supported");
1597 case IO_Action_Mk_BlockDev
:
1598 #if defined(HAVE_MKNOD) && (defined(HAVE_SYS_SYSMACROS_H) || defined(makedev))
1599 EINTR_LOOP(r
, mknod(path
, mode
| S_IFBLK
, makedev(dev_major
, dev_minor
)));
1601 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkblockdev not supported");
1605 case IO_Action_Mk_SymLink
:
1607 EINTR_LOOP(r
, symlink(syml
, path
));
1609 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "symlink not supported");
1613 case IO_Action_ChMod
:
1614 EINTR_LOOP(r
, chmod(path
, mode
));
1616 case IO_Action_LChOwn
: {
1618 EINTR_LOOP(r
, lchown(path
, dev_major
, dev_minor
));
1622 EINTR_LOOP(r
, lstat(path
, &st
));
1625 if (S_ISLNK(st
.st_mode
))
1630 case IO_Action_ChOwn
:
1632 EINTR_LOOP(r
, chown(path
, dev_major
, dev_minor
));
1634 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "chown not supported");
1638 case IO_Action_LUTime
: {
1640 EINTR_LOOP(r
, lstat(path
, &st
));
1643 if (S_ISLNK(st
.st_mode
)) {
1650 case IO_Action_UTime
: {
1651 #if defined(HAVE_UTIMES)
1652 struct timeval ts
[2];
1653 ts
[0].tv_sec
= dev_minor
/ 1000000;
1654 ts
[0].tv_usec
= dev_minor
% 1000000;
1655 ts
[1].tv_sec
= dev_major
/ 1000000;
1656 ts
[1].tv_usec
= dev_major
% 1000000;
1657 EINTR_LOOP(r
, utimes(cast_ptr(char *, path
), ts
));
1659 #elif defined(HAVE_UTIME)
1661 tm
.actime
= dev_minor
/ 1000000;
1662 tm
.modtime
= dev_major
/ 1000000;
1663 EINTR_LOOP(r
, times(path
, &tm
));
1666 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "utime not supported");
1670 internal(file_line
, "os_dir_action: invalid action %d", action
);
1675 os_set_original_cwd();
1676 os_unlock_fork(true);
1680 #ifdef HAVE_AT_FUNCTIONS
1683 if (unlikely(r
== -1)) {
1684 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1685 fatal_mayfail(e
, err
, "can't perform action %d on '%s': %s", action
, path
, error_decode(e
));
1693 os_set_original_cwd();
1694 os_unlock_fork(true);
1700 bool os_dir2_action(dir_handle_t dest_dir
, const char *dest_path
, int action
, dir_handle_t src_dir
, const char *src_path
, ajla_error_t
*err
)
1704 char *dest_final_path
= NULL
;
1705 char *src_final_path
= NULL
;
1706 bool abs_dest_path
= os_path_is_absolute(dest_path
);
1707 bool abs_src_path
= os_path_is_absolute(src_path
);
1709 if (unlikely(!os_test_absolute_path(dest_dir
, abs_dest_path
, err
)))
1711 if (unlikely(!os_test_absolute_path(src_dir
, abs_src_path
, err
)))
1714 #ifdef HAVE_AT_FUNCTIONS
1715 if (likely(have_O_CLOEXEC_openat
)) {
1716 if (!dir_handle_is_valid(dest_dir
))
1717 dest_dir
= AT_FDCWD
;
1718 if (!dir_handle_is_valid(src_dir
))
1721 case IO_Action_Mk_Link
:
1722 EINTR_LOOP(r
, linkat(src_dir
, src_path
, dest_dir
, dest_path
, 0));
1724 case IO_Action_Rename
:
1725 EINTR_LOOP(r
, renameat(src_dir
, src_path
, dest_dir
, dest_path
));
1728 internal(file_line
, "os_dir2_action: invalid action %d", action
);
1734 if (abs_dest_path
) {
1735 dest_final_path
= str_dup(dest_path
, -1, err
);
1736 if (unlikely(!dest_final_path
)) {
1741 char *dest_dir_path
= os_dir_path(dest_dir
, err
);
1742 if (unlikely(!dest_dir_path
)) {
1746 dest_final_path
= os_join_paths(dest_dir_path
, dest_path
, true, err
);
1747 if (unlikely(!dest_final_path
)) {
1748 mem_free(dest_dir_path
);
1752 mem_free(dest_dir_path
);
1753 dest_dir_path
= NULL
;
1756 src_final_path
= str_dup(src_path
, -1, err
);
1757 if (unlikely(!src_final_path
)) {
1762 char *src_dir_path
= os_dir_path(src_dir
, err
);
1763 if (unlikely(!src_dir_path
)) {
1767 src_final_path
= os_join_paths(src_dir_path
, src_path
, true, err
);
1768 if (unlikely(!src_final_path
)) {
1769 mem_free(src_dir_path
);
1773 mem_free(src_dir_path
);
1774 src_dir_path
= NULL
;
1778 case IO_Action_Mk_Link
:
1780 EINTR_LOOP(r
, link(src_final_path
, dest_final_path
));
1782 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "link not supported");
1787 case IO_Action_Rename
:
1788 EINTR_LOOP(r
, rename(src_final_path
, dest_final_path
));
1791 internal(file_line
, "os_dir2_action: invalid action %d", action
);
1795 #ifdef HAVE_AT_FUNCTIONS
1798 if (unlikely(r
== -1)) {
1799 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1800 fatal_mayfail(e
, err
, "can't perform action %d on '%s' and '%s': %s", action
, src_path
, dest_path
, error_decode(e
));
1807 if (dest_final_path
)
1808 mem_free(dest_final_path
);
1810 mem_free(src_final_path
);
1814 #if !defined(OS_DOS)
1816 bool os_drives(char **drives
, size_t *drives_l
, ajla_error_t
*err
)
1818 #if defined(OS_CYGWIN)
1819 uint32_t mask
= GetLogicalDrives();
1820 return os_drives_bitmap(mask
, drives
, drives_l
, err
);
1821 #elif defined(HAVE_GETFSSTAT) || defined(HAVE_GETVFSFSSTAT)
1824 #if defined(HAVE_GETVFSSTAT)
1825 struct statvfs
*buf
;
1832 #if defined(HAVE_GETVFSSTAT)
1833 buf
= mem_alloc_array_mayfail(mem_alloc_mayfail
, struct statvfs
*, 0, 0, n_entries
, sizeof(struct statvfs
), err
);
1835 buf
= mem_alloc_array_mayfail(mem_alloc_mayfail
, struct statfs
*, 0, 0, n_entries
, sizeof(struct statfs
), err
);
1839 #if defined(HAVE_GETVFSSTAT)
1840 EINTR_LOOP(r
, getvfsstat(buf
, sizeof(struct statvfs
) * n_entries
, ST_NOWAIT
));
1842 EINTR_LOOP(r
, getfsstat(buf
, sizeof(struct statfs
) * n_entries
, MNT_NOWAIT
));
1844 if (unlikely(r
== -1)) {
1845 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1846 fatal_mayfail(e
, err
, "getfsstat failed: %s", error_decode(e
));
1850 if (r
>= n_entries
) {
1853 if (unlikely(n_entries
< 0)) {
1854 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "getfsstat buffer overflow");
1860 if (unlikely(!array_init_mayfail(char, drives
, drives_l
, err
))) {
1865 for (i
= 0; i
< r
; i
++) {
1868 if (buf
[i
].f_blocks
<= 2)
1870 str
= buf
[i
].f_mntonname
;
1871 str_l
= strlen(str
) + 1;
1872 if (unlikely(!array_add_multiple_mayfail(char, drives
, drives_l
, str
, str_l
, NULL
, err
))) {
1881 if (unlikely(!array_init_mayfail(char, drives
, drives_l
, err
)))
1890 bool os_tcgetattr(handle_t h
, os_termios_t
*t
, ajla_error_t
*err
)
1893 EINTR_LOOP(r
, tcgetattr(h
, t
));
1894 if (unlikely(r
== -1)) {
1895 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1896 fatal_mayfail(e
, err
, "tcgetattr failed: %s", error_decode(e
));
1902 bool os_tcsetattr(handle_t h
, const os_termios_t
*t
, ajla_error_t
*err
)
1905 EINTR_LOOP(r
, tcsetattr(h
, TCSANOW
, cast_ptr(os_termios_t
*, t
)));
1906 if (unlikely(r
== -1)) {
1907 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1908 fatal_mayfail(e
, err
, "tcsetattr failed: %s", error_decode(e
));
1914 void os_tcflags(os_termios_t
*t
, int flags
)
1916 if (flags
& IO_Stty_Flag_Raw
) {
1917 #ifdef HAVE_CFMAKERAW
1921 t
->c_iflag
&= ~(IGNBRK
|BRKINT
|PARMRK
|ISTRIP
|INLCR
|IGNCR
|ICRNL
|IXON
);
1922 t
->c_oflag
&= ~OPOST
;
1923 t
->c_lflag
&= ~(ECHO
|ECHONL
|ICANON
|ISIG
|IEXTEN
);
1924 t
->c_cflag
&= ~(CSIZE
|PARENB
);
1930 if (flags
& IO_Stty_Flag_Noecho
)
1931 t
->c_lflag
&= ~ECHO
;
1934 if (flags
& IO_Stty_Flag_Nosignal
)
1935 t
->c_lflag
&= ~ISIG
;
1938 if (flags
& IO_Stty_Flag_NoCRLF
)
1939 t
->c_oflag
&= ~OPOST
;
1941 t
->c_oflag
|= OPOST
;
1944 bool os_tty_size(handle_t h
, int *nx
, int *ny
, int *ox
, int *oy
, ajla_error_t
*err
)
1948 signal_seq_t attr_unused seq
;
1950 EINTR_LOOP(r
, ioctl(h
, TIOCGWINSZ
, &ws
));
1951 if (unlikely(r
== -1)) {
1952 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1953 fatal_mayfail(e
, err
, "ioctl(TIOCGWINSZ) failed: %s", error_decode(e
));
1966 static char *os_path_to_exe
;
1968 static void os_init_path_to_exe(void)
1971 char *path
, *component
, *test_path
;
1976 char *ptexe
= os_readlink(dir_none
, "/proc/self/exe", &sink
);
1977 if (likely(ptexe
!= NULL
)) {
1978 if (likely(ptexe
[0] == '/')) {
1980 for (i
= 0; ptexe
[i
]; i
++)
1981 if (unlikely(os_is_path_separator(ptexe
[i
])))
1984 os_path_to_exe
= ptexe
;
1991 for (i
= 0; arg0
[i
]; i
++)
1992 if (unlikely(os_is_path_separator(arg0
[i
])))
1995 component
= str_dup(arg0
, sep
, NULL
);
1999 path
= getenv("PATH");
2001 component
= str_dup(".", -1, NULL
);
2006 while (path
[i
] && !os_is_env_separator(path
[i
]))
2008 component
= str_dup(path
, i
, NULL
);
2009 test_path
= os_join_paths(component
, arg0
, true, NULL
);
2010 if (os_stat(os_cwd
, test_path
, false, &st
, &sink
)) {
2011 mem_free(test_path
);
2014 mem_free(test_path
);
2015 mem_free(component
);
2018 goto next_component
;
2020 warning("could not find executable in path");
2021 component
= str_dup(".", -1, NULL
);
2023 if (os_path_is_absolute(component
)) {
2024 os_path_to_exe
= component
;
2027 dh
= os_dir_open(os_cwd
, component
, 0, NULL
);
2028 os_path_to_exe
= os_dir_path(dh
, NULL
);
2030 mem_free(component
);
2033 const char *os_get_path_to_exe(void)
2035 return os_path_to_exe
;
2039 ajla_time_t
os_time_t_to_ajla_time(time_t sec
)
2041 return (ajla_time_t
)sec
* 1000000;
2044 static ajla_time_t
os_timeval_to_ajla_time(const struct timeval
*tv
)
2046 return os_time_t_to_ajla_time(tv
->tv_sec
) + tv
->tv_usec
;
2049 #ifdef HAVE_STRUCT_TIMESPEC
2050 ajla_time_t
os_timespec_to_ajla_time(const struct timespec
*ts
)
2052 return os_time_t_to_ajla_time(ts
->tv_sec
) + ts
->tv_nsec
/ 1000;
2056 ajla_time_t
os_time_real(void)
2060 EINTR_LOOP(r
, gettimeofday(&tv
, NULL
));
2061 if (unlikely(r
== -1)) {
2063 fatal("gettimeofday failed: %d, %s", e
, error_decode(error_from_errno(EC_SYSCALL
, e
)));
2065 return os_timeval_to_ajla_time(&tv
);
2068 ajla_time_t
os_time_monotonic(void)
2070 #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
2073 EINTR_LOOP(r
, clock_gettime(CLOCK_MONOTONIC
, &ts
));
2074 if (unlikely(r
== -1)) {
2076 fatal("clock_gettime(%d) failed: %d, %s", (int)CLOCK_MONOTONIC
, e
, error_decode(error_from_errno(EC_SYSCALL
, e
)));
2078 return os_timespec_to_ajla_time(&ts
);
2080 return os_time_real();
2085 #if !defined(OS_DOS)
2087 static bool spawn_process_handles(unsigned n_handles
, handle_t
*src
, int *target
)
2091 handle_t max_handle
= 3;
2092 for (i
= 0; i
< n_handles
; i
++) {
2093 if (unlikely(src
[i
] >= signed_maximum(int) / 2) ||
2094 unlikely(target
[i
] >= signed_maximum(int) / 2))
2096 if (src
[i
] >= max_handle
) max_handle
= src
[i
] + 1;
2097 if (target
[i
] >= max_handle
) max_handle
= target
[i
] + 1;
2099 for (i
= 0; i
< n_handles
; i
++) {
2100 EINTR_LOOP(r
, dup2(src
[i
], max_handle
+ i
));
2101 if (unlikely(r
== -1))
2103 /*os_close_handle(src[i]);*/
2105 for (i
= 0; i
< n_handles
; i
++) {
2106 EINTR_LOOP(r
, close(src
[i
]));
2108 EINTR_LOOP(r
, close(0));
2109 EINTR_LOOP(r
, close(1));
2110 EINTR_LOOP(r
, close(2));
2111 for (i
= 0; i
< n_handles
; i
++) {
2112 EINTR_LOOP(r
, dup2(max_handle
+ i
, target
[i
]));
2113 if (unlikely(r
== -1))
2115 os_close_handle(max_handle
+ i
);
2117 for (i
= 0; i
< n_handles
; i
++) {
2118 EINTR_LOOP(r
, fcntl(target
[i
], F_GETFL
));
2119 if (likely(r
>= 0) && r
& O_NONBLOCK
) {
2122 EINTR_LOOP(ir
, fcntl(target
[i
], F_SETFL
, r
));
2128 static bool os_fork(dir_handle_t wd
, const char *path
, unsigned n_handles
, handle_t
*src
, int *target
, char * const args
[], char * const env
[], pid_t
*pid
, ajla_error_t
*err
)
2137 os_block_signals(&set
);
2139 EINTR_LOOP(p
, fork());
2141 os_unblock_signals(&set
);
2145 if (unlikely(!os_set_cwd(wd
, &sink
)))
2147 if (unlikely(!spawn_process_handles(n_handles
, src
, target
)))
2149 os_unblock_all_signals();
2150 EINTR_LOOP(r
, execve(path
, args
, env
));
2153 os_unlock_fork(true);
2155 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2156 fatal_mayfail(e
, err
, "can't spawn process '%s': %s", path
, error_decode(e
));
2163 struct proc_handle
{
2164 struct tree_entry entry
;
2170 struct list wait_list
;
2173 static struct tree proc_tree
;
2174 static mutex_t proc_tree_mutex
;
2176 static inline void proc_lock(void)
2178 mutex_lock(&proc_tree_mutex
);
2181 static inline void proc_unlock(void)
2183 mutex_unlock(&proc_tree_mutex
);
2186 static void proc_handle_free(struct proc_handle
*ph
)
2188 os_signal_unhandle(ph
->sigchld
);
2192 static int proc_handle_compare(const struct tree_entry
*e
, uintptr_t pid
)
2194 const struct proc_handle
*ph
= get_struct(e
, struct proc_handle
, entry
);
2195 if (unlikely(ph
->pid
== (pid_t
)pid
)) return 0;
2196 if (ph
->pid
> (pid_t
)pid
) return 1;
2200 struct proc_handle
*os_proc_spawn(dir_handle_t wd
, const char *path
, size_t n_handles
, handle_t
*src
, int *target
, char * const args
[], char *envc
, ajla_error_t
*err
)
2202 struct proc_handle
*ph
;
2204 struct tree_insert_position ins
;
2205 struct tree_entry
*e
;
2210 if (unlikely(!array_init_mayfail(char *, &env
, &env_l
, err
)))
2213 if (unlikely(!array_add_mayfail(char *, &env
, &env_l
, envc
, NULL
, err
)))
2215 envc
= strchr(envc
, 0) + 1;
2217 if (unlikely(!array_add_mayfail(char *, &env
, &env_l
, NULL
, NULL
, err
)))
2220 ph
= mem_alloc_mayfail(struct proc_handle
*, sizeof(struct proc_handle
), err
);
2221 if (unlikely(!ph
)) {
2226 ph
->detached
= false;
2227 list_init(&ph
->wait_list
);
2228 ph
->sigchld
= os_signal_handle("SIGCHLD", &seq
, err
);
2229 if (unlikely(ph
->sigchld
< 0)) {
2234 if (unlikely(!ph
->sigchld
))
2235 iomux_enable_poll();
2239 if (unlikely(!os_fork(wd
, path
, n_handles
, src
, target
, args
, env
, &ph
->pid
, err
))) {
2242 proc_handle_free(ph
);
2246 e
= tree_find_for_insert(&proc_tree
, proc_handle_compare
, ph
->pid
, &ins
);
2247 if (unlikely(e
!= NULL
)) {
2248 fatal("pid %ld is already present in the tree", (long)ph
->pid
);
2251 tree_insert_after_find(&ph
->entry
, &ins
);
2260 void os_proc_free_handle(struct proc_handle
*ph
)
2263 ajla_assert_lo(list_is_empty(&ph
->wait_list
), (file_line
, "os_proc_free_handle: freeing handle when there are processes waiting for it"));
2266 proc_handle_free(ph
);
2268 ph
->detached
= true;
2273 bool os_proc_register_wait(struct proc_handle
*ph
, mutex_t
**mutex_to_lock
, struct list
*list_entry
, int *status
)
2277 *status
= ph
->status
;
2281 *mutex_to_lock
= &proc_tree_mutex
;
2282 list_add(&ph
->wait_list
, list_entry
);
2288 static void process_pid_and_status(pid_t pid
, int status
)
2290 struct tree_entry
*e
;
2291 struct proc_handle
*ph
;
2295 e
= tree_find(&proc_tree
, proc_handle_compare
, pid
);
2301 ph
= get_struct(e
, struct proc_handle
, entry
);
2304 if (WIFEXITED(status
)) {
2305 ph
->status
= WEXITSTATUS(status
);
2306 } else if (WIFSIGNALED(status
)) {
2307 ph
->status
= -WTERMSIG(status
);
2313 tree_delete(&ph
->entry
);
2315 if (!ph
->detached
) {
2316 call(wake_up_wait_list
)(&ph
->wait_list
, &proc_tree_mutex
, true);
2318 proc_handle_free(ph
);
2323 static attr_noinline
void proc_check_owned(void)
2325 struct tree_entry
*e
;
2326 struct proc_handle
*ph
;
2333 e
= tree_find_next(&proc_tree
, proc_handle_compare
, pid
);
2338 ph
= get_struct(e
, struct proc_handle
, entry
);
2342 EINTR_LOOP(r
, waitpid(pid
, &status
, WNOHANG
));
2346 process_pid_and_status(pid
, status
);
2350 void os_proc_check_all(void)
2356 if (likely(tree_is_empty(&proc_tree
))) {
2364 EINTR_LOOP(pid
, waitpid(-1, &status
, WNOHANG
));
2365 if (unlikely(pid
> 0)) {
2366 process_pid_and_status(pid
, status
);
2377 #ifdef OS_HAS_SIGNALS
2379 #if defined(SIGRTMAX)
2380 #define N_SIGNALS (int)(SIGRTMAX + 1)
2382 #define N_SIGNALS (int)NSIG
2384 #define N_SIGNALS 32
2387 struct signal_state
{
2388 thread_volatile signal_seq_t sig_sequence
;
2389 signal_seq_t last_sig_sequence
;
2392 struct list wait_list
;
2393 struct sigaction prev_sa
;
2396 static struct signal_state
*signal_states
;
2397 static mutex_t signal_state_mutex
;
2399 static void signal_handler(int sig
)
2401 signal_states
[sig
].sig_sequence
+= 1UL;
2405 static int os_signal_number(const char *str
)
2408 if (!strcmp(str
, "SIGABRT")) return SIGABRT
;
2411 if (!strcmp(str
, "SIGALRM")) return SIGALRM
;
2414 if (!strcmp(str
, "SIGBUS")) return SIGBUS
;
2417 if (!strcmp(str
, "SIGCHLD")) return SIGCHLD
;
2420 if (!strcmp(str
, "SIGCLD")) return SIGCLD
;
2423 if (!strcmp(str
, "SIGCONT")) return SIGCONT
;
2426 if (!strcmp(str
, "SIGEMT")) return SIGEMT
;
2429 if (!strcmp(str
, "SIGFPE")) return SIGFPE
;
2432 if (!strcmp(str
, "SIGHUP")) return SIGHUP
;
2435 if (!strcmp(str
, "SIGILL")) return SIGILL
;
2438 if (!strcmp(str
, "SIGINFO")) return SIGINFO
;
2441 if (!strcmp(str
, "SIGINT")) return SIGINT
;
2444 if (!strcmp(str
, "SIGIO")) return SIGIO
;
2447 if (!strcmp(str
, "SIGIOT")) return SIGIOT
;
2450 if (!strcmp(str
, "SIGKILL")) return SIGKILL
;
2453 if (!strcmp(str
, "SIGLOST")) return SIGLOST
;
2456 if (!strcmp(str
, "SIGPIPE")) return SIGPIPE
;
2459 if (!strcmp(str
, "SIGPOLL")) return SIGPOLL
;
2462 if (!strcmp(str
, "SIGPROF")) return SIGPROF
;
2465 if (!strcmp(str
, "SIGPWR")) return SIGPWR
;
2468 if (!strcmp(str
, "SIGQUIT")) return SIGQUIT
;
2471 if (!strcmp(str
, "SIGSEGV")) return SIGSEGV
;
2474 if (!strcmp(str
, "SIGSTKFLT")) return SIGSTKFLT
;
2477 if (!strcmp(str
, "SIGSTOP")) return SIGSTOP
;
2480 if (!strcmp(str
, "SIGTSTP")) return SIGTSTP
;
2483 if (!strcmp(str
, "SIGSYS")) return SIGSYS
;
2486 if (!strcmp(str
, "SIGTERM")) return SIGTERM
;
2489 if (!strcmp(str
, "SIGTRAP")) return SIGTRAP
;
2492 if (!strcmp(str
, "SIGTTIN")) return SIGTTIN
;
2495 if (!strcmp(str
, "SIGTTOU")) return SIGTTOU
;
2498 if (!strcmp(str
, "SIGUNUSED")) return SIGUNUSED
;
2501 if (!strcmp(str
, "SIGURG")) return SIGURG
;
2504 if (!strcmp(str
, "SIGUSR1")) return SIGUSR1
;
2507 if (!strcmp(str
, "SIGUSR2")) return SIGUSR2
;
2510 if (!strcmp(str
, "SIGVTALRM")) return SIGVTALRM
;
2513 if (!strcmp(str
, "SIGWINCH")) return SIGWINCH
;
2516 if (!strcmp(str
, "SIGXCPU")) return SIGXCPU
;
2519 if (!strcmp(str
, "SIGXFSZ")) return SIGXFSZ
;
2521 #if defined(SIGRTMIN) && defined(SIGRTMAX)
2522 if (!strncmp(str
, "SIGRT", 5) && str
[5]) {
2524 unsigned long num
= strtoul(str
+ 5, &endptr
, 10);
2525 if (unlikely(*endptr
))
2528 if (unlikely(num
< (unsigned long)SIGRTMIN
) || unlikely(num
> (unsigned long)SIGRTMAX
))
2536 int os_signal_handle(const char *str
, signal_seq_t
*seq
, ajla_error_t
*err
)
2538 struct signal_state
*s
;
2539 int sig
= os_signal_number(str
);
2540 if (unlikely(!sig
)) {
2544 mutex_lock(&signal_state_mutex
);
2545 s
= &signal_states
[sig
];
2546 if (unlikely(s
->trapped
)) {
2547 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "signal %s already handled", str
);
2550 if (likely(!s
->refcount
)) {
2551 struct sigaction sa
;
2554 s
->sig_sequence
= 0;
2555 s
->last_sig_sequence
= 0;
2557 (void)memset(&sa
, 0, sizeof sa
);
2558 sa
.sa_handler
= signal_handler
;
2559 sigemptyset(&sa
.sa_mask
);
2561 if (sig
!= SIGTTIN
&& sig
!= SIGTTOU
)
2562 sa
.sa_flags
|= SA_RESTART
;
2564 EINTR_LOOP(r
, sigaction(sig
, &sa
, &s
->prev_sa
));
2565 if (unlikely(r
== -1)) {
2566 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2567 fatal_mayfail(e
, err
, "sigaction(%d) failed: %s", sig
, error_decode(e
));
2572 *seq
= s
->last_sig_sequence
;
2573 mutex_unlock(&signal_state_mutex
);
2577 mutex_unlock(&signal_state_mutex
);
2581 static void os_signal_restore(struct signal_state
*s
, int sig
)
2584 EINTR_LOOP(r
, sigaction(sig
, &s
->prev_sa
, NULL
));
2585 if (unlikely(r
== -1)) {
2586 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2587 fatal("sigaction(%d) failed: %s", sig
, error_decode(e
));
2591 void os_signal_unhandle(int sig
)
2593 struct signal_state
*s
;
2596 mutex_lock(&signal_state_mutex
);
2597 s
= &signal_states
[sig
];
2599 internal(file_line
, "os_signal_unhandle: refcount underflow");
2602 os_signal_restore(s
, sig
);
2603 mutex_unlock(&signal_state_mutex
);
2606 signal_seq_t
os_signal_seq(int sig
)
2608 struct signal_state
*s
;
2612 mutex_lock(&signal_state_mutex
);
2613 s
= &signal_states
[sig
];
2615 internal(file_line
, "os_signal_unhandle: unhandled signal");
2616 seq
= s
->last_sig_sequence
;
2617 mutex_unlock(&signal_state_mutex
);
2621 bool os_signal_wait(int sig
, signal_seq_t seq
, mutex_t
**mutex_to_lock
, struct list
*list_entry
)
2623 struct signal_state
*s
;
2625 if (unlikely(!sig
)) {
2626 iomux_never(mutex_to_lock
, list_entry
);
2630 mutex_lock(&signal_state_mutex
);
2631 s
= &signal_states
[sig
];
2632 if (unlikely(seq
!= s
->last_sig_sequence
)) {
2633 mutex_unlock(&signal_state_mutex
);
2636 *mutex_to_lock
= &signal_state_mutex
;
2637 list_add(&s
->wait_list
, list_entry
);
2638 mutex_unlock(&signal_state_mutex
);
2643 void os_signal_check_all(void)
2647 mutex_lock(&signal_state_mutex
);
2648 for (; sig
< N_SIGNALS
; sig
++) {
2649 struct signal_state
*s
= &signal_states
[sig
];
2650 signal_seq_t seq
= s
->sig_sequence
;
2651 if (unlikely(seq
!= s
->last_sig_sequence
)) {
2652 s
->last_sig_sequence
= seq
;
2653 call(wake_up_wait_list
)(&s
->wait_list
, &signal_state_mutex
, true);
2658 mutex_unlock(&signal_state_mutex
);
2661 #ifdef HAVE_CODEGEN_TRAPS
2663 void *u_data_trap_lookup(void *ptr
);
2664 void *c_data_trap_lookup(void *ptr
);
2666 static void sigfpe_handler(int attr_unused sig
, siginfo_t
*siginfo
, void *ucontext
)
2668 ucontext_t
*uc
= ucontext
;
2669 #if defined(ARCH_ALPHA)
2670 if (unlikely(siginfo
->si_code
!= FPE_FLTINV
))
2671 fatal("unexpected SIGFPE received: %d", siginfo
->si_code
);
2672 /*debug("bla: %lx, %lx, %lx", uc->uc_mcontext.sc_regs[0x7], uc->uc_mcontext.sc_regs[0xf], uc->uc_mcontext.sc_regs[0x10]);*/
2673 uc
->uc_mcontext
.sc_pc
= ptr_to_num(call(data_trap_lookup
)(num_to_ptr(uc
->uc_mcontext
.sc_pc
)));
2675 #if defined(ARCH_MIPS)
2676 if (unlikely(siginfo
->si_code
!= FPE_INTOVF
))
2677 fatal("unexpected SIGFPE received: %d", siginfo
->si_code
);
2678 /*debug("bla: %llx, %llx, %llx", uc->uc_mcontext.gregs[0x4], uc->uc_mcontext.gregs[0x17], uc->uc_mcontext.gregs[0x16]);*/
2679 uc
->uc_mcontext
.pc
= ptr_to_num(call(data_trap_lookup
)(num_to_ptr(uc
->uc_mcontext
.pc
)));
2686 void os_signal_trap(int sig
, void (*handler
)(int, siginfo_t
*, void *))
2688 if (OS_SUPPORTS_TRAPS
) {
2689 struct signal_state
*s
= &signal_states
[sig
];
2690 struct sigaction sa
;
2695 (void)memset(&sa
, 0, sizeof sa
);
2696 sa
.sa_sigaction
= handler
;
2697 sigemptyset(&sa
.sa_mask
);
2698 sa
.sa_flags
|= SA_SIGINFO
;
2699 EINTR_LOOP(r
, sigaction(sig
, &sa
, &s
->prev_sa
));
2700 if (unlikely(r
== -1)) {
2701 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2702 fatal("sigaction(%d) failed: %s", sig
, error_decode(e
));
2706 void os_signal_untrap(int sig
)
2708 if (OS_SUPPORTS_TRAPS
) {
2709 struct signal_state
*s
= &signal_states
[sig
];
2710 ajla_assert_lo(s
->trapped
, (file_line
, "os_signal_untrap: signal %d not trapped", sig
));
2711 os_signal_restore(s
, sig
);
2719 int os_signal_handle(const char attr_unused
*str
, signal_seq_t attr_unused
*seq
, ajla_error_t attr_unused
*err
)
2725 void os_signal_unhandle(int attr_unused sig
)
2729 signal_seq_t
os_signal_seq(int attr_unused sig
)
2734 bool os_signal_wait(int attr_unused sig
, signal_seq_t attr_unused seq
, mutex_t
**mutex_to_lock
, struct list
*list_entry
)
2736 iomux_never(mutex_to_lock
, list_entry
);
2740 void os_signal_check_all(void)
2749 handle_t
os_socket(int domain
, int type
, int protocol
, ajla_error_t
*err
)
2752 domain
= os_socket_pf(domain
, err
);
2753 if (unlikely(domain
== -1))
2755 type
= os_socket_type(type
, err
);
2756 if (unlikely(type
== -1))
2758 #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
2759 EINTR_LOOP(h
, socket(domain
, type
| SOCK_NONBLOCK
| SOCK_CLOEXEC
, protocol
));
2760 if (likely(h
!= -1)) {
2761 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
2764 if (errno
!= EINVAL
) {
2765 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2766 fatal_mayfail(e
, err
, "can't create socket (%d, %d, %d): %s", domain
, type
, protocol
, error_decode(e
));
2770 os_lock_fork(false);
2771 EINTR_LOOP(h
, socket(domain
, type
, protocol
));
2772 if (unlikely(h
== -1)) {
2773 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2774 os_unlock_fork(false);
2775 fatal_mayfail(e
, err
, "can't create socket (%d, %d, %d): %s", domain
, type
, protocol
, error_decode(e
));
2779 os_unlock_fork(false);
2780 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
2781 EINTR_LOOP(r
, fcntl(h
, F_SETFL
, O_NONBLOCK
));
2782 if (unlikely(r
== -1)) {
2784 fatal("fcntl(F_SETFL, O_NONBLOCK) on a socket failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
2789 bool os_bind_connect(bool bnd
, handle_t h
, unsigned char *addr
, size_t addr_len
, ajla_error_t
*err
)
2792 struct sockaddr
*sa
;
2794 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2795 sa
= os_get_sock_addr(addr
, &addr_len
, err
);
2799 EINTR_LOOP(r
, connect(h
, sa
, addr_len
));
2801 EINTR_LOOP(r
, bind(h
, sa
, addr_len
));
2802 mem_free_aligned(sa
);
2805 if (likely(!bnd
) && likely(errno
== EINPROGRESS
))
2807 e
= error_from_errno(EC_SYSCALL
, errno
);
2808 fatal_mayfail(e
, err
, "can't %s socket: %s", !bnd
? "connect" : "bind", error_decode(e
));
2812 bool os_connect_completed(handle_t h
, ajla_error_t
*err
)
2818 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2820 EINTR_LOOP(r
, getsockopt(h
, SOL_SOCKET
, SO_ERROR
, &er
, &er_l
));
2821 if (unlikely(r
== -1)) {
2822 e
= error_from_errno(EC_SYSCALL
, errno
);
2823 fatal_mayfail(e
, err
, "getsockopt returned an error: %s", error_decode(e
));
2827 e
= error_from_errno(EC_SYSCALL
, er
);
2828 fatal_mayfail(e
, err
, "can't connect socket: %s", error_decode(e
));
2834 bool os_listen(handle_t h
, ajla_error_t
*err
)
2837 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2838 EINTR_LOOP(r
, listen(h
, signed_maximum(int)));
2839 if (unlikely(r
== -1)) {
2840 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2841 fatal_mayfail(e
, err
, "listen returned an error: %s", error_decode(e
));
2847 int os_accept(handle_t h
, handle_t
*result
, ajla_error_t
*err
)
2851 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2853 EINTR_LOOP(r
, accept4(h
, NULL
, 0, SOCK_NONBLOCK
| SOCK_CLOEXEC
));
2854 if (likely(r
!= -1)) {
2856 obj_registry_insert(OBJ_TYPE_HANDLE
, r
, file_line
);
2859 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
2860 return OS_RW_WOULDBLOCK
;
2861 if (errno
!= ENOSYS
) {
2862 e
= error_from_errno(EC_SYSCALL
, errno
);
2863 fatal_mayfail(e
, err
, "accept returned an error: %s", error_decode(e
));
2867 os_lock_fork(false);
2868 EINTR_LOOP(r
, accept(h
, NULL
, 0));
2869 if (unlikely(r
== -1)) {
2870 os_unlock_fork(false);
2871 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
2872 return OS_RW_WOULDBLOCK
;
2873 e
= error_from_errno(EC_SYSCALL
, errno
);
2874 fatal_mayfail(e
, err
, "accept returned an error: %s", error_decode(e
));
2878 os_unlock_fork(false);
2880 obj_registry_insert(OBJ_TYPE_HANDLE
, r
, file_line
);
2881 EINTR_LOOP(r
, fcntl(r
, F_SETFL
, O_NONBLOCK
));
2882 if (unlikely(r
== -1)) {
2884 fatal("fcntl(F_SETFL, O_NONBLOCK) on a socket failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
2889 bool os_getsockpeername(bool peer
, handle_t h
, unsigned char **addr
, size_t *addr_len
, ajla_error_t
*err
)
2892 struct sockaddr
*sa
;
2895 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2897 sa
= mem_align_mayfail(struct sockaddr
*, SOCKADDR_MAX_LEN
, SOCKADDR_ALIGN
, err
);
2900 addrlen
= SOCKADDR_MAX_LEN
;
2903 EINTR_LOOP(r
, getsockname(h
, sa
, &addrlen
));
2905 #ifdef HAVE_GETPEERNAME
2906 EINTR_LOOP(r
, getpeername(h
, sa
, &addrlen
));
2908 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "getpeername not supported");
2909 goto free_ret_false
;
2912 if (unlikely(r
== -1)) {
2913 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2914 fatal_mayfail(e
, err
, "%s returned an error: %s", !peer
? "getsockname" : "getpeername", error_decode(e
));
2915 goto free_ret_false
;
2918 *addr
= os_get_ajla_addr(sa
, &addrlen
, err
);
2919 if (unlikely(!*addr
))
2920 goto free_ret_false
;
2922 *addr_len
= addrlen
;
2924 mem_free_aligned(sa
);
2928 mem_free_aligned(sa
);
2932 ssize_t
os_recvfrom(handle_t h
, char *buffer
, size_t len
, int flags
, unsigned char **addr
, size_t *addr_len
, ajla_error_t
*err
)
2934 struct sockaddr
*sa
;
2939 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2941 f
= translate_flags(os_socket_msg
, flags
, err
);
2942 if (unlikely(f
< 0))
2945 sa
= mem_align_mayfail(struct sockaddr
*, SOCKADDR_MAX_LEN
, SOCKADDR_ALIGN
, err
);
2948 addrlen
= SOCKADDR_MAX_LEN
;
2950 EINTR_LOOP(r
, recvfrom(h
, buffer
, len
, f
, sa
, &addrlen
));
2953 if (unlikely(addrlen
> SOCKADDR_MAX_LEN
)) {
2954 fatal_mayfail(error_ajla(EC_SYSCALL
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "the system returned too long address");
2955 mem_free_aligned(sa
);
2959 if (unlikely(!array_init_mayfail(unsigned char, addr
, addr_len
, err
))) {
2960 mem_free_aligned(sa
);
2964 *addr
= os_get_ajla_addr(sa
, &addrlen
, err
);
2965 if (unlikely(!*addr
)) {
2966 mem_free_aligned(sa
);
2969 *addr_len
= addrlen
;
2972 mem_free_aligned(sa
);
2973 return os_rdwr_return(r
, "receiving", err
);
2976 ssize_t
os_sendto(handle_t h
, const char *buffer
, size_t len
, int flags
, unsigned char *addr
, size_t addr_len
, ajla_error_t
*err
)
2978 struct sockaddr
*sa
;
2982 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2984 f
= translate_flags(os_socket_msg
, flags
, err
);
2985 if (unlikely(f
< 0))
2988 if (addr_len
!= 0) {
2989 sa
= os_get_sock_addr(addr
, &addr_len
, err
);
2992 EINTR_LOOP(r
, sendto(h
, buffer
, len
, f
, sa
, addr_len
));
2993 mem_free_aligned(sa
);
2995 EINTR_LOOP(r
, send(h
, buffer
, len
, f
));
2998 return os_rdwr_return(r
, "sending", err
);
3001 bool os_getsockopt(handle_t h
, int level
, int option
, char **buffer
, size_t *buffer_len
, ajla_error_t
*err
)
3006 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
3008 level
= os_socket_level(level
, err
);
3009 if (unlikely(level
< 0))
3012 option
= os_socket_option(option
, err
);
3013 if (unlikely(level
< 0))
3017 *buffer
= mem_alloc_mayfail(char *, opt_len
, err
);
3018 if (unlikely(!*buffer
))
3021 EINTR_LOOP(r
, getsockopt(h
, level
, option
, *buffer
, &opt_len
));
3023 if (unlikely(r
== -1)) {
3024 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
3025 fatal_mayfail(e
, err
, "getsockopt returned an error: %s", error_decode(e
));
3030 *buffer_len
= opt_len
;
3034 bool os_setsockopt(handle_t h
, int level
, int option
, const char *buffer
, size_t buffer_len
, ajla_error_t
*err
)
3038 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
3040 level
= os_socket_level(level
, err
);
3041 if (unlikely(level
< 0))
3044 option
= os_socket_option(option
, err
);
3045 if (unlikely(level
< 0))
3048 EINTR_LOOP(r
, setsockopt(h
, level
, option
, buffer
, buffer_len
));
3050 if (unlikely(r
== -1)) {
3051 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
3052 fatal_mayfail(e
, err
, "setsockopt returned an error: %s", error_decode(e
));
3059 #ifdef HAVE_GETADDRINFO
3060 bool os_getaddrinfo(const char *host
, int port
, struct address
**result
, size_t *result_l
, ajla_error_t
*err
)
3065 struct addrinfo
*res
= NULL
, *rs
;
3067 if (unlikely(!array_init_mayfail(struct address
, result
, result_l
, err
)))
3070 snprintf(port_str
, sizeof port_str
, "%d", port
);
3071 r
= getaddrinfo(host
, port_str
, NULL
, &res
);
3073 if (unlikely(r
== EAI_SYSTEM
))
3074 fatal_mayfail(error_from_errno(EC_SYSCALL
, errno
), err
, "host not found");
3076 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_GAI
, abs((int)r
)), err
, "host not found");
3080 for (rs
= res
; rs
; rs
= rs
->ai_next
) {
3082 struct address addr
;
3084 socklen_t addrlen
= rs
->ai_addrlen
;
3086 memset(&addr
.entry
, 0, sizeof addr
.entry
); /* avoid warning */
3088 addr
.address
= os_get_ajla_addr(rs
->ai_addr
, &addrlen
, &e
);
3089 if (unlikely(!addr
.address
))
3091 addr
.address_length
= addrlen
;
3093 if (unlikely(!array_add_mayfail(struct address
, result
, result_l
, addr
, &xresult
, err
))) {
3099 if (unlikely(!*result_l
)) {
3100 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_GAI
, abs(EAI_NONAME
)), err
, "host not found");
3110 for (i
= 0; i
< *result_l
; i
++)
3111 mem_free((*result
)[i
].address
);
3119 #ifndef HAVE_H_ERRNO
3122 bool os_getaddrinfo(const char *host
, int port
, struct address
**result
, size_t *result_l
, ajla_error_t
*err
)
3129 if (unlikely(!array_init_mayfail(struct address
, result
, result_l
, err
)))
3132 he
= gethostbyname(host
);
3134 if (unlikely(!he
)) {
3135 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_H_ERRNO
, h_errno
), err
, "host not found");
3139 if (he
->h_addrtype
!= AF_INET
|| he
->h_length
!= 4 || !he
->h_addr
) {
3140 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_H_ERRNO
, NO_DATA
), err
, "host not found");
3145 for (i
= 0; (a
= he
->h_addr_list
[i
]); i
++)
3150 struct sockaddr_in sin
;
3152 struct address addr
;
3154 socklen_t addrlen
= sizeof sin
;
3156 sin
.sin_family
= AF_INET
;
3157 sin
.sin_port
= htons(port
);
3158 memcpy(&sin
.sin_addr
, a
, 4);
3160 memcpy(&sa
, &sin
, sizeof sin
);
3162 addr
.address
= os_get_ajla_addr(&sa
, &addrlen
, &e
);
3163 if (unlikely(!addr
.address
))
3165 addr
.address_length
= addrlen
;
3167 if (unlikely(!array_add_mayfail(struct address
, result
, result_l
, addr
, &xresult
, err
))) {
3173 if (unlikely(!*result_l
)) {
3174 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_H_ERRNO
, NO_DATA
), err
, "host not found");
3181 for (i
= 0; i
< *result_l
; i
++)
3182 mem_free((*result
)[i
].address
);
3188 #ifdef HAVE_GETNAMEINFO
3189 char *os_getnameinfo(unsigned char *addr
, size_t addr_len
, ajla_error_t
*err
)
3191 struct sockaddr
*sa
;
3195 sa
= os_get_sock_addr(addr
, &addr_len
, err
);
3204 h
= mem_alloc_mayfail(char *, h_len
, err
);
3206 mem_free_aligned(sa
);
3209 r
= getnameinfo(sa
, addr_len
, h
, h_len
, NULL
, 0, 0);
3212 if (unlikely(r
== EAI_OVERFLOW
)) {
3215 if (unlikely(!h_len
)) {
3216 fatal_mayfail(error_ajla(EC_SYSCALL
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "name buffer overflow");
3217 mem_free_aligned(sa
);
3220 goto alloc_buffer_again
;
3223 if (unlikely(r
== EAI_SYSTEM
)) {
3224 fatal_mayfail(error_from_errno(EC_SYSCALL
, errno
), err
, "host not found");
3226 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_GAI
, abs((int)r
)), err
, "host not found");
3229 mem_free_aligned(sa
);
3232 mem_free_aligned(sa
);
3235 #elif defined(HAVE_GETHOSTBYADDR)
3236 char *os_getnameinfo(unsigned char *addr
, size_t addr_len
, ajla_error_t
*err
)
3238 struct sockaddr
*sa
;
3242 sa
= os_get_sock_addr(addr
, &addr_len
, err
);
3245 switch (sa
->sa_family
) {
3247 struct sockaddr_in
*sin
;
3248 if (unlikely(addr_len
< offsetof(struct sockaddr_in
, sin_addr
) + 4)) {
3249 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), err
, "too short address");
3250 mem_free_aligned(sa
);
3253 sin
= cast_ptr(struct sockaddr_in
*, sa
);
3254 he
= gethostbyaddr(cast_ptr(void *, &sin
->sin_addr
.s_addr
), 4, sa
->sa_family
);
3259 struct sockaddr_in6
*sin6
;
3260 if (unlikely(addr_len
< offsetof(struct sockaddr_in6
, sin6_addr
) + 16)) {
3261 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), err
, "too short address");
3262 mem_free_aligned(sa
);
3265 sin6
= cast_ptr(struct sockaddr_in6
*, sa
);
3266 he
= gethostbyaddr(&sin6
->sin6_addr
.s6_addr
, 16, sa
->sa_family
);
3271 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "address family %d not supported", sa
->sa_family
);
3272 mem_free_aligned(sa
);
3276 mem_free_aligned(sa
);
3277 if (unlikely(!he
) || !he
->h_name
) {
3278 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_H_ERRNO
, h_errno
), err
, "host not found");
3281 le
= strlen(he
->h_name
);
3282 name
= mem_alloc_mayfail(char *, le
+ 1, err
);
3283 if (unlikely(!name
))
3285 return memcpy(name
, he
->h_name
, le
+ 1);
3288 char *os_getnameinfo(unsigned char attr_unused
*addr
, size_t attr_unused addr_len
, ajla_error_t
*err
)
3290 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "getnameinfo not supported");
3297 handle_t
os_socket(int attr_unused domain
, int attr_unused type
, int attr_unused protocol
, ajla_error_t
*err
)
3299 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3303 bool os_bind_connect(bool attr_unused bnd
, handle_t attr_unused h
, unsigned char attr_unused
*addr
, size_t attr_unused addr_len
, ajla_error_t
*err
)
3305 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3309 bool os_connect_completed(handle_t attr_unused h
, ajla_error_t
*err
)
3311 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3315 bool os_listen(handle_t attr_unused h
, ajla_error_t
*err
)
3317 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3321 int os_accept(handle_t attr_unused h
, handle_t attr_unused
*result
, ajla_error_t
*err
)
3323 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3327 bool os_getsockpeername(bool attr_unused peer
, handle_t attr_unused h
, unsigned char attr_unused
**addr
, size_t attr_unused
*addr_len
, ajla_error_t
*err
)
3329 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3333 ssize_t
os_recvfrom(handle_t attr_unused h
, char attr_unused
*buffer
, size_t attr_unused len
, int attr_unused flags
, unsigned char attr_unused
**addr
, size_t attr_unused
*addr_len
, ajla_error_t
*err
)
3335 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3339 ssize_t
os_sendto(handle_t attr_unused h
, const char attr_unused
*buffer
, size_t attr_unused len
, int attr_unused flags
, unsigned char attr_unused
*addr
, size_t attr_unused addr_len
, ajla_error_t
*err
)
3341 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3345 bool os_getsockopt(handle_t attr_unused h
, int attr_unused level
, int attr_unused option
, char attr_unused
**buffer
, size_t attr_unused
*buffer_len
, ajla_error_t
*err
)
3347 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3351 bool os_setsockopt(handle_t attr_unused h
, int attr_unused level
, int attr_unused option
, const char attr_unused
*buffer
, size_t attr_unused buffer_len
, ajla_error_t
*err
)
3353 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3357 bool os_getaddrinfo(const char attr_unused
*host
, int attr_unused port
, struct address attr_unused
**result
, size_t attr_unused
*result_l
, ajla_error_t
*err
)
3359 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3363 char *os_getnameinfo(unsigned char attr_unused
*addr
, size_t attr_unused addr_len
, ajla_error_t
*err
)
3365 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3372 const char *os_decode_error(ajla_error_t error
, char attr_unused
*(*tls_buffer
)(void))
3374 switch (error
.error_type
) {
3375 #if defined(HAVE_NETWORK) && defined(HAVE_GETADDRINFO)
3376 case AJLA_ERROR_GAI
: {
3377 return gai_strerror(error
.error_aux
* (EAI_NONAME
< 0 ? -1 : 1));
3380 case AJLA_ERROR_H_ERRNO
: {
3381 #if defined(HAVE_NETWORK) && defined(HAVE_HSTRERROR)
3382 return hstrerror(error
.error_aux
);
3384 return "Unknown host";
3393 #ifdef OS_HAS_DLOPEN
3394 struct dl_handle_t
*os_dlopen(const char *filename
, ajla_error_t
*err
, char **err_msg
)
3396 struct dl_handle_t
*dlh
;
3397 dlh
= dlopen(filename
, RTLD_LAZY
);
3398 if (unlikely(!dlh
)) {
3400 *err_msg
= dlerror();
3401 e
= error_ajla(EC_SYNC
, AJLA_ERROR_LIBRARY_NOT_FOUND
);
3402 fatal_mayfail(e
, err
, "can't open dynamic library '%s': %s", filename
, *err_msg
);
3408 void os_dlclose(struct dl_handle_t
*dlh
)
3410 int r
= dlclose(dlh
);
3411 #if defined(OS_CYGWIN)
3412 /* dlclose fails if we attempt to unload non-cygwin dll */
3413 if (unlikely(r
== -1) && errno
== ENOENT
)
3417 internal(file_line
, "dlclose failed: %s", dlerror());
3420 bool os_dlsym(struct dl_handle_t
*dlh
, const char *symbol
, void **result
)
3423 r
= dlsym(dlh
, symbol
);
3432 #ifdef OS_HAVE_NOTIFY_PIPE
3433 handle_t os_notify_pipe
[2];
3435 void os_notify(void)
3439 EINTR_LOOP(r
, write(os_notify_pipe
[1], &c
, 1));
3440 if (unlikely(r
== -1)) {
3442 if (unlikely(er
!= EAGAIN
) && unlikely(er
!= EWOULDBLOCK
) && unlikely(er
!= EBADF
)) {
3443 fatal("error writing to the notify pipe: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
3448 bool os_drain_notify_pipe(void)
3450 static char buffer
[1024];
3452 EINTR_LOOP(r
, read(os_notify_pipe
[0], buffer
, sizeof(buffer
)));
3453 if (likely(r
== -1)) {
3455 if (unlikely(er
!= EAGAIN
) && unlikely(er
!= EWOULDBLOCK
)) {
3456 fatal("error reading the notify pipe: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
3462 void os_shutdown_notify_pipe(void)
3465 EINTR_LOOP(r
, dup2(os_notify_pipe
[0], os_notify_pipe
[1]));
3466 if (unlikely(r
== -1)) {
3468 fatal("error shutting down the notify pipe: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
3477 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
3479 const char *os_get_flavor(void)
3483 #elif defined(OS_CYGWIN)
3490 void os_get_uname(os_utsname_t
*un
)
3493 EINTR_LOOP(r
, uname(un
));
3494 if (unlikely(r
== -1)) {
3496 fatal("uname returned error: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
3498 if (sizeof un
->sysname
>= 10 && likely(!strcmp(un
->sysname
, "Linux")))
3499 strcpy(un
->sysname
, "GNU/Linux"); /* make RMS happy */
3502 bool os_kernel_version(const char *sys
, const char *vers
)
3504 static os_utsname_t un
;
3505 static bool have_un
= false;
3506 const char *last_comp
, *ptr_sys
, *ptr_wanted
;
3511 if (unlikely(strcmp(sys
, un
.sysname
)))
3513 last_comp
= strrchr(vers
, '.');
3518 if (strncmp(un
.release
, vers
, last_comp
- vers
))
3520 ptr_sys
= un
.release
+ (last_comp
- vers
);
3521 ptr_wanted
= vers
+ (last_comp
- vers
);
3524 if (likely(*ptr_sys
>= '0') && likely(*ptr_sys
<= '9')) {
3525 if (atoi(ptr_sys
) >= atoi(ptr_wanted
)) {
3534 void os_get_uname(os_utsname_t
*un
)
3536 memset(un
, 0, sizeof(os_utsname_t
));
3537 strcpy(un
->sysname
, "Posix");
3539 strcpy(un
->machine
, ARCH_NAME
);
3543 bool os_kernel_version(const char attr_unused
*sys
, const char attr_unused
*vers
)
3550 char *os_get_host_name(ajla_error_t
*err
)
3552 #ifdef HAVE_GETHOSTNAME
3560 fatal_mayfail(error_ajla(EC_ASYNC
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "overflow when allocating host name");
3563 hn
= mem_alloc_mayfail(char *, s
, err
);
3567 EINTR_LOOP(r
, gethostname(hn
, s
));
3569 if (unlikely(r
== -1)) {
3570 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
3572 if (errno
== EINVAL
|| errno
== ENAMETOOLONG
)
3574 fatal_mayfail(e
, err
, "can't get hostname: %s", error_decode(e
));
3578 if (unlikely(strnlen(hn
, s
) >= s
- 1)) {
3585 char *e
= getenv("HOSTNAME");
3588 return str_dup(e
, -1, err
);
3598 EINTR_LOOP(r
, close(3));
3599 EINTR_LOOP(r
, close(4));
3605 EINTR_LOOP(r
, fstat(n_std_handles
, &st
));
3610 if (unlikely(n_std_handles
< 3))
3613 #ifdef HAVE_AT_FUNCTIONS
3614 if (os_kernel_version("GNU/Linux", "3") ||
3615 os_kernel_version("GNU/Linux", "2.6.23")) {
3616 have_O_CLOEXEC_openat
= true;
3621 EINTR_LOOP(r
, fstatat(AT_FDCWD
, "/", &st
, AT_SYMLINK_NOFOLLOW
));
3622 if (unlikely(r
== -1))
3625 EINTR_LOOP(h
, openat(AT_FDCWD
, "/dev/null", O_RDONLY
| O_CLOEXEC
));
3626 if (unlikely(h
== -1))
3629 EINTR_LOOP(flags
, fcntl(h
, F_GETFD
));
3630 if (likely(flags
>= 0) && likely(flags
& FD_CLOEXEC
))
3631 have_O_CLOEXEC_openat
= true;
3637 os_cwd
= os_get_cwd(&sink
);
3638 if (unlikely(dir_handle_is_valid(os_cwd
))) {
3639 os_set_original_cwd();
3641 os_cwd
= os_get_cwd(NULL
);
3644 os_init_path_to_exe();
3646 #ifdef OS_HAVE_NOTIFY_PIPE
3647 os_pipe(os_notify_pipe
, 3, NULL
);
3650 #ifdef OS_HAS_SIGNALS
3651 signal_states
= mem_alloc_array_mayfail(mem_calloc_mayfail
, struct signal_state
*, 0, 0, N_SIGNALS
, sizeof(struct signal_state
), NULL
);
3652 for (i
= 0; i
< N_SIGNALS
; i
++)
3653 list_init(&signal_states
[i
].wait_list
);
3655 #ifdef HAVE_CODEGEN_TRAPS
3656 os_signal_trap(SIGFPE
, sigfpe_handler
);
3657 #if defined(ARCH_MIPS)
3658 os_signal_trap(SIGTRAP
, sigfpe_handler
);
3667 #ifdef OS_HAS_SIGNALS
3670 #ifdef HAVE_CODEGEN_TRAPS
3671 os_signal_untrap(SIGFPE
);
3672 #if defined(ARCH_MIPS)
3673 os_signal_untrap(SIGTRAP
);
3677 for (sig
= 0; sig
< N_SIGNALS
; sig
++) {
3678 if (unlikely(signal_states
[sig
].trapped
) || unlikely(signal_states
[sig
].refcount
!= 0))
3679 internal(file_line
, "signal %d leaked", sig
);
3681 mem_free(signal_states
);
3682 signal_states
= NULL
;
3685 #ifdef OS_HAVE_NOTIFY_PIPE
3686 os_close(os_notify_pipe
[0]);
3687 os_close(os_notify_pipe
[1]);
3690 os_dir_close(os_cwd
);
3692 mem_free(os_path_to_exe
);
3695 void os_init_multithreaded(void)
3699 os_init_calendar_lock();
3701 rwmutex_init(&fork_lock
);
3702 os_threads_initialized
= true;
3704 #if !defined(OS_DOS)
3705 tree_init(&proc_tree
);
3706 mutex_init(&proc_tree_mutex
);
3709 #ifdef OS_HAS_SIGNALS
3710 mutex_init(&signal_state_mutex
);
3713 for (u
= 0; u
< n_std_handles
; u
++)
3714 obj_registry_insert(OBJ_TYPE_HANDLE
, u
, file_line
);
3720 void os_done_multithreaded(void)
3727 for (u
= 0; u
< n_std_handles
; u
++)
3728 obj_registry_remove(OBJ_TYPE_HANDLE
, u
, file_line
);
3730 #ifdef OS_HAS_SIGNALS
3731 mutex_done(&signal_state_mutex
);
3734 #if !defined(OS_DOS)
3735 if (unlikely(!tree_is_empty(&proc_tree
))) {
3736 struct proc_handle
*ph
= get_struct(tree_any(&proc_tree
), struct proc_handle
, entry
);
3737 tree_delete(&ph
->entry
);
3738 proc_handle_free(ph
);
3740 mutex_done(&proc_tree_mutex
);
3743 os_threads_initialized
= false;
3744 rwmutex_done(&fork_lock
);
3746 os_done_calendar_lock();