18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <stdio.h> 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <stdlib.h> 98c2ecf20Sopenharmony_ci#include <string.h> 108c2ecf20Sopenharmony_ci#include <errno.h> 118c2ecf20Sopenharmony_ci#include <fcntl.h> 128c2ecf20Sopenharmony_ci#include <signal.h> 138c2ecf20Sopenharmony_ci#include <linux/falloc.h> 148c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 158c2ecf20Sopenharmony_ci#include <sys/mount.h> 168c2ecf20Sopenharmony_ci#include <sys/socket.h> 178c2ecf20Sopenharmony_ci#include <sys/stat.h> 188c2ecf20Sopenharmony_ci#include <sys/sysmacros.h> 198c2ecf20Sopenharmony_ci#include <sys/un.h> 208c2ecf20Sopenharmony_ci#include <sys/types.h> 218c2ecf20Sopenharmony_ci#include <sys/eventfd.h> 228c2ecf20Sopenharmony_ci#include <poll.h> 238c2ecf20Sopenharmony_ci#include <os.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void copy_stat(struct uml_stat *dst, const struct stat64 *src) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci *dst = ((struct uml_stat) { 288c2ecf20Sopenharmony_ci .ust_dev = src->st_dev, /* device */ 298c2ecf20Sopenharmony_ci .ust_ino = src->st_ino, /* inode */ 308c2ecf20Sopenharmony_ci .ust_mode = src->st_mode, /* protection */ 318c2ecf20Sopenharmony_ci .ust_nlink = src->st_nlink, /* number of hard links */ 328c2ecf20Sopenharmony_ci .ust_uid = src->st_uid, /* user ID of owner */ 338c2ecf20Sopenharmony_ci .ust_gid = src->st_gid, /* group ID of owner */ 348c2ecf20Sopenharmony_ci .ust_size = src->st_size, /* total size, in bytes */ 358c2ecf20Sopenharmony_ci .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */ 368c2ecf20Sopenharmony_ci .ust_blocks = src->st_blocks, /* number of blocks allocated */ 378c2ecf20Sopenharmony_ci .ust_atime = src->st_atime, /* time of last access */ 388c2ecf20Sopenharmony_ci .ust_mtime = src->st_mtime, /* time of last modification */ 398c2ecf20Sopenharmony_ci .ust_ctime = src->st_ctime, /* time of last change */ 408c2ecf20Sopenharmony_ci }); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciint os_stat_fd(const int fd, struct uml_stat *ubuf) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct stat64 sbuf; 468c2ecf20Sopenharmony_ci int err; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci CATCH_EINTR(err = fstat64(fd, &sbuf)); 498c2ecf20Sopenharmony_ci if (err < 0) 508c2ecf20Sopenharmony_ci return -errno; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (ubuf != NULL) 538c2ecf20Sopenharmony_ci copy_stat(ubuf, &sbuf); 548c2ecf20Sopenharmony_ci return err; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciint os_stat_file(const char *file_name, struct uml_stat *ubuf) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct stat64 sbuf; 608c2ecf20Sopenharmony_ci int err; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci CATCH_EINTR(err = stat64(file_name, &sbuf)); 638c2ecf20Sopenharmony_ci if (err < 0) 648c2ecf20Sopenharmony_ci return -errno; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (ubuf != NULL) 678c2ecf20Sopenharmony_ci copy_stat(ubuf, &sbuf); 688c2ecf20Sopenharmony_ci return err; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciint os_access(const char *file, int mode) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci int amode, err; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci amode = (mode & OS_ACC_R_OK ? R_OK : 0) | 768c2ecf20Sopenharmony_ci (mode & OS_ACC_W_OK ? W_OK : 0) | 778c2ecf20Sopenharmony_ci (mode & OS_ACC_X_OK ? X_OK : 0) | 788c2ecf20Sopenharmony_ci (mode & OS_ACC_F_OK ? F_OK : 0); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci err = access(file, amode); 818c2ecf20Sopenharmony_ci if (err < 0) 828c2ecf20Sopenharmony_ci return -errno; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */ 888c2ecf20Sopenharmony_ciint os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci int err; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci err = ioctl(fd, cmd, arg); 938c2ecf20Sopenharmony_ci if (err < 0) 948c2ecf20Sopenharmony_ci return -errno; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return err; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* FIXME: ensure namebuf in os_get_if_name is big enough */ 1008c2ecf20Sopenharmony_ciint os_get_ifname(int fd, char* namebuf) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci if (ioctl(fd, SIOCGIFNAME, namebuf) < 0) 1038c2ecf20Sopenharmony_ci return -errno; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return 0; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciint os_set_slip(int fd) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int disc, sencap; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci disc = N_SLIP; 1138c2ecf20Sopenharmony_ci if (ioctl(fd, TIOCSETD, &disc) < 0) 1148c2ecf20Sopenharmony_ci return -errno; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci sencap = 0; 1178c2ecf20Sopenharmony_ci if (ioctl(fd, SIOCSIFENCAP, &sencap) < 0) 1188c2ecf20Sopenharmony_ci return -errno; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciint os_mode_fd(int fd, int mode) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci int err; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci CATCH_EINTR(err = fchmod(fd, mode)); 1288c2ecf20Sopenharmony_ci if (err < 0) 1298c2ecf20Sopenharmony_ci return -errno; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciint os_file_type(char *file) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct uml_stat buf; 1378c2ecf20Sopenharmony_ci int err; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci err = os_stat_file(file, &buf); 1408c2ecf20Sopenharmony_ci if (err < 0) 1418c2ecf20Sopenharmony_ci return err; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (S_ISDIR(buf.ust_mode)) 1448c2ecf20Sopenharmony_ci return OS_TYPE_DIR; 1458c2ecf20Sopenharmony_ci else if (S_ISLNK(buf.ust_mode)) 1468c2ecf20Sopenharmony_ci return OS_TYPE_SYMLINK; 1478c2ecf20Sopenharmony_ci else if (S_ISCHR(buf.ust_mode)) 1488c2ecf20Sopenharmony_ci return OS_TYPE_CHARDEV; 1498c2ecf20Sopenharmony_ci else if (S_ISBLK(buf.ust_mode)) 1508c2ecf20Sopenharmony_ci return OS_TYPE_BLOCKDEV; 1518c2ecf20Sopenharmony_ci else if (S_ISFIFO(buf.ust_mode)) 1528c2ecf20Sopenharmony_ci return OS_TYPE_FIFO; 1538c2ecf20Sopenharmony_ci else if (S_ISSOCK(buf.ust_mode)) 1548c2ecf20Sopenharmony_ci return OS_TYPE_SOCK; 1558c2ecf20Sopenharmony_ci else return OS_TYPE_FILE; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ciint os_file_mode(const char *file, struct openflags *mode_out) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci int err; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci *mode_out = OPENFLAGS(); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci err = access(file, W_OK); 1658c2ecf20Sopenharmony_ci if (err && (errno != EACCES)) 1668c2ecf20Sopenharmony_ci return -errno; 1678c2ecf20Sopenharmony_ci else if (!err) 1688c2ecf20Sopenharmony_ci *mode_out = of_write(*mode_out); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci err = access(file, R_OK); 1718c2ecf20Sopenharmony_ci if (err && (errno != EACCES)) 1728c2ecf20Sopenharmony_ci return -errno; 1738c2ecf20Sopenharmony_ci else if (!err) 1748c2ecf20Sopenharmony_ci *mode_out = of_read(*mode_out); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return err; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ciint os_open_file(const char *file, struct openflags flags, int mode) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int fd, err, f = 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (flags.r && flags.w) 1848c2ecf20Sopenharmony_ci f = O_RDWR; 1858c2ecf20Sopenharmony_ci else if (flags.r) 1868c2ecf20Sopenharmony_ci f = O_RDONLY; 1878c2ecf20Sopenharmony_ci else if (flags.w) 1888c2ecf20Sopenharmony_ci f = O_WRONLY; 1898c2ecf20Sopenharmony_ci else f = 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (flags.s) 1928c2ecf20Sopenharmony_ci f |= O_SYNC; 1938c2ecf20Sopenharmony_ci if (flags.c) 1948c2ecf20Sopenharmony_ci f |= O_CREAT; 1958c2ecf20Sopenharmony_ci if (flags.t) 1968c2ecf20Sopenharmony_ci f |= O_TRUNC; 1978c2ecf20Sopenharmony_ci if (flags.e) 1988c2ecf20Sopenharmony_ci f |= O_EXCL; 1998c2ecf20Sopenharmony_ci if (flags.a) 2008c2ecf20Sopenharmony_ci f |= O_APPEND; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci fd = open64(file, f, mode); 2038c2ecf20Sopenharmony_ci if (fd < 0) 2048c2ecf20Sopenharmony_ci return -errno; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (flags.cl && fcntl(fd, F_SETFD, 1)) { 2078c2ecf20Sopenharmony_ci err = -errno; 2088c2ecf20Sopenharmony_ci close(fd); 2098c2ecf20Sopenharmony_ci return err; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return fd; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciint os_connect_socket(const char *name) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct sockaddr_un sock; 2188c2ecf20Sopenharmony_ci int fd, err; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci sock.sun_family = AF_UNIX; 2218c2ecf20Sopenharmony_ci snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci fd = socket(AF_UNIX, SOCK_STREAM, 0); 2248c2ecf20Sopenharmony_ci if (fd < 0) { 2258c2ecf20Sopenharmony_ci err = -errno; 2268c2ecf20Sopenharmony_ci goto out; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); 2308c2ecf20Sopenharmony_ci if (err) { 2318c2ecf20Sopenharmony_ci err = -errno; 2328c2ecf20Sopenharmony_ci goto out_close; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return fd; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciout_close: 2388c2ecf20Sopenharmony_ci close(fd); 2398c2ecf20Sopenharmony_ciout: 2408c2ecf20Sopenharmony_ci return err; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_civoid os_close_file(int fd) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci close(fd); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ciint os_fsync_file(int fd) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci if (fsync(fd) < 0) 2508c2ecf20Sopenharmony_ci return -errno; 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciint os_seek_file(int fd, unsigned long long offset) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci unsigned long long actual; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci actual = lseek64(fd, offset, SEEK_SET); 2598c2ecf20Sopenharmony_ci if (actual != offset) 2608c2ecf20Sopenharmony_ci return -errno; 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciint os_read_file(int fd, void *buf, int len) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci int n = read(fd, buf, len); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (n < 0) 2698c2ecf20Sopenharmony_ci return -errno; 2708c2ecf20Sopenharmony_ci return n; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ciint os_pread_file(int fd, void *buf, int len, unsigned long long offset) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci int n = pread(fd, buf, len, offset); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (n < 0) 2788c2ecf20Sopenharmony_ci return -errno; 2798c2ecf20Sopenharmony_ci return n; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ciint os_write_file(int fd, const void *buf, int len) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci int n = write(fd, (void *) buf, len); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (n < 0) 2878c2ecf20Sopenharmony_ci return -errno; 2888c2ecf20Sopenharmony_ci return n; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciint os_sync_file(int fd) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int n = fdatasync(fd); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (n < 0) 2968c2ecf20Sopenharmony_ci return -errno; 2978c2ecf20Sopenharmony_ci return n; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ciint os_pwrite_file(int fd, const void *buf, int len, unsigned long long offset) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci int n = pwrite(fd, (void *) buf, len, offset); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (n < 0) 3058c2ecf20Sopenharmony_ci return -errno; 3068c2ecf20Sopenharmony_ci return n; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciint os_file_size(const char *file, unsigned long long *size_out) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct uml_stat buf; 3138c2ecf20Sopenharmony_ci int err; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci err = os_stat_file(file, &buf); 3168c2ecf20Sopenharmony_ci if (err < 0) { 3178c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file, 3188c2ecf20Sopenharmony_ci -err); 3198c2ecf20Sopenharmony_ci return err; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (S_ISBLK(buf.ust_mode)) { 3238c2ecf20Sopenharmony_ci int fd; 3248c2ecf20Sopenharmony_ci long blocks; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci fd = open(file, O_RDONLY, 0); 3278c2ecf20Sopenharmony_ci if (fd < 0) { 3288c2ecf20Sopenharmony_ci err = -errno; 3298c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "Couldn't open \"%s\", " 3308c2ecf20Sopenharmony_ci "errno = %d\n", file, errno); 3318c2ecf20Sopenharmony_ci return err; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci if (ioctl(fd, BLKGETSIZE, &blocks) < 0) { 3348c2ecf20Sopenharmony_ci err = -errno; 3358c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "Couldn't get the block size of " 3368c2ecf20Sopenharmony_ci "\"%s\", errno = %d\n", file, errno); 3378c2ecf20Sopenharmony_ci close(fd); 3388c2ecf20Sopenharmony_ci return err; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci *size_out = ((long long) blocks) * 512; 3418c2ecf20Sopenharmony_ci close(fd); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci else *size_out = buf.ust_size; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciint os_file_modtime(const char *file, long long *modtime) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct uml_stat buf; 3518c2ecf20Sopenharmony_ci int err; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci err = os_stat_file(file, &buf); 3548c2ecf20Sopenharmony_ci if (err < 0) { 3558c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file, 3568c2ecf20Sopenharmony_ci -err); 3578c2ecf20Sopenharmony_ci return err; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci *modtime = buf.ust_mtime; 3618c2ecf20Sopenharmony_ci return 0; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ciint os_set_exec_close(int fd) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci int err; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci CATCH_EINTR(err = fcntl(fd, F_SETFD, FD_CLOEXEC)); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (err < 0) 3718c2ecf20Sopenharmony_ci return -errno; 3728c2ecf20Sopenharmony_ci return err; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciint os_pipe(int *fds, int stream, int close_on_exec) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci err = socketpair(AF_UNIX, type, 0, fds); 3808c2ecf20Sopenharmony_ci if (err < 0) 3818c2ecf20Sopenharmony_ci return -errno; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (!close_on_exec) 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci err = os_set_exec_close(fds[0]); 3878c2ecf20Sopenharmony_ci if (err < 0) 3888c2ecf20Sopenharmony_ci goto error; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci err = os_set_exec_close(fds[1]); 3918c2ecf20Sopenharmony_ci if (err < 0) 3928c2ecf20Sopenharmony_ci goto error; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci error: 3978c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "os_pipe : Setting FD_CLOEXEC failed, err = %d\n", 3988c2ecf20Sopenharmony_ci -err); 3998c2ecf20Sopenharmony_ci close(fds[1]); 4008c2ecf20Sopenharmony_ci close(fds[0]); 4018c2ecf20Sopenharmony_ci return err; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ciint os_set_fd_async(int fd) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci int err, flags; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci flags = fcntl(fd, F_GETFL); 4098c2ecf20Sopenharmony_ci if (flags < 0) 4108c2ecf20Sopenharmony_ci return -errno; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci flags |= O_ASYNC | O_NONBLOCK; 4138c2ecf20Sopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) { 4148c2ecf20Sopenharmony_ci err = -errno; 4158c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "os_set_fd_async : failed to set O_ASYNC " 4168c2ecf20Sopenharmony_ci "and O_NONBLOCK on fd # %d, errno = %d\n", fd, errno); 4178c2ecf20Sopenharmony_ci return err; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if ((fcntl(fd, F_SETSIG, SIGIO) < 0) || 4218c2ecf20Sopenharmony_ci (fcntl(fd, F_SETOWN, os_getpid()) < 0)) { 4228c2ecf20Sopenharmony_ci err = -errno; 4238c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "os_set_fd_async : Failed to fcntl F_SETOWN " 4248c2ecf20Sopenharmony_ci "(or F_SETSIG) fd %d, errno = %d\n", fd, errno); 4258c2ecf20Sopenharmony_ci return err; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ciint os_clear_fd_async(int fd) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci int flags; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci flags = fcntl(fd, F_GETFL); 4368c2ecf20Sopenharmony_ci if (flags < 0) 4378c2ecf20Sopenharmony_ci return -errno; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci flags &= ~(O_ASYNC | O_NONBLOCK); 4408c2ecf20Sopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) 4418c2ecf20Sopenharmony_ci return -errno; 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciint os_set_fd_block(int fd, int blocking) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci int flags; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci flags = fcntl(fd, F_GETFL); 4508c2ecf20Sopenharmony_ci if (flags < 0) 4518c2ecf20Sopenharmony_ci return -errno; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (blocking) 4548c2ecf20Sopenharmony_ci flags &= ~O_NONBLOCK; 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci flags |= O_NONBLOCK; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) 4598c2ecf20Sopenharmony_ci return -errno; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ciint os_accept_connection(int fd) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci int new; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci new = accept(fd, NULL, 0); 4698c2ecf20Sopenharmony_ci if (new < 0) 4708c2ecf20Sopenharmony_ci return -errno; 4718c2ecf20Sopenharmony_ci return new; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci#ifndef SHUT_RD 4758c2ecf20Sopenharmony_ci#define SHUT_RD 0 4768c2ecf20Sopenharmony_ci#endif 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci#ifndef SHUT_WR 4798c2ecf20Sopenharmony_ci#define SHUT_WR 1 4808c2ecf20Sopenharmony_ci#endif 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci#ifndef SHUT_RDWR 4838c2ecf20Sopenharmony_ci#define SHUT_RDWR 2 4848c2ecf20Sopenharmony_ci#endif 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ciint os_shutdown_socket(int fd, int r, int w) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci int what, err; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (r && w) 4918c2ecf20Sopenharmony_ci what = SHUT_RDWR; 4928c2ecf20Sopenharmony_ci else if (r) 4938c2ecf20Sopenharmony_ci what = SHUT_RD; 4948c2ecf20Sopenharmony_ci else if (w) 4958c2ecf20Sopenharmony_ci what = SHUT_WR; 4968c2ecf20Sopenharmony_ci else 4978c2ecf20Sopenharmony_ci return -EINVAL; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci err = shutdown(fd, what); 5008c2ecf20Sopenharmony_ci if (err < 0) 5018c2ecf20Sopenharmony_ci return -errno; 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ciint os_rcv_fd(int fd, int *helper_pid_out) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci int new, n; 5088c2ecf20Sopenharmony_ci char buf[CMSG_SPACE(sizeof(new))]; 5098c2ecf20Sopenharmony_ci struct msghdr msg; 5108c2ecf20Sopenharmony_ci struct cmsghdr *cmsg; 5118c2ecf20Sopenharmony_ci struct iovec iov; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci msg.msg_name = NULL; 5148c2ecf20Sopenharmony_ci msg.msg_namelen = 0; 5158c2ecf20Sopenharmony_ci iov = ((struct iovec) { .iov_base = helper_pid_out, 5168c2ecf20Sopenharmony_ci .iov_len = sizeof(*helper_pid_out) }); 5178c2ecf20Sopenharmony_ci msg.msg_iov = &iov; 5188c2ecf20Sopenharmony_ci msg.msg_iovlen = 1; 5198c2ecf20Sopenharmony_ci msg.msg_control = buf; 5208c2ecf20Sopenharmony_ci msg.msg_controllen = sizeof(buf); 5218c2ecf20Sopenharmony_ci msg.msg_flags = 0; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci n = recvmsg(fd, &msg, 0); 5248c2ecf20Sopenharmony_ci if (n < 0) 5258c2ecf20Sopenharmony_ci return -errno; 5268c2ecf20Sopenharmony_ci else if (n != iov.iov_len) 5278c2ecf20Sopenharmony_ci *helper_pid_out = -1; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci cmsg = CMSG_FIRSTHDR(&msg); 5308c2ecf20Sopenharmony_ci if (cmsg == NULL) { 5318c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "rcv_fd didn't receive anything, " 5328c2ecf20Sopenharmony_ci "error = %d\n", errno); 5338c2ecf20Sopenharmony_ci return -1; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci if ((cmsg->cmsg_level != SOL_SOCKET) || 5368c2ecf20Sopenharmony_ci (cmsg->cmsg_type != SCM_RIGHTS)) { 5378c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n"); 5388c2ecf20Sopenharmony_ci return -1; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci new = ((int *) CMSG_DATA(cmsg))[0]; 5428c2ecf20Sopenharmony_ci return new; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ciint os_create_unix_socket(const char *file, int len, int close_on_exec) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct sockaddr_un addr; 5488c2ecf20Sopenharmony_ci int sock, err; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci sock = socket(PF_UNIX, SOCK_DGRAM, 0); 5518c2ecf20Sopenharmony_ci if (sock < 0) 5528c2ecf20Sopenharmony_ci return -errno; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (close_on_exec) { 5558c2ecf20Sopenharmony_ci err = os_set_exec_close(sock); 5568c2ecf20Sopenharmony_ci if (err < 0) 5578c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "create_unix_socket : " 5588c2ecf20Sopenharmony_ci "close_on_exec failed, err = %d", -err); 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci addr.sun_family = AF_UNIX; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci snprintf(addr.sun_path, len, "%s", file); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); 5668c2ecf20Sopenharmony_ci if (err < 0) 5678c2ecf20Sopenharmony_ci return -errno; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return sock; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_civoid os_flush_stdout(void) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci fflush(stdout); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ciint os_lock_file(int fd, int excl) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci int type = excl ? F_WRLCK : F_RDLCK; 5808c2ecf20Sopenharmony_ci struct flock lock = ((struct flock) { .l_type = type, 5818c2ecf20Sopenharmony_ci .l_whence = SEEK_SET, 5828c2ecf20Sopenharmony_ci .l_start = 0, 5838c2ecf20Sopenharmony_ci .l_len = 0 } ); 5848c2ecf20Sopenharmony_ci int err, save; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci err = fcntl(fd, F_SETLK, &lock); 5878c2ecf20Sopenharmony_ci if (!err) 5888c2ecf20Sopenharmony_ci goto out; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci save = -errno; 5918c2ecf20Sopenharmony_ci err = fcntl(fd, F_GETLK, &lock); 5928c2ecf20Sopenharmony_ci if (err) { 5938c2ecf20Sopenharmony_ci err = -errno; 5948c2ecf20Sopenharmony_ci goto out; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "F_SETLK failed, file already locked by pid %d\n", 5988c2ecf20Sopenharmony_ci lock.l_pid); 5998c2ecf20Sopenharmony_ci err = save; 6008c2ecf20Sopenharmony_ci out: 6018c2ecf20Sopenharmony_ci return err; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciunsigned os_major(unsigned long long dev) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci return major(dev); 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ciunsigned os_minor(unsigned long long dev) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci return minor(dev); 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ciunsigned long long os_makedev(unsigned major, unsigned minor) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci return makedev(major, minor); 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ciint os_falloc_punch(int fd, unsigned long long offset, int len) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci int n = fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, offset, len); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (n < 0) 6248c2ecf20Sopenharmony_ci return -errno; 6258c2ecf20Sopenharmony_ci return n; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ciint os_eventfd(unsigned int initval, int flags) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci int fd = eventfd(initval, flags); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (fd < 0) 6338c2ecf20Sopenharmony_ci return -errno; 6348c2ecf20Sopenharmony_ci return fd; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ciint os_sendmsg_fds(int fd, const void *buf, unsigned int len, const int *fds, 6388c2ecf20Sopenharmony_ci unsigned int fds_num) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct iovec iov = { 6418c2ecf20Sopenharmony_ci .iov_base = (void *) buf, 6428c2ecf20Sopenharmony_ci .iov_len = len, 6438c2ecf20Sopenharmony_ci }; 6448c2ecf20Sopenharmony_ci union { 6458c2ecf20Sopenharmony_ci char control[CMSG_SPACE(sizeof(*fds) * OS_SENDMSG_MAX_FDS)]; 6468c2ecf20Sopenharmony_ci struct cmsghdr align; 6478c2ecf20Sopenharmony_ci } u; 6488c2ecf20Sopenharmony_ci unsigned int fds_size = sizeof(*fds) * fds_num; 6498c2ecf20Sopenharmony_ci struct msghdr msg = { 6508c2ecf20Sopenharmony_ci .msg_iov = &iov, 6518c2ecf20Sopenharmony_ci .msg_iovlen = 1, 6528c2ecf20Sopenharmony_ci .msg_control = u.control, 6538c2ecf20Sopenharmony_ci .msg_controllen = CMSG_SPACE(fds_size), 6548c2ecf20Sopenharmony_ci }; 6558c2ecf20Sopenharmony_ci struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 6568c2ecf20Sopenharmony_ci int err; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (fds_num > OS_SENDMSG_MAX_FDS) 6598c2ecf20Sopenharmony_ci return -EINVAL; 6608c2ecf20Sopenharmony_ci memset(u.control, 0, sizeof(u.control)); 6618c2ecf20Sopenharmony_ci cmsg->cmsg_level = SOL_SOCKET; 6628c2ecf20Sopenharmony_ci cmsg->cmsg_type = SCM_RIGHTS; 6638c2ecf20Sopenharmony_ci cmsg->cmsg_len = CMSG_LEN(fds_size); 6648c2ecf20Sopenharmony_ci memcpy(CMSG_DATA(cmsg), fds, fds_size); 6658c2ecf20Sopenharmony_ci err = sendmsg(fd, &msg, 0); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (err < 0) 6688c2ecf20Sopenharmony_ci return -errno; 6698c2ecf20Sopenharmony_ci return err; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ciint os_poll(unsigned int n, const int *fds) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci /* currently need 2 FDs at most so avoid dynamic allocation */ 6758c2ecf20Sopenharmony_ci struct pollfd pollfds[2] = {}; 6768c2ecf20Sopenharmony_ci unsigned int i; 6778c2ecf20Sopenharmony_ci int ret; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (n > ARRAY_SIZE(pollfds)) 6808c2ecf20Sopenharmony_ci return -EINVAL; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 6838c2ecf20Sopenharmony_ci pollfds[i].fd = fds[i]; 6848c2ecf20Sopenharmony_ci pollfds[i].events = POLLIN; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci ret = poll(pollfds, n, -1); 6888c2ecf20Sopenharmony_ci if (ret < 0) 6898c2ecf20Sopenharmony_ci return -errno; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Return the index of the available FD */ 6928c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 6938c2ecf20Sopenharmony_ci if (pollfds[i].revents) 6948c2ecf20Sopenharmony_ci return i; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return -EIO; 6988c2ecf20Sopenharmony_ci} 699