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)
39 #ifdef HAVE_SYS_SYSMACROS_H
40 #include <sys/sysmacros.h>
42 #ifdef HAVE_LINUX_FALLOC_H
43 #include <linux/falloc.h>
48 #ifdef HAVE_SYS_SELECT_H
49 #include <sys/select.h>
52 #include <sys/socket.h>
53 #include <netinet/in.h>
60 #include <sys/ioctl.h>
61 #if defined(HAVE_SYS_PARAM_H)
62 #include <sys/param.h>
64 #if defined(HAVE_SYS_UCRED_H)
65 #include <sys/ucred.h>
67 #if defined(HAVE_SYS_MOUNT_H)
68 #include <sys/mount.h>
70 #if defined(HAVE_LINUX_FS_H) && !defined(__TINYC__)
74 #define SOCKADDR_MAX_LEN 65535
75 #define SOCKADDR_ALIGN 16
77 #ifndef wake_up_wait_list
78 void u_name(wake_up_wait_list
)(struct list
*wait_list
, mutex_t
*mutex_to_lock
, bool can_allocate_memory
);
79 void c_name(wake_up_wait_list
)(struct list
*wait_list
, mutex_t
*mutex_to_lock
, bool can_allocate_memory
);
82 #if !defined(THREAD_NONE) && defined(USE_SIGPROCMASK) && defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SIGMASK)
84 #define USE_PTHREAD_SIGMASK
87 #ifdef OS_USE_LARGEFILE64_SOURCE
89 #define fstatvfs fstatvfs64
90 #define ftruncate ftruncate64
96 #define pwrite pwrite64
98 #define statvfs statvfs64
99 #define truncate truncate64
102 static rwmutex_t fork_lock
;
103 static bool os_threads_initialized
= false;
105 #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)
106 static bool have_O_CLOEXEC_openat
= false;
107 #define HAVE_AT_FUNCTIONS
113 #include "os_com.inc"
116 static void os_lock_fork(bool for_write
)
118 if (os_threads_initialized
) {
120 rwmutex_lock_read(&fork_lock
);
122 rwmutex_lock_write(&fork_lock
);
126 static void os_unlock_fork(bool for_write
)
128 if (os_threads_initialized
) {
130 rwmutex_unlock_read(&fork_lock
);
132 rwmutex_unlock_write(&fork_lock
);
136 uint32_t os_get_last_error(void)
141 uint32_t os_get_last_socket_error(void)
148 int os_getpagesize(void)
150 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
153 EINTR_LOOP(ps
, sysconf(_SC_PAGESIZE
));
154 if (unlikely(ps
== -1)) {
156 warning("sysconf(_SC_PAGESIZE) returned error: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
161 #elif defined(HAVE_GETPAGESIZE)
164 EINTR_LOOP(ps
, getpagesize());
165 if (unlikely(ps
== -1)) {
167 warning("getpagesize() returned error: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
176 void *os_mmap(void *ptr
, size_t size
, int prot
, int flags
, int h
, os_off_t off
, ajla_error_t
*err
)
180 prot
|= PROT_MPROTECT(PROT_EXEC
);
182 #ifndef HAVE_MPROTECT
185 EINTR_LOOP_VAL(p
, MAP_FAILED
, mmap(ptr
, size
, prot
, flags
, h
, off
));
186 if (unlikely(p
== MAP_FAILED
)) {
187 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
188 fatal_mayfail(e
, err
, "can't map memory: %s", error_decode(e
));
194 void os_munmap(void *ptr
, size_t size
, bool attr_unused file
)
197 EINTR_LOOP(r
, munmap(ptr
, size
));
198 if (unlikely(r
== -1)) {
200 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
)));
204 bool os_mprotect(void attr_unused
*ptr
, size_t attr_unused size
, int attr_unused prot
, ajla_error_t
*err
)
208 EINTR_LOOP(r
, mprotect(ptr
, size
, prot
));
209 if (unlikely(r
== -1)) {
210 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
211 fatal_mayfail(e
, err
, "can't protect memory: %s", error_decode(e
));
216 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "the system doesn't support mprotect");
222 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
)
226 EINTR_LOOP_VAL(p
, MAP_FAILED
, mremap(old_ptr
, old_size
, new_size
, flags
, new_ptr
));
228 EINTR_LOOP_VAL(p
, MAP_FAILED
, mremap(old_ptr
, old_size
, new_size
, flags
));
230 if (unlikely(p
== MAP_FAILED
)) {
231 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
232 fatal_mayfail(e
, err
, "can't remap memory: %s", error_decode(e
));
242 void os_code_invalidate_cache(uint8_t attr_unused
*code
, size_t attr_unused code_size
, bool attr_unused set_exec
)
244 #if defined(ARCH_PARISC) && defined(HAVE_GCC_ASSEMBLER)
246 size_t cl_size
= cpu_test_feature(CPU_FEATURE_pa20
) ? 64 : 16;
247 size_t align
= ptr_to_num(code
) & (cl_size
- 1);
250 __asm__
volatile ("sync" : : : "memory");
251 for (i
= 0; i
< code_size
; i
+= cl_size
) {
252 __asm__
volatile ("fdc %%r0(%0)" : : "r"(code
+ i
) : "memory");
254 __asm__
volatile ("sync");
255 #if defined(ARCH_PARISC32)
258 __asm__
volatile("ldsid (%1), %0\n mtsp %0, %%sr0" : "=r"(reg
) : "r"(code
) : "memory");
261 for (i
= 0; i
< code_size
; i
+= cl_size
) {
262 #if defined(ARCH_PARISC32)
264 __asm__
volatile ("fic %%r0(%%sr0, %0)" : : "r"(code
+ i
) : "memory");
266 __asm__
volatile ("fic %%r0(%%sr4, %0)" : : "r"(code
+ i
) : "memory");
269 __asm__
volatile ("fic %%r0(%0)" : : "r"(code
+ i
) : "memory");
272 __asm__
volatile ("sync" : : : "memory");
273 #elif defined(ARCH_ALPHA)
274 /* imb doesn't work on SMP systems */
275 #elif defined(ARCH_SPARC64) && defined(HAVE_GCC_ASSEMBLER)
277 __asm__
volatile ("membar #StoreStore" : : : "memory");
278 for (i
= 0; i
< code_size
; i
+= 8) {
279 __asm__
volatile ("flush %0" : : "r"(code
+ i
) : "memory");
281 #elif defined(HAVE___BUILTIN___CLEAR_CACHE)
282 __builtin___clear_cache(cast_ptr(void *, code
), cast_ptr(char *, code
) + code_size
);
284 #if defined(OS_HAS_MMAP) && defined(HAVE_MPROTECT)
286 int prot_flags
= PROT_READ
| PROT_EXEC
287 #ifdef CODEGEN_USE_HEAP
291 int page_size
= os_getpagesize();
292 int front_pad
= ptr_to_num(code
) & (page_size
- 1);
293 uint8_t *mem_region
= code
- front_pad
;
294 size_t mem_length
= code_size
+ front_pad
;
295 mem_length
= round_up(mem_length
, page_size
);
296 os_mprotect(mem_region
, mem_length
, prot_flags
, NULL
);
301 void *os_code_map(uint8_t *code
, size_t code_size
, ajla_error_t attr_unused
*err
)
303 #ifdef CODEGEN_USE_HEAP
304 os_code_invalidate_cache(code
, code_size
, !amalloc_enabled
);
307 size_t rounded_size
= round_up(code_size
, os_getpagesize());
308 void *ptr
= os_mmap(NULL
, rounded_size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANONYMOUS
, handle_none
, 0, err
);
309 if (unlikely(ptr
== MAP_FAILED
)) {
313 memcpy(ptr
, code
, code_size
);
314 os_code_invalidate_cache(ptr
, code_size
, true);
320 void os_code_unmap(void *mapped_code
, size_t attr_unused code_size
)
322 #ifdef CODEGEN_USE_HEAP
323 mem_free(mapped_code
);
325 size_t rounded_size
= round_up(code_size
, os_getpagesize());
326 os_munmap(mapped_code
, rounded_size
, false);
331 void os_block_signals(sig_state_t attr_unused
*set
)
333 #ifdef USE_SIGPROCMASK
337 sigdelset(&block
, SIGFPE
);
338 sigdelset(&block
, SIGTRAP
);
339 #ifdef USE_PTHREAD_SIGMASK
340 er
= pthread_sigmask(SIG_BLOCK
, &block
, set
);
342 fatal("pthread_sigmask failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
344 if (unlikely(sigprocmask(SIG_BLOCK
, &block
, set
))) {
346 fatal("sigprocmask failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
349 #elif defined(HAVE_SIGBLOCK) && defined(HAVE_SIGSETMASK)
350 sig_state_t s
= sigblock(~(sigmask(SIGFPE
) | sigmask(SIGTRAP
)));
356 void os_unblock_signals(const sig_state_t attr_unused
*set
)
358 #ifdef USE_SIGPROCMASK
360 #ifdef USE_PTHREAD_SIGMASK
361 er
= pthread_sigmask(SIG_SETMASK
, set
, NULL
);
363 fatal("pthread_sigmask failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
365 if (unlikely(sigprocmask(SIG_SETMASK
, set
, NULL
))) {
367 fatal("sigprocmask failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
370 #elif defined(HAVE_SIGBLOCK) && defined(HAVE_SIGSETMASK)
376 static void os_unblock_all_signals(void)
379 #ifdef USE_SIGPROCMASK
380 sigemptyset(&unblock
);
381 #elif defined(HAVE_SIGBLOCK) && defined(HAVE_SIGSETMASK)
384 os_unblock_signals(&unblock
);
389 void attr_cold
os_stop(void)
392 kill(getpid(), SIGSTOP
);
394 warning("stop not supported");
398 static inline void u_sleep(unsigned us
)
401 tv
.tv_sec
= us
/ 1000000;
402 tv
.tv_usec
= us
% 1000000;
403 select(0, NULL
, NULL
, NULL
, &tv
);
406 void os_background(void)
417 os_block_signals(&set
);
419 EINTR_LOOP(p
, fork());
421 os_unblock_signals(&set
);
426 * Note that this is racy. If we send SIGCONT too
427 * quickly, the ajla process will not be put to
434 os_unlock_fork(true);
439 * Another race - we must not send SIGKILL too quickly
443 EINTR_LOOP(r
, waitpid(p
, NULL
, 0));
447 bool os_foreground(void)
449 int sigttin
, sigttou
;
454 sigttin
= os_signal_handle("SIGTTIN", &seq
, NULL
);
455 sigttou
= os_signal_handle("SIGTTOU", &seq
, NULL
);
456 r
= tcgetattr(0, &tc
);
458 r
= tcsetattr(0, TCSANOW
, &tc
);
459 os_signal_unhandle(sigttin
);
460 os_signal_unhandle(sigttou
);
465 void os_set_cloexec(handle_t h
)
468 EINTR_LOOP(r
, fcntl(h
, F_SETFD
, FD_CLOEXEC
));
469 if (unlikely(r
== -1)) {
471 fatal("fcntl(F_SETFD, FD_CLOEXEC) failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
475 static char *os_call_getcwd(ajla_error_t
*err
)
479 size_t buf_size
= 32;
482 h
= mem_alloc_mayfail(char *, buf_size
, err
);
485 EINTR_LOOP_VAL(r
, NULL
, getcwd(h
, buf_size
));
487 if (errno
== ERANGE
) {
490 if (unlikely(!buf_size
)) {
491 fatal_mayfail(error_ajla(EC_ASYNC
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "overflow when allocating directory buffer");
496 e
= error_from_errno(EC_SYSCALL
, errno
);
497 fatal_mayfail(e
, err
, "can't get working directory: %s", error_decode(e
));
502 if (unlikely(h
[0] != '/')) {
503 e
= error_from_errno(EC_SYSCALL
, ENOENT
);
504 fatal_mayfail(e
, err
, "can't get working directory: %s", error_decode(e
));
513 static dir_handle_t
os_get_cwd(ajla_error_t
*err
)
515 #ifndef NO_DIR_HANDLES
517 #ifdef HAVE_AT_FUNCTIONS
518 if (likely(have_O_CLOEXEC_openat
)) {
519 EINTR_LOOP(h
, open(".", O_RDONLY
| O_CLOEXEC
, 0));
520 if (unlikely(h
== -1)) {
521 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
522 fatal_mayfail(e
, err
, "can't open the current directory: %s", error_decode(e
));
524 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
529 EINTR_LOOP(h
, open(".", O_RDONLY
, 0));
530 if (unlikely(h
== -1)) {
531 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
532 fatal_mayfail(e
, err
, "cam't open the current directory: %s", error_decode(e
));
534 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
540 return os_call_getcwd(err
);
544 bool os_set_cwd(dir_handle_t h
, ajla_error_t
*err
)
546 #ifndef NO_DIR_HANDLES
548 EINTR_LOOP(r
, fchdir(h
));
549 if (unlikely(r
== -1)) {
550 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
551 fatal_mayfail(e
, err
, "can't set directory: %s", error_decode(e
));
556 EINTR_LOOP(r
, chdir(h
));
557 if (unlikely(r
== -1)) {
558 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
559 fatal_mayfail(e
, err
, "can't set directory '%s': %s", h
, error_decode(e
));
566 void os_set_original_cwd(void)
570 if (likely(os_set_cwd(os_cwd
, &sink
)))
572 EINTR_LOOP(r
, chdir("/"));
573 if (unlikely(r
== -1)) {
575 fatal("unable to select root directory: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
579 static handle_t
os_open_internal(dir_handle_t dir
, const char *path
, int flags
, int mode
, bool want_dir
, ajla_error_t
*err
)
582 bool abs_path
= os_path_is_absolute(path
);
584 if (unlikely(!os_test_absolute_path(dir
, abs_path
, err
)))
589 flags
|= O_DIRECTORY
;
592 #ifdef HAVE_AT_FUNCTIONS
593 if (likely(have_O_CLOEXEC_openat
)) {
594 if (!dir_handle_is_valid(dir
)) {
595 EINTR_LOOP(h
, open(path
, flags
| O_CLOEXEC
, mode
));
597 EINTR_LOOP(h
, openat(dir
, path
, flags
| O_CLOEXEC
, mode
));
600 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
602 if (errno
== EACCES
&& want_dir
) {
603 EINTR_LOOP(h
, openat(dir
, path
, flags
| O_CLOEXEC
| O_PATH
, mode
));
608 fatal_mayfail(e
, err
, "can't open file '%s': %s", path
, error_decode(e
));
612 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
617 os_lock_fork(!abs_path
);
620 if (unlikely(!os_set_cwd(dir
, err
))) {
622 goto restore_dir_ret
;
626 EINTR_LOOP(h
, open(path
, flags
, mode
));
627 if (unlikely(h
== -1)) {
628 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
629 fatal_mayfail(e
, err
, "can't open file '%s': %s", path
, error_decode(e
));
630 goto restore_dir_ret
;
632 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
638 os_set_original_cwd();
641 os_unlock_fork(!abs_path
);
643 #ifdef HAVE_AT_FUNCTIONS
646 if (likely(h
!= -1)) {
649 if (!(flags
& (O_WRONLY
| O_RDWR
))) {
650 if (unlikely(!os_fstat(h
, &st
, err
))) {
651 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
652 fatal_mayfail(e
, err
, "fstat on file '%s' failed", path
);
655 } else if (unlikely(S_ISDIR(st
.st_mode
))) {
656 ajla_error_t e
= error_from_errno(EC_SYSCALL
, EISDIR
);
657 fatal_mayfail(e
, err
, "file '%s' is a directory", path
);
664 if (unlikely(!os_fstat(h
, &st
, err
))) {
665 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
666 fatal_mayfail(e
, err
, "fstat on file '%s' failed", path
);
669 } else if (unlikely(!S_ISDIR(st
.st_mode
))) {
670 ajla_error_t e
= error_from_errno(EC_SYSCALL
, ENOTDIR
);
671 fatal_mayfail(e
, err
, "file '%s' is not a directory", path
);
681 handle_t
os_open(dir_handle_t dir
, const char *path
, int flags
, int mode
, ajla_error_t
*err
)
686 return os_open_internal(dir
, path
, flags
, mode
, false, err
);
689 bool os_pipe(handle_t result
[2], int nonblock_flags
, ajla_error_t
*err
)
693 EINTR_LOOP(r
, pipe2(result
, O_CLOEXEC
| (nonblock_flags
== 3 ? O_NONBLOCK
: 0)));
694 if (likely(r
!= -1)) {
695 if (nonblock_flags
== 3) {
696 obj_registry_insert(OBJ_TYPE_HANDLE
, result
[0], file_line
);
697 obj_registry_insert(OBJ_TYPE_HANDLE
, result
[1], file_line
);
702 if (errno
!= ENOSYS
) {
703 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
704 fatal_mayfail(e
, err
, "can't create pipe: %s", error_decode(e
));
710 EINTR_LOOP(r
, pipe(result
));
711 if (unlikely(r
== -1)) {
712 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
713 os_unlock_fork(false);
714 fatal_mayfail(e
, err
, "can't create pipe: %s", error_decode(e
));
717 for (i
= 0; i
< 2; i
++)
718 os_set_cloexec(result
[i
]);
719 os_unlock_fork(false);
724 for (i
= 0; i
< 2; i
++) {
725 obj_registry_insert(OBJ_TYPE_HANDLE
, result
[i
], file_line
);
726 if (nonblock_flags
& (1 << i
)) {
727 EINTR_LOOP(r
, fcntl(result
[i
], F_SETFL
, O_NONBLOCK
));
728 if (unlikely(r
== -1)) {
730 fatal("fcntl(F_SETFL, O_NONBLOCK) on a pipe failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
737 void os_close_handle(handle_t h
)
741 internal(file_line
, "os_close: attempting to close invalid handle %d", h
);
742 EINTR_LOOP(r
, close(h
));
743 if (unlikely(r
== -1) && errno
== EBADF
)
744 internal(file_line
, "os_close: closing invalid handle %d", h
);
747 void os_close(handle_t h
)
749 obj_registry_remove(OBJ_TYPE_HANDLE
, h
, file_line
);
753 static unsigned n_std_handles
;
755 unsigned os_n_std_handles(void)
757 return n_std_handles
;
760 handle_t
os_get_std_handle(unsigned h
)
765 handle_t
os_number_to_handle(uintptr_t n
, bool attr_unused sckt
, ajla_error_t
*err
)
767 if (unlikely(n
!= (uintptr_t)(int)n
) || unlikely((int)n
< 0)) {
768 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), err
, "invalid handle");
771 obj_registry_insert(OBJ_TYPE_HANDLE
, (int)n
, file_line
);
776 static ssize_t
os_rdwr_return(int r
, const char *msg
, ajla_error_t
*err
)
778 if (unlikely(r
== -1)) {
780 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
781 return OS_RW_WOULDBLOCK
;
782 e
= error_from_errno(EC_SYSCALL
, errno
);
783 fatal_mayfail(e
, err
, "error %s data: %s", msg
, error_decode(e
));
789 ssize_t
os_read(handle_t h
, char *buffer
, int size
, ajla_error_t
*err
)
792 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
793 EINTR_LOOP(r
, read(h
, buffer
, size
));
794 return os_rdwr_return(r
, "reading", err
);
797 ssize_t
os_write(handle_t h
, const char *buffer
, int size
, ajla_error_t
*err
)
800 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
801 EINTR_LOOP(r
, write(h
, buffer
, size
));
803 * https://stackoverflow.com/questions/5656628/what-should-i-do-when-writefd-buf-count-returns-0
804 * Long, long ago, pre-POSIX, some systems returned 0 instead of EAGAIN.
806 if (unlikely(!r
) && size
)
807 return OS_RW_WOULDBLOCK
;
808 return os_rdwr_return(r
, "writing", err
);
811 ssize_t
os_pread(handle_t h
, char *buffer
, int size
, os_off_t off
, ajla_error_t
*err
)
814 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
815 #ifndef DO_LOCK_HANDLES
816 EINTR_LOOP(r
, pread(h
, buffer
, size
, off
));
818 address_lock(num_to_ptr(h
), DEPTH_HANDLE
);
819 EINTR_LOOP(off
, lseek(h
, off
, SEEK_SET
));
820 if (unlikely(off
== -1)) {
824 EINTR_LOOP(r
, read(h
, buffer
, size
));
826 address_unlock(num_to_ptr(h
), DEPTH_HANDLE
);
828 return os_rdwr_return(r
, "preading", err
);
831 ssize_t
os_pwrite(handle_t h
, const char *buffer
, int size
, os_off_t off
, ajla_error_t
*err
)
834 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
835 #ifndef DO_LOCK_HANDLES
836 EINTR_LOOP(r
, pwrite(h
, buffer
, size
, off
));
838 address_lock(num_to_ptr(h
), DEPTH_HANDLE
);
839 EINTR_LOOP(off
, lseek(h
, off
, SEEK_SET
));
840 if (unlikely(off
== -1)) {
844 EINTR_LOOP(r
, write(h
, buffer
, size
));
846 address_unlock(num_to_ptr(h
), DEPTH_HANDLE
);
848 return os_rdwr_return(r
, "pwriting", err
);
851 bool os_lseek(handle_t h
, unsigned mode
, os_off_t off
, os_off_t
*result
, ajla_error_t
*err
)
855 #ifdef DO_LOCK_HANDLES
856 address_lock(num_to_ptr(h
), DEPTH_HANDLE
);
873 EINTR_LOOP(res
, lseek(h
, 0, SEEK_END
));
874 if (unlikely(res
== -1))
876 if (unlikely(off
> res
))
890 default:internal(file_line
, "os_lseek: unsupported mode %u", mode
);
893 EINTR_LOOP(res
, lseek(h
, off
, whence
));
894 if (unlikely(res
== -1)) {
896 if (errno
== EINVAL
) {
907 if (errno
== ENXIO
&& mode
>= 3) {
914 e
= error_from_errno(EC_SYSCALL
, errno
);
915 fatal_mayfail(e
, err
, "can't lseek: %s", error_decode(e
));
920 #ifdef DO_LOCK_HANDLES
921 address_unlock(num_to_ptr(h
), DEPTH_HANDLE
);
925 #ifdef DO_LOCK_HANDLES
926 address_unlock(num_to_ptr(h
), DEPTH_HANDLE
);
931 bool os_ftruncate(handle_t h
, os_off_t size
, ajla_error_t
*err
)
934 EINTR_LOOP(r
, ftruncate(h
, size
));
935 if (unlikely(r
== -1)) {
936 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
937 fatal_mayfail(e
, err
, "ftruncate returned an error: %s", error_decode(e
));
943 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
)
945 #ifdef HAVE_FALLOCATE
949 /* EINTR may cause infinite loop */
953 os_block_signals(&set
);
954 EINTR_LOOP(r
, fallocate(h
, FALLOC_FL_KEEP_SIZE
, position
, size
));
955 os_unblock_signals(&set
);
958 r
= fallocate(h
, FALLOC_FL_KEEP_SIZE
, position
, size
);
959 if (unlikely(r
== -1) && errno
== EINTR
)
960 r
= fallocate(h
, FALLOC_FL_KEEP_SIZE
, position
, size
);
962 if (unlikely(r
== -1) && errno
!= EINTR
&& errno
!= ENOSYS
&& errno
!= EOPNOTSUPP
) {
963 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
964 fatal_mayfail(e
, err
, "fallocate returned an error: %s", error_decode(e
));
971 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
)
975 struct file_clone_range c
;
977 c
.src_offset
= src_pos
;
979 c
.dest_offset
= dst_pos
;
980 EINTR_LOOP(r
, ioctl(dst_h
, FICLONERANGE
, &c
));
981 if (unlikely(r
== -1)) {
982 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
983 fatal_mayfail(e
, err
, "clone range returned an error: %s", error_decode(e
));
988 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "clone not supported");
991 bool os_fsync(handle_t h
, unsigned mode
, ajla_error_t
*err
)
995 if (mode
== 0 || mode
== 1) {
996 EINTR_LOOP(r
, fcntl(h
, F_FULLFSYNC
));
1001 #if defined(HAVE_FDATASYNC) && !defined(__APPLE__)
1003 EINTR_LOOP(r
, fdatasync(h
));
1007 if (mode
== 0 || mode
== 1) {
1008 EINTR_LOOP(r
, fsync(h
));
1013 EINTR_LOOP(r
, syncfs(h
));
1017 if (mode
== 2 || mode
== 3) {
1021 internal(file_line
, "os_fsync: invalid mode %u", mode
);
1023 if (unlikely(r
== -1)) {
1024 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1025 fatal_mayfail(e
, err
, "fsync returned an error: %s", error_decode(e
));
1031 #if !defined(OS_DOS)
1032 ssize_t
os_read_console_packet(handle_t attr_unused h
, struct console_read_packet attr_unused
*result
, ajla_error_t
*err
)
1034 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "console packets not supported");
1038 bool os_write_console_packet(handle_t attr_unused h
, struct console_write_packet attr_unused
*packet
, ajla_error_t
*err
)
1040 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "console packets not supported");
1044 dir_handle_t
os_dir_root(ajla_error_t
*err
)
1046 const char *root
= "/";
1047 #ifndef NO_DIR_HANDLES
1048 return os_dir_open(dir_none
, root
, 0, err
);
1050 return str_dup(root
, -1, err
);
1055 dir_handle_t
os_dir_cwd(ajla_error_t
*err
)
1057 return os_dir_open(os_cwd
, ".", 0, err
);
1060 dir_handle_t
os_dir_open(dir_handle_t dir
, const char *path
, int attr_unused flags
, ajla_error_t
*err
)
1062 #ifndef NO_DIR_HANDLES
1063 return os_open_internal(dir
, path
, O_RDONLY
| flags
, 0, true, err
);
1067 if (unlikely(!os_test_absolute_path(dir
, os_path_is_absolute(path
), err
)))
1072 if (dir_handle_is_valid(dir
)) {
1073 if (unlikely(!os_set_cwd(dir
, err
))) {
1079 if (unlikely(!os_set_cwd((dir_handle_t
)path
, err
))) {
1084 ret
= os_get_cwd(err
);
1087 os_set_original_cwd();
1089 os_unlock_fork(true);
1094 void os_dir_close(dir_handle_t h
)
1096 #ifndef NO_DIR_HANDLES
1103 char *os_dir_path(dir_handle_t h
, ajla_error_t
*err
)
1105 #ifndef NO_DIR_HANDLES
1110 snprintf(lnk
, sizeof(lnk
), "/proc/self/fd/%u", h
);
1111 path
= os_readlink(dir_none
, lnk
, &sink
);
1112 if (likely(path
!= NULL
)) {
1114 char *deleted
= " (deleted)";
1115 if (unlikely(path
[0] != '/')) {
1117 goto skip_optimization
;
1120 dl
= strlen(deleted
);
1121 if (sl
>= dl
&& unlikely(!memcmp(path
+ sl
- dl
, deleted
, dl
))) {
1123 goto skip_optimization
;
1130 if (unlikely(!os_set_cwd(h
, err
))) {
1134 path
= os_call_getcwd(err
);
1135 os_set_original_cwd();
1137 os_unlock_fork(true);
1140 return str_dup(h
, -1, err
);
1144 static void os_close_DIR(DIR *d
)
1147 EINTR_LOOP(r
, closedir(d
));
1149 internal(file_line
, "os_close_DIR: closing invalid directory handle: %s", error_decode(error_from_errno(EC_SYSCALL
, errno
)));
1152 bool os_dir_read(dir_handle_t h
, char ***files
, size_t *n_files
, ajla_error_t
*err
)
1156 #if !defined(NO_DIR_HANDLES)
1159 if (unlikely(!os_set_cwd(h
, err
))) {
1160 os_set_original_cwd();
1161 os_unlock_fork(true);
1164 EINTR_LOOP_VAL(d
, NULL
, opendir("."));
1166 os_set_original_cwd();
1167 os_unlock_fork(true);
1170 EINTR_LOOP_VAL(d
, NULL
, opendir(h
));
1173 e
= error_from_errno(EC_SYSCALL
, errno
);
1174 fatal_mayfail(e
, err
, "can't open directory: %s", error_decode(e
));
1177 if (unlikely(!array_init_mayfail(char *, files
, n_files
, err
))) {
1187 if (unlikely(!de
)) {
1190 e
= error_from_errno(EC_SYSCALL
, errno
);
1191 fatal_mayfail(e
, err
, "error reading directory directory: %s", error_decode(e
));
1192 os_dir_free(*files
, *n_files
);
1196 if (unlikely(!strcmp(de
->d_name
, ".")) ||
1197 unlikely(!strcmp(de
->d_name
, "..")))
1199 fn
= mem_alloc_mayfail(char *, strlen(de
->d_name
) + 1, err
);
1200 if (unlikely(!fn
)) {
1201 os_dir_free(*files
, *n_files
);
1205 strcpy(fn
, de
->d_name
);
1206 array_add(char *, files
, n_files
, fn
);
1212 void os_dir_free(char **files
, size_t n_files
)
1215 for (i
= 0; i
< n_files
; i
++)
1221 unsigned os_dev_t_major(dev_t dev
)
1223 #if defined(HAVE_SYS_SYSMACROS_H) || defined(major)
1226 return (dev
>> 8) & 0xff;
1230 unsigned os_dev_t_minor(dev_t dev
)
1232 #if defined(HAVE_SYS_SYSMACROS_H) || defined(minor)
1239 bool os_fstat(handle_t h
, os_stat_t
*st
, ajla_error_t
*err
)
1242 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
1243 EINTR_LOOP(r
, fstat(h
, st
));
1244 if (unlikely(r
== -1)) {
1246 if (unlikely(errno
== EBADF
))
1247 internal(file_line
, "os_fstat: invalid handle %d", h
);
1248 e
= error_from_errno(EC_SYSCALL
, errno
);
1249 fatal_mayfail(e
, err
, "can't stat file handle: %s", error_decode(e
));
1255 bool os_stat(dir_handle_t dir
, const char *path
, bool attr_unused lnk
, os_stat_t
*st
, ajla_error_t
*err
)
1258 bool abs_path
= os_path_is_absolute(path
);
1260 if (unlikely(!os_test_absolute_path(dir
, abs_path
, err
)))
1263 #ifdef HAVE_AT_FUNCTIONS
1264 if (likely(have_O_CLOEXEC_openat
) && dir_handle_is_valid(dir
)) {
1265 EINTR_LOOP(r
, fstatat(dir
, path
, st
, lnk
? AT_SYMLINK_NOFOLLOW
: 0));
1266 if (unlikely(r
== -1)) {
1267 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1268 fatal_mayfail(e
, err
, "can't open file '%s': %s", path
, error_decode(e
));
1275 if (unlikely(!os_set_cwd(dir
, err
))) {
1282 EINTR_LOOP(r
, (!lnk
? stat
: lstat
)(path
, st
));
1284 EINTR_LOOP(r
, stat(path
, st
));
1286 if (unlikely(r
== -1)) {
1287 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1288 fatal_mayfail(e
, err
, "can't open file '%s': %s", path
, error_decode(e
));
1293 os_set_original_cwd();
1294 os_unlock_fork(true);
1300 #if (defined(HAVE_FSTATFS) && !defined(HAVE_FSTATVFS)) || (defined(HAVE_STATFS) && !defined(HAVE_STATVFS))
1301 static inline void attr_unused
statfs_2_statvfs(struct statfs
*stfs
, os_statvfs_t
*st
)
1303 memset(st
, 0, sizeof(os_statvfs_t
));
1304 #if defined(__linux__)
1305 st
->f_bsize
= stfs
->f_bsize
;
1306 st
->f_frsize
= stfs
->f_bsize
;
1307 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
1308 st
->f_bsize
= stfs
->f_iosize
;
1309 st
->f_frsize
= stfs
->f_bsize
;
1311 st
->f_bsize
= stfs
->f_bsize
;
1312 st
->f_frsize
= stfs
->f_bsize
;
1314 st
->f_blocks
= stfs
->f_blocks
;
1315 st
->f_bfree
= stfs
->f_bfree
;
1316 st
->f_bavail
= stfs
->f_bavail
;
1317 st
->f_files
= stfs
->f_files
;
1318 st
->f_ffree
= stfs
->f_ffree
;
1319 st
->f_favail
= stfs
->f_ffree
;
1320 memcpy(&st
->f_fsid
, &stfs
->f_fsid
, minimum(sizeof(st
->f_fsid
), sizeof(stfs
->f_fsid
)));
1321 #if defined(__linux__)
1322 st
->f_namemax
= stfs
->f_namelen
;
1323 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
1324 st
->f_namemax
= stfs
->f_namemax
;
1326 st
->f_namemax
= 255;
1331 bool os_fstatvfs(handle_t h
, os_statvfs_t
*st
, ajla_error_t
*err
)
1335 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
1336 #if defined(HAVE_FSTATVFS)
1337 EINTR_LOOP(r
, fstatvfs(h
, st
));
1338 if (unlikely(r
== -1))
1341 #elif defined(HAVE_FSTATFS)
1344 EINTR_LOOP(r
, fstatfs(h
, &stfs
));
1345 if (unlikely(r
== -1))
1347 statfs_2_statvfs(&stfs
, st
);
1351 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "the system doesn't support mprotect");
1356 if (unlikely(errno
== EBADF
))
1357 internal(file_line
, "os_fstatvfs: invalid handle %d", h
);
1358 e
= error_from_errno(EC_SYSCALL
, errno
);
1359 fatal_mayfail(e
, err
, "can't fstatvfs file handle: %s", error_decode(e
));
1363 bool os_dstatvfs(dir_handle_t dir
, os_statvfs_t
*st
, ajla_error_t
*err
)
1365 ajla_error_t attr_unused e
;
1367 #ifndef NO_DIR_HANDLES
1368 return os_fstatvfs(dir
, st
, err
);
1369 #elif defined(HAVE_STATVFS)
1370 EINTR_LOOP(r
, statvfs(dir
, st
));
1371 if (unlikely(r
== -1))
1374 #elif defined(HAVE_STATFS)
1377 EINTR_LOOP(r
, statfs(dir
, &stfs
));
1378 if (unlikely(r
== -1))
1380 statfs_2_statvfs(&stfs
, st
);
1384 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "the system doesn't support mprotect");
1389 e
= error_from_errno(EC_SYSCALL
, errno
);
1390 fatal_mayfail(e
, err
, "can't statvfs directory: %s", error_decode(e
));
1394 char *os_readlink(dir_handle_t attr_unused dir
, const char attr_unused
*path
, ajla_error_t
*err
)
1396 #ifdef HAVE_READLINK
1397 size_t buf_size
= 32;
1400 bool abs_path
= os_path_is_absolute(path
);
1402 if (unlikely(!os_test_absolute_path(dir
, abs_path
, err
)))
1406 buf
= mem_alloc_mayfail(char *, buf_size
, err
);
1410 #ifdef HAVE_AT_FUNCTIONS
1411 if (likely(have_O_CLOEXEC_openat
)) {
1412 EINTR_LOOP(r
, readlinkat(dir
, path
, buf
, buf_size
));
1418 if (unlikely(!os_set_cwd(dir
, err
))) {
1419 os_unlock_fork(true);
1425 EINTR_LOOP(r
, readlink(path
, buf
, buf_size
));
1429 os_set_original_cwd();
1430 os_unlock_fork(true);
1434 #ifdef HAVE_AT_FUNCTIONS
1437 if (unlikely(r
== -1)) {
1438 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1439 fatal_mayfail(e
, err
, "can't read link '%s': %s", path
, error_decode(e
));
1443 if (unlikely((size_t)r
== buf_size
)) {
1446 if (unlikely((buf_size
* 2) == 0)) {
1447 fatal_mayfail(error_ajla(EC_ASYNC
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "overflow when allocating readlink buffer");
1457 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "readlink not supported");
1462 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
)
1465 bool abs_path
= os_path_is_absolute(path
);
1467 if (unlikely((mode
& ~07777) != 0)) {
1468 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), err
, "invalid mode: %d", mode
);
1472 if (unlikely(!os_test_absolute_path(dir
, abs_path
, err
)))
1475 #ifdef HAVE_AT_FUNCTIONS
1476 if (likely(have_O_CLOEXEC_openat
)) {
1477 if (!dir_handle_is_valid(dir
))
1481 EINTR_LOOP(r
, unlinkat(dir
, path
, 0));
1483 case IO_Action_Rm_Dir
:
1484 EINTR_LOOP(r
, unlinkat(dir
, path
, AT_REMOVEDIR
));
1486 case IO_Action_Mk_Dir
:
1487 EINTR_LOOP(r
, mkdirat(dir
, path
, mode
));
1489 case IO_Action_Mk_Pipe
:
1490 EINTR_LOOP(r
, mknodat(dir
, path
, mode
| S_IFIFO
, 0));
1492 case IO_Action_Mk_Socket
:
1493 EINTR_LOOP(r
, mknodat(dir
, path
, mode
| S_IFSOCK
, 0));
1495 case IO_Action_Mk_CharDev
:
1496 #if defined(HAVE_SYS_SYSMACROS_H) || defined(makedev)
1497 EINTR_LOOP(r
, mknodat(dir
, path
, mode
| S_IFCHR
, makedev(dev_major
, dev_minor
)));
1499 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkchardev not supported");
1503 case IO_Action_Mk_BlockDev
:
1504 #if defined(HAVE_SYS_SYSMACROS_H) || defined(makedev)
1505 EINTR_LOOP(r
, mknodat(dir
, path
, mode
| S_IFBLK
, makedev(dev_major
, dev_minor
)));
1507 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkblockdev not supported");
1511 case IO_Action_Mk_SymLink
:
1512 EINTR_LOOP(r
, symlinkat(syml
, dir
, path
));
1514 case IO_Action_ChMod
:
1515 EINTR_LOOP(r
, fchmodat(dir
, path
, mode
, 0));
1517 case IO_Action_ChOwn
:
1518 EINTR_LOOP(r
, fchownat(dir
, path
, dev_major
, dev_minor
, 0));
1520 case IO_Action_LChOwn
:
1521 EINTR_LOOP(r
, fchownat(dir
, path
, dev_major
, dev_minor
, AT_SYMLINK_NOFOLLOW
));
1523 case IO_Action_UTime
:
1524 case IO_Action_LUTime
: {
1525 struct timespec ts
[2];
1526 ts
[0].tv_sec
= dev_minor
/ 1000000;
1527 ts
[0].tv_nsec
= dev_minor
% 1000000 * 1000;
1528 ts
[1].tv_sec
= dev_major
/ 1000000;
1529 ts
[1].tv_nsec
= dev_major
% 1000000 * 1000;
1530 EINTR_LOOP(r
, utimensat(dir
, path
, ts
, action
== IO_Action_UTime
? 0 : AT_SYMLINK_NOFOLLOW
));
1534 internal(file_line
, "os_dir_action: invalid action %d", action
);
1542 if (unlikely(!os_set_cwd(dir
, err
))) {
1543 os_unlock_fork(true);
1550 EINTR_LOOP(r
, unlink(path
));
1552 case IO_Action_Rm_Dir
:
1553 EINTR_LOOP(r
, rmdir(path
));
1555 case IO_Action_Mk_Dir
:
1556 EINTR_LOOP(r
, mkdir(path
, mode
));
1559 * Minix 3 returns EACCES when attempting to make the
1560 * home directory. So we test if the directory exists
1561 * and return EEXIST if it does.
1563 if (r
== -1 && errno
== EACCES
) {
1566 EINTR_LOOP(rr
, stat(path
, &st
));
1574 case IO_Action_Mk_Pipe
:
1576 EINTR_LOOP(r
, mknod(path
, mode
| S_IFIFO
, 0));
1578 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkpipe not supported");
1582 case IO_Action_Mk_Socket
:
1583 #if defined(HAVE_MKNOD) && defined(S_IFSOCK)
1584 EINTR_LOOP(r
, mknod(path
, mode
| S_IFSOCK
, 0));
1586 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mksocket not supported");
1590 case IO_Action_Mk_CharDev
:
1591 #if defined(HAVE_MKNOD) && (defined(HAVE_SYS_SYSMACROS_H) || defined(makedev))
1592 EINTR_LOOP(r
, mknod(path
, mode
| S_IFCHR
, makedev(dev_major
, dev_minor
)));
1594 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkchardev not supported");
1598 case IO_Action_Mk_BlockDev
:
1599 #if defined(HAVE_MKNOD) && (defined(HAVE_SYS_SYSMACROS_H) || defined(makedev))
1600 EINTR_LOOP(r
, mknod(path
, mode
| S_IFBLK
, makedev(dev_major
, dev_minor
)));
1602 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "mkblockdev not supported");
1606 case IO_Action_Mk_SymLink
:
1608 EINTR_LOOP(r
, symlink(syml
, path
));
1610 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "symlink not supported");
1614 case IO_Action_ChMod
:
1615 EINTR_LOOP(r
, chmod(path
, mode
));
1617 case IO_Action_LChOwn
: {
1619 EINTR_LOOP(r
, lchown(path
, dev_major
, dev_minor
));
1623 EINTR_LOOP(r
, lstat(path
, &st
));
1626 if (S_ISLNK(st
.st_mode
))
1631 case IO_Action_ChOwn
:
1633 EINTR_LOOP(r
, chown(path
, dev_major
, dev_minor
));
1635 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "chown not supported");
1639 case IO_Action_LUTime
: {
1641 EINTR_LOOP(r
, lstat(path
, &st
));
1644 if (S_ISLNK(st
.st_mode
)) {
1651 case IO_Action_UTime
: {
1652 #if defined(HAVE_UTIMES)
1653 struct timeval ts
[2];
1654 ts
[0].tv_sec
= dev_minor
/ 1000000;
1655 ts
[0].tv_usec
= dev_minor
% 1000000;
1656 ts
[1].tv_sec
= dev_major
/ 1000000;
1657 ts
[1].tv_usec
= dev_major
% 1000000;
1658 EINTR_LOOP(r
, utimes(cast_ptr(char *, path
), ts
));
1660 #elif defined(HAVE_UTIME)
1662 tm
.actime
= dev_minor
/ 1000000;
1663 tm
.modtime
= dev_major
/ 1000000;
1664 EINTR_LOOP(r
, times(path
, &tm
));
1667 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "utime not supported");
1671 internal(file_line
, "os_dir_action: invalid action %d", action
);
1676 os_set_original_cwd();
1677 os_unlock_fork(true);
1681 #ifdef HAVE_AT_FUNCTIONS
1684 if (unlikely(r
== -1)) {
1685 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1686 fatal_mayfail(e
, err
, "can't perform action %d on '%s': %s", action
, path
, error_decode(e
));
1694 os_set_original_cwd();
1695 os_unlock_fork(true);
1701 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
)
1705 char *dest_final_path
= NULL
;
1706 char *src_final_path
= NULL
;
1707 bool abs_dest_path
= os_path_is_absolute(dest_path
);
1708 bool abs_src_path
= os_path_is_absolute(src_path
);
1710 if (unlikely(!os_test_absolute_path(dest_dir
, abs_dest_path
, err
)))
1712 if (unlikely(!os_test_absolute_path(src_dir
, abs_src_path
, err
)))
1715 #ifdef HAVE_AT_FUNCTIONS
1716 if (likely(have_O_CLOEXEC_openat
)) {
1717 if (!dir_handle_is_valid(dest_dir
))
1718 dest_dir
= AT_FDCWD
;
1719 if (!dir_handle_is_valid(src_dir
))
1722 case IO_Action_Mk_Link
:
1723 EINTR_LOOP(r
, linkat(src_dir
, src_path
, dest_dir
, dest_path
, 0));
1725 case IO_Action_Rename
:
1726 EINTR_LOOP(r
, renameat(src_dir
, src_path
, dest_dir
, dest_path
));
1729 internal(file_line
, "os_dir2_action: invalid action %d", action
);
1735 if (abs_dest_path
) {
1736 dest_final_path
= str_dup(dest_path
, -1, err
);
1737 if (unlikely(!dest_final_path
)) {
1742 char *dest_dir_path
= os_dir_path(dest_dir
, err
);
1743 if (unlikely(!dest_dir_path
)) {
1747 dest_final_path
= os_join_paths(dest_dir_path
, dest_path
, true, err
);
1748 if (unlikely(!dest_final_path
)) {
1749 mem_free(dest_dir_path
);
1753 mem_free(dest_dir_path
);
1754 dest_dir_path
= NULL
;
1757 src_final_path
= str_dup(src_path
, -1, err
);
1758 if (unlikely(!src_final_path
)) {
1763 char *src_dir_path
= os_dir_path(src_dir
, err
);
1764 if (unlikely(!src_dir_path
)) {
1768 src_final_path
= os_join_paths(src_dir_path
, src_path
, true, err
);
1769 if (unlikely(!src_final_path
)) {
1770 mem_free(src_dir_path
);
1774 mem_free(src_dir_path
);
1775 src_dir_path
= NULL
;
1779 case IO_Action_Mk_Link
:
1781 EINTR_LOOP(r
, link(src_final_path
, dest_final_path
));
1783 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "link not supported");
1788 case IO_Action_Rename
:
1789 EINTR_LOOP(r
, rename(src_final_path
, dest_final_path
));
1792 internal(file_line
, "os_dir2_action: invalid action %d", action
);
1796 #ifdef HAVE_AT_FUNCTIONS
1799 if (unlikely(r
== -1)) {
1800 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1801 fatal_mayfail(e
, err
, "can't perform action %d on '%s' and '%s': %s", action
, src_path
, dest_path
, error_decode(e
));
1808 if (dest_final_path
)
1809 mem_free(dest_final_path
);
1811 mem_free(src_final_path
);
1815 #if !defined(OS_DOS)
1817 bool os_drives(char **drives
, size_t *drives_l
, ajla_error_t
*err
)
1819 #if defined(OS_CYGWIN)
1820 uint32_t mask
= GetLogicalDrives();
1821 return os_drives_bitmap(mask
, drives
, drives_l
, err
);
1822 #elif defined(HAVE_GETFSSTAT) || defined(HAVE_GETVFSFSSTAT)
1825 #if defined(HAVE_GETVFSSTAT)
1826 struct statvfs
*buf
;
1833 #if defined(HAVE_GETVFSSTAT)
1834 buf
= mem_alloc_array_mayfail(mem_alloc_mayfail
, struct statvfs
*, 0, 0, n_entries
, sizeof(struct statvfs
), err
);
1836 buf
= mem_alloc_array_mayfail(mem_alloc_mayfail
, struct statfs
*, 0, 0, n_entries
, sizeof(struct statfs
), err
);
1840 #if defined(HAVE_GETVFSSTAT)
1841 EINTR_LOOP(r
, getvfsstat(buf
, sizeof(struct statvfs
) * n_entries
, ST_NOWAIT
));
1843 EINTR_LOOP(r
, getfsstat(buf
, sizeof(struct statfs
) * n_entries
, MNT_NOWAIT
));
1845 if (unlikely(r
== -1)) {
1846 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1847 fatal_mayfail(e
, err
, "getfsstat failed: %s", error_decode(e
));
1851 if (r
>= n_entries
) {
1854 if (unlikely(n_entries
< 0)) {
1855 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "getfsstat buffer overflow");
1861 if (unlikely(!array_init_mayfail(char, drives
, drives_l
, err
))) {
1866 for (i
= 0; i
< r
; i
++) {
1869 if (buf
[i
].f_blocks
<= 2)
1871 str
= buf
[i
].f_mntonname
;
1872 str_l
= strlen(str
) + 1;
1873 if (unlikely(!array_add_multiple_mayfail(char, drives
, drives_l
, str
, str_l
, NULL
, err
))) {
1882 if (unlikely(!array_init_mayfail(char, drives
, drives_l
, err
)))
1891 bool os_tcgetattr(handle_t h
, os_termios_t
*t
, ajla_error_t
*err
)
1894 EINTR_LOOP(r
, tcgetattr(h
, t
));
1895 if (unlikely(r
== -1)) {
1896 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1897 fatal_mayfail(e
, err
, "tcgetattr failed: %s", error_decode(e
));
1903 bool os_tcsetattr(handle_t h
, const os_termios_t
*t
, ajla_error_t
*err
)
1906 EINTR_LOOP(r
, tcsetattr(h
, TCSANOW
, cast_ptr(os_termios_t
*, t
)));
1907 if (unlikely(r
== -1)) {
1908 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1909 fatal_mayfail(e
, err
, "tcsetattr failed: %s", error_decode(e
));
1915 void os_tcflags(os_termios_t
*t
, int flags
)
1917 if (flags
& IO_Stty_Flag_Raw
) {
1918 #ifdef HAVE_CFMAKERAW
1922 t
->c_iflag
&= ~(IGNBRK
|BRKINT
|PARMRK
|ISTRIP
|INLCR
|IGNCR
|ICRNL
|IXON
);
1923 t
->c_oflag
&= ~OPOST
;
1924 t
->c_lflag
&= ~(ECHO
|ECHONL
|ICANON
|ISIG
|IEXTEN
);
1925 t
->c_cflag
&= ~(CSIZE
|PARENB
);
1931 if (flags
& IO_Stty_Flag_Noecho
)
1932 t
->c_lflag
&= ~ECHO
;
1935 if (flags
& IO_Stty_Flag_Nosignal
)
1936 t
->c_lflag
&= ~ISIG
;
1939 if (flags
& IO_Stty_Flag_NoCRLF
)
1940 t
->c_oflag
&= ~OPOST
;
1942 t
->c_oflag
|= OPOST
;
1945 bool os_tty_size(handle_t h
, int *nx
, int *ny
, int *ox
, int *oy
, ajla_error_t
*err
)
1949 signal_seq_t attr_unused seq
;
1951 EINTR_LOOP(r
, ioctl(h
, TIOCGWINSZ
, &ws
));
1952 if (unlikely(r
== -1)) {
1953 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
1954 fatal_mayfail(e
, err
, "ioctl(TIOCGWINSZ) failed: %s", error_decode(e
));
1967 static char *os_path_to_exe
;
1969 static void os_init_path_to_exe(void)
1972 char *path
, *component
, *test_path
;
1977 char *ptexe
= os_readlink(dir_none
, "/proc/self/exe", &sink
);
1978 if (likely(ptexe
!= NULL
)) {
1979 if (likely(ptexe
[0] == '/')) {
1981 for (i
= 0; ptexe
[i
]; i
++)
1982 if (unlikely(os_is_path_separator(ptexe
[i
])))
1985 os_path_to_exe
= ptexe
;
1992 for (i
= 0; arg0
[i
]; i
++)
1993 if (unlikely(os_is_path_separator(arg0
[i
])))
1996 component
= str_dup(arg0
, sep
, NULL
);
2000 path
= getenv("PATH");
2002 component
= str_dup(".", -1, NULL
);
2007 while (path
[i
] && !os_is_env_separator(path
[i
]))
2009 component
= str_dup(path
, i
, NULL
);
2010 test_path
= os_join_paths(component
, arg0
, true, NULL
);
2011 if (os_stat(os_cwd
, test_path
, false, &st
, &sink
)) {
2012 mem_free(test_path
);
2015 mem_free(test_path
);
2016 mem_free(component
);
2019 goto next_component
;
2021 warning("could not find executable in path");
2022 component
= str_dup(".", -1, NULL
);
2024 if (os_path_is_absolute(component
)) {
2025 os_path_to_exe
= component
;
2028 dh
= os_dir_open(os_cwd
, component
, 0, NULL
);
2029 os_path_to_exe
= os_dir_path(dh
, NULL
);
2031 mem_free(component
);
2034 const char *os_get_path_to_exe(void)
2036 return os_path_to_exe
;
2040 ajla_time_t
os_time_t_to_ajla_time(time_t sec
)
2042 return (ajla_time_t
)sec
* 1000000;
2045 static ajla_time_t
os_timeval_to_ajla_time(const struct timeval
*tv
)
2047 return os_time_t_to_ajla_time(tv
->tv_sec
) + tv
->tv_usec
;
2050 #ifdef HAVE_STRUCT_TIMESPEC
2051 ajla_time_t
os_timespec_to_ajla_time(const struct timespec
*ts
)
2053 return os_time_t_to_ajla_time(ts
->tv_sec
) + ts
->tv_nsec
/ 1000;
2057 ajla_time_t
os_time_real(void)
2061 EINTR_LOOP(r
, gettimeofday(&tv
, NULL
));
2062 if (unlikely(r
== -1)) {
2064 fatal("gettimeofday failed: %d, %s", e
, error_decode(error_from_errno(EC_SYSCALL
, e
)));
2066 return os_timeval_to_ajla_time(&tv
);
2069 ajla_time_t
os_time_monotonic(void)
2071 #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
2074 EINTR_LOOP(r
, clock_gettime(CLOCK_MONOTONIC
, &ts
));
2075 if (unlikely(r
== -1)) {
2077 fatal("clock_gettime(%d) failed: %d, %s", (int)CLOCK_MONOTONIC
, e
, error_decode(error_from_errno(EC_SYSCALL
, e
)));
2079 return os_timespec_to_ajla_time(&ts
);
2081 return os_time_real();
2086 #if !defined(OS_DOS)
2088 static bool spawn_process_handles(unsigned n_handles
, handle_t
*src
, int *target
)
2092 handle_t max_handle
= 3;
2093 for (i
= 0; i
< n_handles
; i
++) {
2094 if (unlikely(src
[i
] >= signed_maximum(int) / 2) ||
2095 unlikely(target
[i
] >= signed_maximum(int) / 2))
2097 if (src
[i
] >= max_handle
) max_handle
= src
[i
] + 1;
2098 if (target
[i
] >= max_handle
) max_handle
= target
[i
] + 1;
2100 for (i
= 0; i
< n_handles
; i
++) {
2101 EINTR_LOOP(r
, dup2(src
[i
], max_handle
+ i
));
2102 if (unlikely(r
== -1))
2104 /*os_close_handle(src[i]);*/
2106 for (i
= 0; i
< n_handles
; i
++) {
2107 EINTR_LOOP(r
, close(src
[i
]));
2109 EINTR_LOOP(r
, close(0));
2110 EINTR_LOOP(r
, close(1));
2111 EINTR_LOOP(r
, close(2));
2112 for (i
= 0; i
< n_handles
; i
++) {
2113 EINTR_LOOP(r
, dup2(max_handle
+ i
, target
[i
]));
2114 if (unlikely(r
== -1))
2116 os_close_handle(max_handle
+ i
);
2118 for (i
= 0; i
< n_handles
; i
++) {
2119 EINTR_LOOP(r
, fcntl(target
[i
], F_GETFL
));
2120 if (likely(r
>= 0) && r
& O_NONBLOCK
) {
2123 EINTR_LOOP(ir
, fcntl(target
[i
], F_SETFL
, r
));
2129 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
)
2138 os_block_signals(&set
);
2140 EINTR_LOOP(p
, fork());
2142 os_unblock_signals(&set
);
2146 if (unlikely(!os_set_cwd(wd
, &sink
)))
2148 if (unlikely(!spawn_process_handles(n_handles
, src
, target
)))
2150 os_unblock_all_signals();
2151 EINTR_LOOP(r
, execve(path
, args
, env
));
2154 os_unlock_fork(true);
2156 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2157 fatal_mayfail(e
, err
, "can't spawn process '%s': %s", path
, error_decode(e
));
2164 struct proc_handle
{
2165 struct tree_entry entry
;
2171 struct list wait_list
;
2174 static struct tree proc_tree
;
2175 static mutex_t proc_tree_mutex
;
2177 static inline void proc_lock(void)
2179 mutex_lock(&proc_tree_mutex
);
2182 static inline void proc_unlock(void)
2184 mutex_unlock(&proc_tree_mutex
);
2187 static void proc_handle_free(struct proc_handle
*ph
)
2189 os_signal_unhandle(ph
->sigchld
);
2193 static int proc_handle_compare(const struct tree_entry
*e
, uintptr_t pid
)
2195 const struct proc_handle
*ph
= get_struct(e
, struct proc_handle
, entry
);
2196 if (unlikely(ph
->pid
== (pid_t
)pid
)) return 0;
2197 if (ph
->pid
> (pid_t
)pid
) return 1;
2201 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
)
2203 struct proc_handle
*ph
;
2205 struct tree_insert_position ins
;
2206 struct tree_entry
*e
;
2211 if (unlikely(!array_init_mayfail(char *, &env
, &env_l
, err
)))
2214 if (unlikely(!array_add_mayfail(char *, &env
, &env_l
, envc
, NULL
, err
)))
2216 envc
= strchr(envc
, 0) + 1;
2218 if (unlikely(!array_add_mayfail(char *, &env
, &env_l
, NULL
, NULL
, err
)))
2221 ph
= mem_alloc_mayfail(struct proc_handle
*, sizeof(struct proc_handle
), err
);
2222 if (unlikely(!ph
)) {
2227 ph
->detached
= false;
2228 list_init(&ph
->wait_list
);
2229 ph
->sigchld
= os_signal_handle("SIGCHLD", &seq
, err
);
2230 if (unlikely(ph
->sigchld
< 0)) {
2235 if (unlikely(!ph
->sigchld
))
2236 iomux_enable_poll();
2240 if (unlikely(!os_fork(wd
, path
, n_handles
, src
, target
, args
, env
, &ph
->pid
, err
))) {
2243 proc_handle_free(ph
);
2247 e
= tree_find_for_insert(&proc_tree
, proc_handle_compare
, ph
->pid
, &ins
);
2248 if (unlikely(e
!= NULL
)) {
2249 fatal("pid %ld is already present in the tree", (long)ph
->pid
);
2252 tree_insert_after_find(&ph
->entry
, &ins
);
2261 void os_proc_free_handle(struct proc_handle
*ph
)
2264 ajla_assert_lo(list_is_empty(&ph
->wait_list
), (file_line
, "os_proc_free_handle: freeing handle when there are processes waiting for it"));
2267 proc_handle_free(ph
);
2269 ph
->detached
= true;
2274 bool os_proc_register_wait(struct proc_handle
*ph
, mutex_t
**mutex_to_lock
, struct list
*list_entry
, int *status
)
2278 *status
= ph
->status
;
2282 *mutex_to_lock
= &proc_tree_mutex
;
2283 list_add(&ph
->wait_list
, list_entry
);
2289 static void process_pid_and_status(pid_t pid
, int status
)
2291 struct tree_entry
*e
;
2292 struct proc_handle
*ph
;
2296 e
= tree_find(&proc_tree
, proc_handle_compare
, pid
);
2302 ph
= get_struct(e
, struct proc_handle
, entry
);
2305 if (WIFEXITED(status
)) {
2306 ph
->status
= WEXITSTATUS(status
);
2307 } else if (WIFSIGNALED(status
)) {
2308 ph
->status
= -WTERMSIG(status
);
2314 tree_delete(&ph
->entry
);
2316 if (!ph
->detached
) {
2317 call(wake_up_wait_list
)(&ph
->wait_list
, &proc_tree_mutex
, true);
2319 proc_handle_free(ph
);
2324 static attr_noinline
void proc_check_owned(void)
2326 struct tree_entry
*e
;
2327 struct proc_handle
*ph
;
2334 e
= tree_find_next(&proc_tree
, proc_handle_compare
, pid
);
2339 ph
= get_struct(e
, struct proc_handle
, entry
);
2343 EINTR_LOOP(r
, waitpid(pid
, &status
, WNOHANG
));
2347 process_pid_and_status(pid
, status
);
2351 void os_proc_check_all(void)
2357 if (likely(tree_is_empty(&proc_tree
))) {
2365 EINTR_LOOP(pid
, waitpid(-1, &status
, WNOHANG
));
2366 if (unlikely(pid
> 0)) {
2367 process_pid_and_status(pid
, status
);
2378 #ifdef OS_HAS_SIGNALS
2380 #if defined(SIGRTMAX)
2381 #define N_SIGNALS (int)(SIGRTMAX + 1)
2383 #define N_SIGNALS (int)NSIG
2385 #define N_SIGNALS 32
2388 struct signal_state
{
2389 thread_volatile signal_seq_t sig_sequence
;
2390 signal_seq_t last_sig_sequence
;
2393 struct list wait_list
;
2394 struct sigaction prev_sa
;
2397 static struct signal_state
*signal_states
;
2398 static mutex_t signal_state_mutex
;
2400 static void signal_handler(int sig
)
2402 signal_states
[sig
].sig_sequence
+= 1UL;
2406 static int os_signal_number(const char *str
)
2409 if (!strcmp(str
, "SIGABRT")) return SIGABRT
;
2412 if (!strcmp(str
, "SIGALRM")) return SIGALRM
;
2415 if (!strcmp(str
, "SIGBUS")) return SIGBUS
;
2418 if (!strcmp(str
, "SIGCHLD")) return SIGCHLD
;
2421 if (!strcmp(str
, "SIGCLD")) return SIGCLD
;
2424 if (!strcmp(str
, "SIGCONT")) return SIGCONT
;
2427 if (!strcmp(str
, "SIGEMT")) return SIGEMT
;
2430 if (!strcmp(str
, "SIGFPE")) return SIGFPE
;
2433 if (!strcmp(str
, "SIGHUP")) return SIGHUP
;
2436 if (!strcmp(str
, "SIGILL")) return SIGILL
;
2439 if (!strcmp(str
, "SIGINFO")) return SIGINFO
;
2442 if (!strcmp(str
, "SIGINT")) return SIGINT
;
2445 if (!strcmp(str
, "SIGIO")) return SIGIO
;
2448 if (!strcmp(str
, "SIGIOT")) return SIGIOT
;
2451 if (!strcmp(str
, "SIGKILL")) return SIGKILL
;
2454 if (!strcmp(str
, "SIGLOST")) return SIGLOST
;
2457 if (!strcmp(str
, "SIGPIPE")) return SIGPIPE
;
2460 if (!strcmp(str
, "SIGPOLL")) return SIGPOLL
;
2463 if (!strcmp(str
, "SIGPROF")) return SIGPROF
;
2466 if (!strcmp(str
, "SIGPWR")) return SIGPWR
;
2469 if (!strcmp(str
, "SIGQUIT")) return SIGQUIT
;
2472 if (!strcmp(str
, "SIGSEGV")) return SIGSEGV
;
2475 if (!strcmp(str
, "SIGSTKFLT")) return SIGSTKFLT
;
2478 if (!strcmp(str
, "SIGSTOP")) return SIGSTOP
;
2481 if (!strcmp(str
, "SIGTSTP")) return SIGTSTP
;
2484 if (!strcmp(str
, "SIGSYS")) return SIGSYS
;
2487 if (!strcmp(str
, "SIGTERM")) return SIGTERM
;
2490 if (!strcmp(str
, "SIGTRAP")) return SIGTRAP
;
2493 if (!strcmp(str
, "SIGTTIN")) return SIGTTIN
;
2496 if (!strcmp(str
, "SIGTTOU")) return SIGTTOU
;
2499 if (!strcmp(str
, "SIGUNUSED")) return SIGUNUSED
;
2502 if (!strcmp(str
, "SIGURG")) return SIGURG
;
2505 if (!strcmp(str
, "SIGUSR1")) return SIGUSR1
;
2508 if (!strcmp(str
, "SIGUSR2")) return SIGUSR2
;
2511 if (!strcmp(str
, "SIGVTALRM")) return SIGVTALRM
;
2514 if (!strcmp(str
, "SIGWINCH")) return SIGWINCH
;
2517 if (!strcmp(str
, "SIGXCPU")) return SIGXCPU
;
2520 if (!strcmp(str
, "SIGXFSZ")) return SIGXFSZ
;
2522 #if defined(SIGRTMIN) && defined(SIGRTMAX)
2523 if (!strncmp(str
, "SIGRT", 5) && str
[5]) {
2525 unsigned long num
= strtoul(str
+ 5, &endptr
, 10);
2526 if (unlikely(*endptr
))
2529 if (unlikely(num
< (unsigned long)SIGRTMIN
) || unlikely(num
> (unsigned long)SIGRTMAX
))
2537 int os_signal_handle(const char *str
, signal_seq_t
*seq
, ajla_error_t
*err
)
2539 struct signal_state
*s
;
2540 int sig
= os_signal_number(str
);
2541 if (unlikely(!sig
)) {
2545 mutex_lock(&signal_state_mutex
);
2546 s
= &signal_states
[sig
];
2547 if (unlikely(s
->trapped
)) {
2548 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "signal %s already handled", str
);
2551 if (likely(!s
->refcount
)) {
2552 struct sigaction sa
;
2555 s
->sig_sequence
= 0;
2556 s
->last_sig_sequence
= 0;
2558 (void)memset(&sa
, 0, sizeof sa
);
2559 sa
.sa_handler
= signal_handler
;
2560 sigemptyset(&sa
.sa_mask
);
2562 if (sig
!= SIGTTIN
&& sig
!= SIGTTOU
)
2563 sa
.sa_flags
|= SA_RESTART
;
2565 EINTR_LOOP(r
, sigaction(sig
, &sa
, &s
->prev_sa
));
2566 if (unlikely(r
== -1)) {
2567 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2568 fatal_mayfail(e
, err
, "sigaction(%d) failed: %s", sig
, error_decode(e
));
2573 *seq
= s
->last_sig_sequence
;
2574 mutex_unlock(&signal_state_mutex
);
2578 mutex_unlock(&signal_state_mutex
);
2582 static void os_signal_restore(struct signal_state
*s
, int sig
)
2585 EINTR_LOOP(r
, sigaction(sig
, &s
->prev_sa
, NULL
));
2586 if (unlikely(r
== -1)) {
2587 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2588 fatal("sigaction(%d) failed: %s", sig
, error_decode(e
));
2592 void os_signal_unhandle(int sig
)
2594 struct signal_state
*s
;
2597 mutex_lock(&signal_state_mutex
);
2598 s
= &signal_states
[sig
];
2600 internal(file_line
, "os_signal_unhandle: refcount underflow");
2603 os_signal_restore(s
, sig
);
2604 mutex_unlock(&signal_state_mutex
);
2607 signal_seq_t
os_signal_seq(int sig
)
2609 struct signal_state
*s
;
2613 mutex_lock(&signal_state_mutex
);
2614 s
= &signal_states
[sig
];
2616 internal(file_line
, "os_signal_unhandle: unhandled signal");
2617 seq
= s
->last_sig_sequence
;
2618 mutex_unlock(&signal_state_mutex
);
2622 bool os_signal_wait(int sig
, signal_seq_t seq
, mutex_t
**mutex_to_lock
, struct list
*list_entry
)
2624 struct signal_state
*s
;
2626 if (unlikely(!sig
)) {
2627 iomux_never(mutex_to_lock
, list_entry
);
2631 mutex_lock(&signal_state_mutex
);
2632 s
= &signal_states
[sig
];
2633 if (unlikely(seq
!= s
->last_sig_sequence
)) {
2634 mutex_unlock(&signal_state_mutex
);
2637 *mutex_to_lock
= &signal_state_mutex
;
2638 list_add(&s
->wait_list
, list_entry
);
2639 mutex_unlock(&signal_state_mutex
);
2644 void os_signal_check_all(void)
2648 mutex_lock(&signal_state_mutex
);
2649 for (; sig
< N_SIGNALS
; sig
++) {
2650 struct signal_state
*s
= &signal_states
[sig
];
2651 signal_seq_t seq
= s
->sig_sequence
;
2652 if (unlikely(seq
!= s
->last_sig_sequence
)) {
2653 s
->last_sig_sequence
= seq
;
2654 call(wake_up_wait_list
)(&s
->wait_list
, &signal_state_mutex
, true);
2659 mutex_unlock(&signal_state_mutex
);
2662 #ifdef HAVE_CODEGEN_TRAPS
2664 void *u_data_trap_lookup(void *ptr
);
2665 void *c_data_trap_lookup(void *ptr
);
2667 static void sigfpe_handler(int attr_unused sig
, siginfo_t
*siginfo
, void *ucontext
)
2669 ucontext_t
*uc
= ucontext
;
2670 #if defined(ARCH_ALPHA)
2671 if (unlikely(siginfo
->si_code
!= FPE_FLTINV
))
2672 fatal("unexpected SIGFPE received: %d", siginfo
->si_code
);
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 uc
->uc_mcontext
.pc
= ptr_to_num(call(data_trap_lookup
)(num_to_ptr(uc
->uc_mcontext
.pc
)));
2685 void os_signal_trap(int sig
, void (*handler
)(int, siginfo_t
*, void *))
2687 if (OS_SUPPORTS_TRAPS
) {
2688 struct signal_state
*s
= &signal_states
[sig
];
2689 struct sigaction sa
;
2694 (void)memset(&sa
, 0, sizeof sa
);
2695 sa
.sa_sigaction
= handler
;
2696 sigemptyset(&sa
.sa_mask
);
2697 sa
.sa_flags
|= SA_SIGINFO
;
2698 EINTR_LOOP(r
, sigaction(sig
, &sa
, &s
->prev_sa
));
2699 if (unlikely(r
== -1)) {
2700 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2701 fatal("sigaction(%d) failed: %s", sig
, error_decode(e
));
2705 void os_signal_untrap(int sig
)
2707 if (OS_SUPPORTS_TRAPS
) {
2708 struct signal_state
*s
= &signal_states
[sig
];
2709 ajla_assert_lo(s
->trapped
, (file_line
, "os_signal_untrap: signal %d not trapped", sig
));
2710 os_signal_restore(s
, sig
);
2718 int os_signal_handle(const char attr_unused
*str
, signal_seq_t attr_unused
*seq
, ajla_error_t attr_unused
*err
)
2724 void os_signal_unhandle(int attr_unused sig
)
2728 signal_seq_t
os_signal_seq(int attr_unused sig
)
2733 bool os_signal_wait(int attr_unused sig
, signal_seq_t attr_unused seq
, mutex_t
**mutex_to_lock
, struct list
*list_entry
)
2735 iomux_never(mutex_to_lock
, list_entry
);
2739 void os_signal_check_all(void)
2748 handle_t
os_socket(int domain
, int type
, int protocol
, ajla_error_t
*err
)
2751 domain
= os_socket_pf(domain
, err
);
2752 if (unlikely(domain
== -1))
2754 type
= os_socket_type(type
, err
);
2755 if (unlikely(type
== -1))
2757 #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
2758 EINTR_LOOP(h
, socket(domain
, type
| SOCK_NONBLOCK
| SOCK_CLOEXEC
, protocol
));
2759 if (likely(h
!= -1)) {
2760 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
2763 if (errno
!= EINVAL
) {
2764 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2765 fatal_mayfail(e
, err
, "can't create socket (%d, %d, %d): %s", domain
, type
, protocol
, error_decode(e
));
2769 os_lock_fork(false);
2770 EINTR_LOOP(h
, socket(domain
, type
, protocol
));
2771 if (unlikely(h
== -1)) {
2772 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2773 os_unlock_fork(false);
2774 fatal_mayfail(e
, err
, "can't create socket (%d, %d, %d): %s", domain
, type
, protocol
, error_decode(e
));
2778 os_unlock_fork(false);
2779 obj_registry_insert(OBJ_TYPE_HANDLE
, h
, file_line
);
2780 EINTR_LOOP(r
, fcntl(h
, F_SETFL
, O_NONBLOCK
));
2781 if (unlikely(r
== -1)) {
2783 fatal("fcntl(F_SETFL, O_NONBLOCK) on a socket failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
2788 bool os_bind_connect(bool bnd
, handle_t h
, unsigned char *addr
, size_t addr_len
, ajla_error_t
*err
)
2791 struct sockaddr
*sa
;
2793 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2794 sa
= os_get_sock_addr(addr
, &addr_len
, err
);
2798 EINTR_LOOP(r
, connect(h
, sa
, addr_len
));
2800 EINTR_LOOP(r
, bind(h
, sa
, addr_len
));
2801 mem_free_aligned(sa
);
2804 if (likely(!bnd
) && likely(errno
== EINPROGRESS
))
2806 e
= error_from_errno(EC_SYSCALL
, errno
);
2807 fatal_mayfail(e
, err
, "can't %s socket: %s", !bnd
? "connect" : "bind", error_decode(e
));
2811 bool os_connect_completed(handle_t h
, ajla_error_t
*err
)
2817 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2819 EINTR_LOOP(r
, getsockopt(h
, SOL_SOCKET
, SO_ERROR
, &er
, &er_l
));
2820 if (unlikely(r
== -1)) {
2821 e
= error_from_errno(EC_SYSCALL
, errno
);
2822 fatal_mayfail(e
, err
, "getsockopt returned an error: %s", error_decode(e
));
2826 e
= error_from_errno(EC_SYSCALL
, er
);
2827 fatal_mayfail(e
, err
, "can't connect socket: %s", error_decode(e
));
2833 bool os_listen(handle_t h
, ajla_error_t
*err
)
2836 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2837 EINTR_LOOP(r
, listen(h
, signed_maximum(int)));
2838 if (unlikely(r
== -1)) {
2839 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2840 fatal_mayfail(e
, err
, "listen returned an error: %s", error_decode(e
));
2846 int os_accept(handle_t h
, handle_t
*result
, ajla_error_t
*err
)
2850 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2852 EINTR_LOOP(r
, accept4(h
, NULL
, 0, SOCK_NONBLOCK
| SOCK_CLOEXEC
));
2853 if (likely(r
!= -1)) {
2855 obj_registry_insert(OBJ_TYPE_HANDLE
, r
, file_line
);
2858 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
2859 return OS_RW_WOULDBLOCK
;
2860 if (errno
!= ENOSYS
) {
2861 e
= error_from_errno(EC_SYSCALL
, errno
);
2862 fatal_mayfail(e
, err
, "accept returned an error: %s", error_decode(e
));
2866 os_lock_fork(false);
2867 EINTR_LOOP(r
, accept(h
, NULL
, 0));
2868 if (unlikely(r
== -1)) {
2869 os_unlock_fork(false);
2870 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
2871 return OS_RW_WOULDBLOCK
;
2872 e
= error_from_errno(EC_SYSCALL
, errno
);
2873 fatal_mayfail(e
, err
, "accept returned an error: %s", error_decode(e
));
2877 os_unlock_fork(false);
2879 obj_registry_insert(OBJ_TYPE_HANDLE
, r
, file_line
);
2880 EINTR_LOOP(r
, fcntl(r
, F_SETFL
, O_NONBLOCK
));
2881 if (unlikely(r
== -1)) {
2883 fatal("fcntl(F_SETFL, O_NONBLOCK) on a socket failed: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
2888 bool os_getsockpeername(bool peer
, handle_t h
, unsigned char **addr
, size_t *addr_len
, ajla_error_t
*err
)
2891 struct sockaddr
*sa
;
2894 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2896 sa
= mem_align_mayfail(struct sockaddr
*, SOCKADDR_MAX_LEN
, SOCKADDR_ALIGN
, err
);
2899 addrlen
= SOCKADDR_MAX_LEN
;
2902 EINTR_LOOP(r
, getsockname(h
, sa
, &addrlen
));
2904 #ifdef HAVE_GETPEERNAME
2905 EINTR_LOOP(r
, getpeername(h
, sa
, &addrlen
));
2907 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "getpeername not supported");
2908 goto free_ret_false
;
2911 if (unlikely(r
== -1)) {
2912 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
2913 fatal_mayfail(e
, err
, "%s returned an error: %s", !peer
? "getsockname" : "getpeername", error_decode(e
));
2914 goto free_ret_false
;
2917 *addr
= os_get_ajla_addr(sa
, &addrlen
, err
);
2918 if (unlikely(!*addr
))
2919 goto free_ret_false
;
2921 *addr_len
= addrlen
;
2923 mem_free_aligned(sa
);
2927 mem_free_aligned(sa
);
2931 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
)
2933 struct sockaddr
*sa
;
2938 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2940 f
= translate_flags(os_socket_msg
, flags
, err
);
2941 if (unlikely(f
< 0))
2944 sa
= mem_align_mayfail(struct sockaddr
*, SOCKADDR_MAX_LEN
, SOCKADDR_ALIGN
, err
);
2947 addrlen
= SOCKADDR_MAX_LEN
;
2949 EINTR_LOOP(r
, recvfrom(h
, buffer
, len
, f
, sa
, &addrlen
));
2952 if (unlikely(addrlen
> SOCKADDR_MAX_LEN
)) {
2953 fatal_mayfail(error_ajla(EC_SYSCALL
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "the system returned too long address");
2954 mem_free_aligned(sa
);
2958 if (unlikely(!array_init_mayfail(unsigned char, addr
, addr_len
, err
))) {
2959 mem_free_aligned(sa
);
2963 *addr
= os_get_ajla_addr(sa
, &addrlen
, err
);
2964 if (unlikely(!*addr
)) {
2965 mem_free_aligned(sa
);
2968 *addr_len
= addrlen
;
2971 mem_free_aligned(sa
);
2972 return os_rdwr_return(r
, "receiving", err
);
2975 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
)
2977 struct sockaddr
*sa
;
2981 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
2983 f
= translate_flags(os_socket_msg
, flags
, err
);
2984 if (unlikely(f
< 0))
2987 if (addr_len
!= 0) {
2988 sa
= os_get_sock_addr(addr
, &addr_len
, err
);
2991 EINTR_LOOP(r
, sendto(h
, buffer
, len
, f
, sa
, addr_len
));
2992 mem_free_aligned(sa
);
2994 EINTR_LOOP(r
, send(h
, buffer
, len
, f
));
2997 return os_rdwr_return(r
, "sending", err
);
3000 bool os_getsockopt(handle_t h
, int level
, int option
, char **buffer
, size_t *buffer_len
, ajla_error_t
*err
)
3005 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
3007 level
= os_socket_level(level
, err
);
3008 if (unlikely(level
< 0))
3011 option
= os_socket_option(option
, err
);
3012 if (unlikely(level
< 0))
3016 *buffer
= mem_alloc_mayfail(char *, opt_len
, err
);
3017 if (unlikely(!*buffer
))
3020 EINTR_LOOP(r
, getsockopt(h
, level
, option
, *buffer
, &opt_len
));
3022 if (unlikely(r
== -1)) {
3023 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
3024 fatal_mayfail(e
, err
, "getsockopt returned an error: %s", error_decode(e
));
3029 *buffer_len
= opt_len
;
3033 bool os_setsockopt(handle_t h
, int level
, int option
, const char *buffer
, size_t buffer_len
, ajla_error_t
*err
)
3037 obj_registry_verify(OBJ_TYPE_HANDLE
, h
, file_line
);
3039 level
= os_socket_level(level
, err
);
3040 if (unlikely(level
< 0))
3043 option
= os_socket_option(option
, err
);
3044 if (unlikely(level
< 0))
3047 EINTR_LOOP(r
, setsockopt(h
, level
, option
, buffer
, buffer_len
));
3049 if (unlikely(r
== -1)) {
3050 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
3051 fatal_mayfail(e
, err
, "setsockopt returned an error: %s", error_decode(e
));
3058 #ifdef HAVE_GETADDRINFO
3059 bool os_getaddrinfo(const char *host
, int port
, struct address
**result
, size_t *result_l
, ajla_error_t
*err
)
3064 struct addrinfo
*res
= NULL
, *rs
;
3066 if (unlikely(!array_init_mayfail(struct address
, result
, result_l
, err
)))
3069 snprintf(port_str
, sizeof port_str
, "%d", port
);
3070 r
= getaddrinfo(host
, port_str
, NULL
, &res
);
3072 if (unlikely(r
== EAI_SYSTEM
))
3073 fatal_mayfail(error_from_errno(EC_SYSCALL
, errno
), err
, "host not found");
3075 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_GAI
, abs((int)r
)), err
, "host not found");
3079 for (rs
= res
; rs
; rs
= rs
->ai_next
) {
3081 struct address addr
;
3083 socklen_t addrlen
= rs
->ai_addrlen
;
3085 memset(&addr
.entry
, 0, sizeof addr
.entry
); /* avoid warning */
3087 addr
.address
= os_get_ajla_addr(rs
->ai_addr
, &addrlen
, &e
);
3088 if (unlikely(!addr
.address
))
3090 addr
.address_length
= addrlen
;
3092 if (unlikely(!array_add_mayfail(struct address
, result
, result_l
, addr
, &xresult
, err
))) {
3098 if (unlikely(!*result_l
)) {
3099 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_GAI
, abs(EAI_NONAME
)), err
, "host not found");
3109 for (i
= 0; i
< *result_l
; i
++)
3110 mem_free((*result
)[i
].address
);
3118 #ifndef HAVE_H_ERRNO
3121 bool os_getaddrinfo(const char *host
, int port
, struct address
**result
, size_t *result_l
, ajla_error_t
*err
)
3128 if (unlikely(!array_init_mayfail(struct address
, result
, result_l
, err
)))
3131 he
= gethostbyname(host
);
3133 if (unlikely(!he
)) {
3134 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_H_ERRNO
, h_errno
), err
, "host not found");
3138 if (he
->h_addrtype
!= AF_INET
|| he
->h_length
!= 4 || !he
->h_addr
) {
3139 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_H_ERRNO
, NO_DATA
), err
, "host not found");
3144 for (i
= 0; (a
= he
->h_addr_list
[i
]); i
++)
3149 struct sockaddr_in sin
;
3151 struct address addr
;
3153 socklen_t addrlen
= sizeof sin
;
3155 sin
.sin_family
= AF_INET
;
3156 sin
.sin_port
= htons(port
);
3157 memcpy(&sin
.sin_addr
, a
, 4);
3159 memcpy(&sa
, &sin
, sizeof sin
);
3161 addr
.address
= os_get_ajla_addr(&sa
, &addrlen
, &e
);
3162 if (unlikely(!addr
.address
))
3164 addr
.address_length
= addrlen
;
3166 if (unlikely(!array_add_mayfail(struct address
, result
, result_l
, addr
, &xresult
, err
))) {
3172 if (unlikely(!*result_l
)) {
3173 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_H_ERRNO
, NO_DATA
), err
, "host not found");
3180 for (i
= 0; i
< *result_l
; i
++)
3181 mem_free((*result
)[i
].address
);
3187 #ifdef HAVE_GETNAMEINFO
3188 char *os_getnameinfo(unsigned char *addr
, size_t addr_len
, ajla_error_t
*err
)
3190 struct sockaddr
*sa
;
3194 sa
= os_get_sock_addr(addr
, &addr_len
, err
);
3203 h
= mem_alloc_mayfail(char *, h_len
, err
);
3205 mem_free_aligned(sa
);
3208 r
= getnameinfo(sa
, addr_len
, h
, h_len
, NULL
, 0, 0);
3211 if (unlikely(r
== EAI_OVERFLOW
)) {
3214 if (unlikely(!h_len
)) {
3215 fatal_mayfail(error_ajla(EC_SYSCALL
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "name buffer overflow");
3216 mem_free_aligned(sa
);
3219 goto alloc_buffer_again
;
3222 if (unlikely(r
== EAI_SYSTEM
)) {
3223 fatal_mayfail(error_from_errno(EC_SYSCALL
, errno
), err
, "host not found");
3225 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_GAI
, abs((int)r
)), err
, "host not found");
3228 mem_free_aligned(sa
);
3231 mem_free_aligned(sa
);
3234 #elif defined(HAVE_GETHOSTBYADDR)
3235 char *os_getnameinfo(unsigned char *addr
, size_t addr_len
, ajla_error_t
*err
)
3237 struct sockaddr
*sa
;
3241 sa
= os_get_sock_addr(addr
, &addr_len
, err
);
3244 switch (sa
->sa_family
) {
3246 struct sockaddr_in
*sin
;
3247 if (unlikely(addr_len
< offsetof(struct sockaddr_in
, sin_addr
) + 4)) {
3248 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), err
, "too short address");
3249 mem_free_aligned(sa
);
3252 sin
= cast_ptr(struct sockaddr_in
*, sa
);
3253 he
= gethostbyaddr(cast_ptr(void *, &sin
->sin_addr
.s_addr
), 4, sa
->sa_family
);
3258 struct sockaddr_in6
*sin6
;
3259 if (unlikely(addr_len
< offsetof(struct sockaddr_in6
, sin6_addr
) + 16)) {
3260 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_INVALID_OPERATION
), err
, "too short address");
3261 mem_free_aligned(sa
);
3264 sin6
= cast_ptr(struct sockaddr_in6
*, sa
);
3265 he
= gethostbyaddr(&sin6
->sin6_addr
.s6_addr
, 16, sa
->sa_family
);
3270 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "address family %d not supported", sa
->sa_family
);
3271 mem_free_aligned(sa
);
3275 mem_free_aligned(sa
);
3276 if (unlikely(!he
) || !he
->h_name
) {
3277 fatal_mayfail(error_ajla_aux(EC_SYSCALL
, AJLA_ERROR_H_ERRNO
, h_errno
), err
, "host not found");
3280 le
= strlen(he
->h_name
);
3281 name
= mem_alloc_mayfail(char *, le
+ 1, err
);
3282 if (unlikely(!name
))
3284 return memcpy(name
, he
->h_name
, le
+ 1);
3287 char *os_getnameinfo(unsigned char attr_unused
*addr
, size_t attr_unused addr_len
, ajla_error_t
*err
)
3289 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "getnameinfo not supported");
3296 handle_t
os_socket(int attr_unused domain
, int attr_unused type
, int attr_unused protocol
, ajla_error_t
*err
)
3298 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3302 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
)
3304 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3308 bool os_connect_completed(handle_t attr_unused h
, ajla_error_t
*err
)
3310 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3314 bool os_listen(handle_t attr_unused h
, ajla_error_t
*err
)
3316 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3320 int os_accept(handle_t attr_unused h
, handle_t attr_unused
*result
, ajla_error_t
*err
)
3322 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3326 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
)
3328 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3332 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
)
3334 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3338 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
)
3340 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3344 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
)
3346 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3350 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
)
3352 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3356 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
)
3358 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3362 char *os_getnameinfo(unsigned char attr_unused
*addr
, size_t attr_unused addr_len
, ajla_error_t
*err
)
3364 fatal_mayfail(error_ajla(EC_SYNC
, AJLA_ERROR_NOT_SUPPORTED
), err
, "sockets not supported");
3371 const char *os_decode_error(ajla_error_t error
, char attr_unused
*(*tls_buffer
)(void))
3373 switch (error
.error_type
) {
3374 #if defined(HAVE_NETWORK) && defined(HAVE_GETADDRINFO)
3375 case AJLA_ERROR_GAI
: {
3376 return gai_strerror(error
.error_aux
* (EAI_NONAME
< 0 ? -1 : 1));
3379 case AJLA_ERROR_H_ERRNO
: {
3380 #if defined(HAVE_NETWORK) && defined(HAVE_HSTRERROR)
3381 return hstrerror(error
.error_aux
);
3383 return "Unknown host";
3392 #ifdef OS_HAS_DLOPEN
3393 struct dl_handle_t
*os_dlopen(const char *filename
, ajla_error_t
*err
, char **err_msg
)
3395 struct dl_handle_t
*dlh
;
3396 dlh
= dlopen(filename
, RTLD_LAZY
);
3397 if (unlikely(!dlh
)) {
3399 *err_msg
= dlerror();
3400 e
= error_ajla(EC_SYNC
, AJLA_ERROR_LIBRARY_NOT_FOUND
);
3401 fatal_mayfail(e
, err
, "can't open dynamic library '%s': %s", filename
, *err_msg
);
3407 void os_dlclose(struct dl_handle_t
*dlh
)
3409 int r
= dlclose(dlh
);
3410 #if defined(OS_CYGWIN)
3411 /* dlclose fails if we attempt to unload non-cygwin dll */
3412 if (unlikely(r
== -1) && errno
== ENOENT
)
3416 internal(file_line
, "dlclose failed: %s", dlerror());
3419 bool os_dlsym(struct dl_handle_t
*dlh
, const char *symbol
, void **result
)
3422 r
= dlsym(dlh
, symbol
);
3431 #ifdef OS_HAVE_NOTIFY_PIPE
3432 handle_t os_notify_pipe
[2];
3434 void os_notify(void)
3438 EINTR_LOOP(r
, write(os_notify_pipe
[1], &c
, 1));
3439 if (unlikely(r
== -1)) {
3441 if (unlikely(er
!= EAGAIN
) && unlikely(er
!= EWOULDBLOCK
) && unlikely(er
!= EBADF
)) {
3442 fatal("error writing to the notify pipe: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
3447 bool os_drain_notify_pipe(void)
3449 static char buffer
[1024];
3451 EINTR_LOOP(r
, read(os_notify_pipe
[0], buffer
, sizeof(buffer
)));
3452 if (likely(r
== -1)) {
3454 if (unlikely(er
!= EAGAIN
) && unlikely(er
!= EWOULDBLOCK
)) {
3455 fatal("error reading the notify pipe: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
3461 void os_shutdown_notify_pipe(void)
3464 EINTR_LOOP(r
, dup2(os_notify_pipe
[0], os_notify_pipe
[1]));
3465 if (unlikely(r
== -1)) {
3467 fatal("error shutting down the notify pipe: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
3476 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
3478 const char *os_get_flavor(void)
3482 #elif defined(OS_CYGWIN)
3489 void os_get_uname(os_utsname_t
*un
)
3492 EINTR_LOOP(r
, uname(un
));
3493 if (unlikely(r
== -1)) {
3495 fatal("uname returned error: %d, %s", er
, error_decode(error_from_errno(EC_SYSCALL
, er
)));
3497 if (sizeof un
->sysname
>= 10 && likely(!strcmp(un
->sysname
, "Linux")))
3498 strcpy(un
->sysname
, "GNU/Linux"); /* make RMS happy */
3501 bool os_kernel_version(const char *sys
, const char *vers
)
3503 static os_utsname_t un
;
3504 static bool have_un
= false;
3505 const char *last_comp
, *ptr_sys
, *ptr_wanted
;
3510 if (unlikely(strcmp(sys
, un
.sysname
)))
3512 last_comp
= strrchr(vers
, '.');
3517 if (strncmp(un
.release
, vers
, last_comp
- vers
))
3519 ptr_sys
= un
.release
+ (last_comp
- vers
);
3520 ptr_wanted
= vers
+ (last_comp
- vers
);
3523 if (likely(*ptr_sys
>= '0') && likely(*ptr_sys
<= '9')) {
3524 if (atoi(ptr_sys
) >= atoi(ptr_wanted
)) {
3533 void os_get_uname(os_utsname_t
*un
)
3535 memset(un
, 0, sizeof(os_utsname_t
));
3536 strcpy(un
->sysname
, "Posix");
3538 strcpy(un
->machine
, ARCH_NAME
);
3542 bool os_kernel_version(const char attr_unused
*sys
, const char attr_unused
*vers
)
3549 char *os_get_host_name(ajla_error_t
*err
)
3551 #ifdef HAVE_GETHOSTNAME
3559 fatal_mayfail(error_ajla(EC_ASYNC
, AJLA_ERROR_SIZE_OVERFLOW
), err
, "overflow when allocating host name");
3562 hn
= mem_alloc_mayfail(char *, s
, err
);
3566 EINTR_LOOP(r
, gethostname(hn
, s
));
3568 if (unlikely(r
== -1)) {
3569 ajla_error_t e
= error_from_errno(EC_SYSCALL
, errno
);
3571 if (errno
== EINVAL
|| errno
== ENAMETOOLONG
)
3573 fatal_mayfail(e
, err
, "can't get hostname: %s", error_decode(e
));
3577 if (unlikely(strnlen(hn
, s
) >= s
- 1)) {
3584 char *e
= getenv("HOSTNAME");
3587 return str_dup(e
, -1, err
);
3597 EINTR_LOOP(r
, close(3));
3598 EINTR_LOOP(r
, close(4));
3604 EINTR_LOOP(r
, fstat(n_std_handles
, &st
));
3609 if (unlikely(n_std_handles
< 3))
3612 #ifdef HAVE_AT_FUNCTIONS
3613 if (os_kernel_version("GNU/Linux", "3") ||
3614 os_kernel_version("GNU/Linux", "2.6.23")) {
3615 have_O_CLOEXEC_openat
= true;
3620 EINTR_LOOP(r
, fstatat(AT_FDCWD
, "/", &st
, AT_SYMLINK_NOFOLLOW
));
3621 if (unlikely(r
== -1))
3624 EINTR_LOOP(h
, openat(AT_FDCWD
, "/dev/null", O_RDONLY
| O_CLOEXEC
));
3625 if (unlikely(h
== -1))
3628 EINTR_LOOP(flags
, fcntl(h
, F_GETFD
));
3629 if (likely(flags
>= 0) && likely(flags
& FD_CLOEXEC
))
3630 have_O_CLOEXEC_openat
= true;
3636 os_cwd
= os_get_cwd(&sink
);
3637 if (unlikely(dir_handle_is_valid(os_cwd
))) {
3638 os_set_original_cwd();
3640 os_cwd
= os_get_cwd(NULL
);
3643 os_init_path_to_exe();
3645 #ifdef OS_HAVE_NOTIFY_PIPE
3646 os_pipe(os_notify_pipe
, 3, NULL
);
3649 #ifdef OS_HAS_SIGNALS
3650 signal_states
= mem_alloc_array_mayfail(mem_calloc_mayfail
, struct signal_state
*, 0, 0, N_SIGNALS
, sizeof(struct signal_state
), NULL
);
3651 for (i
= 0; i
< N_SIGNALS
; i
++)
3652 list_init(&signal_states
[i
].wait_list
);
3654 #ifdef HAVE_CODEGEN_TRAPS
3655 os_signal_trap(SIGFPE
, sigfpe_handler
);
3656 #if defined(ARCH_MIPS)
3657 os_signal_trap(SIGTRAP
, sigfpe_handler
);
3666 #ifdef OS_HAS_SIGNALS
3669 #ifdef HAVE_CODEGEN_TRAPS
3670 os_signal_untrap(SIGFPE
);
3671 #if defined(ARCH_MIPS)
3672 os_signal_untrap(SIGTRAP
);
3676 for (sig
= 0; sig
< N_SIGNALS
; sig
++) {
3677 if (unlikely(signal_states
[sig
].trapped
) || unlikely(signal_states
[sig
].refcount
!= 0))
3678 internal(file_line
, "signal %d leaked", sig
);
3680 mem_free(signal_states
);
3681 signal_states
= NULL
;
3684 #ifdef OS_HAVE_NOTIFY_PIPE
3685 os_close(os_notify_pipe
[0]);
3686 os_close(os_notify_pipe
[1]);
3689 os_dir_close(os_cwd
);
3691 mem_free(os_path_to_exe
);
3694 void os_init_multithreaded(void)
3698 os_init_calendar_lock();
3700 rwmutex_init(&fork_lock
);
3701 os_threads_initialized
= true;
3703 #if !defined(OS_DOS)
3704 tree_init(&proc_tree
);
3705 mutex_init(&proc_tree_mutex
);
3708 #ifdef OS_HAS_SIGNALS
3709 mutex_init(&signal_state_mutex
);
3712 for (u
= 0; u
< n_std_handles
; u
++)
3713 obj_registry_insert(OBJ_TYPE_HANDLE
, u
, file_line
);
3719 void os_done_multithreaded(void)
3726 for (u
= 0; u
< n_std_handles
; u
++)
3727 obj_registry_remove(OBJ_TYPE_HANDLE
, u
, file_line
);
3729 #ifdef OS_HAS_SIGNALS
3730 mutex_done(&signal_state_mutex
);
3733 #if !defined(OS_DOS)
3734 if (unlikely(!tree_is_empty(&proc_tree
))) {
3735 struct proc_handle
*ph
= get_struct(tree_any(&proc_tree
), struct proc_handle
, entry
);
3736 tree_delete(&ph
->entry
);
3737 proc_handle_free(ph
);
3739 mutex_done(&proc_tree_mutex
);
3742 os_threads_initialized
= false;
3743 rwmutex_done(&fork_lock
);
3745 os_done_calendar_lock();