162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <stdio.h>
762306a36Sopenharmony_ci#include <unistd.h>
862306a36Sopenharmony_ci#include <stdlib.h>
962306a36Sopenharmony_ci#include <string.h>
1062306a36Sopenharmony_ci#include <errno.h>
1162306a36Sopenharmony_ci#include <fcntl.h>
1262306a36Sopenharmony_ci#include <signal.h>
1362306a36Sopenharmony_ci#include <linux/falloc.h>
1462306a36Sopenharmony_ci#include <sys/ioctl.h>
1562306a36Sopenharmony_ci#include <sys/mount.h>
1662306a36Sopenharmony_ci#include <sys/socket.h>
1762306a36Sopenharmony_ci#include <sys/stat.h>
1862306a36Sopenharmony_ci#include <sys/sysmacros.h>
1962306a36Sopenharmony_ci#include <sys/un.h>
2062306a36Sopenharmony_ci#include <sys/types.h>
2162306a36Sopenharmony_ci#include <sys/eventfd.h>
2262306a36Sopenharmony_ci#include <poll.h>
2362306a36Sopenharmony_ci#include <os.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic void copy_stat(struct uml_stat *dst, const struct stat64 *src)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	*dst = ((struct uml_stat) {
2862306a36Sopenharmony_ci		.ust_dev     = src->st_dev,     /* device */
2962306a36Sopenharmony_ci		.ust_ino     = src->st_ino,     /* inode */
3062306a36Sopenharmony_ci		.ust_mode    = src->st_mode,    /* protection */
3162306a36Sopenharmony_ci		.ust_nlink   = src->st_nlink,   /* number of hard links */
3262306a36Sopenharmony_ci		.ust_uid     = src->st_uid,     /* user ID of owner */
3362306a36Sopenharmony_ci		.ust_gid     = src->st_gid,     /* group ID of owner */
3462306a36Sopenharmony_ci		.ust_size    = src->st_size,    /* total size, in bytes */
3562306a36Sopenharmony_ci		.ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
3662306a36Sopenharmony_ci		.ust_blocks  = src->st_blocks,  /* number of blocks allocated */
3762306a36Sopenharmony_ci		.ust_atime   = src->st_atime,   /* time of last access */
3862306a36Sopenharmony_ci		.ust_mtime   = src->st_mtime,   /* time of last modification */
3962306a36Sopenharmony_ci		.ust_ctime   = src->st_ctime,   /* time of last change */
4062306a36Sopenharmony_ci	});
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ciint os_stat_fd(const int fd, struct uml_stat *ubuf)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct stat64 sbuf;
4662306a36Sopenharmony_ci	int err;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	CATCH_EINTR(err = fstat64(fd, &sbuf));
4962306a36Sopenharmony_ci	if (err < 0)
5062306a36Sopenharmony_ci		return -errno;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (ubuf != NULL)
5362306a36Sopenharmony_ci		copy_stat(ubuf, &sbuf);
5462306a36Sopenharmony_ci	return err;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciint os_stat_file(const char *file_name, struct uml_stat *ubuf)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	struct stat64 sbuf;
6062306a36Sopenharmony_ci	int err;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	CATCH_EINTR(err = stat64(file_name, &sbuf));
6362306a36Sopenharmony_ci	if (err < 0)
6462306a36Sopenharmony_ci		return -errno;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (ubuf != NULL)
6762306a36Sopenharmony_ci		copy_stat(ubuf, &sbuf);
6862306a36Sopenharmony_ci	return err;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ciint os_access(const char *file, int mode)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	int amode, err;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	amode = (mode & OS_ACC_R_OK ? R_OK : 0) |
7662306a36Sopenharmony_ci		(mode & OS_ACC_W_OK ? W_OK : 0) |
7762306a36Sopenharmony_ci		(mode & OS_ACC_X_OK ? X_OK : 0) |
7862306a36Sopenharmony_ci		(mode & OS_ACC_F_OK ? F_OK : 0);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	err = access(file, amode);
8162306a36Sopenharmony_ci	if (err < 0)
8262306a36Sopenharmony_ci		return -errno;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return 0;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
8862306a36Sopenharmony_ciint os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	int err;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	err = ioctl(fd, cmd, arg);
9362306a36Sopenharmony_ci	if (err < 0)
9462306a36Sopenharmony_ci		return -errno;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return err;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* FIXME: ensure namebuf in os_get_if_name is big enough */
10062306a36Sopenharmony_ciint os_get_ifname(int fd, char* namebuf)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (ioctl(fd, SIOCGIFNAME, namebuf) < 0)
10362306a36Sopenharmony_ci		return -errno;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	return 0;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciint os_set_slip(int fd)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	int disc, sencap;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	disc = N_SLIP;
11362306a36Sopenharmony_ci	if (ioctl(fd, TIOCSETD, &disc) < 0)
11462306a36Sopenharmony_ci		return -errno;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	sencap = 0;
11762306a36Sopenharmony_ci	if (ioctl(fd, SIOCSIFENCAP, &sencap) < 0)
11862306a36Sopenharmony_ci		return -errno;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciint os_mode_fd(int fd, int mode)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	int err;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	CATCH_EINTR(err = fchmod(fd, mode));
12862306a36Sopenharmony_ci	if (err < 0)
12962306a36Sopenharmony_ci		return -errno;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return 0;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciint os_file_type(char *file)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct uml_stat buf;
13762306a36Sopenharmony_ci	int err;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	err = os_stat_file(file, &buf);
14062306a36Sopenharmony_ci	if (err < 0)
14162306a36Sopenharmony_ci		return err;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (S_ISDIR(buf.ust_mode))
14462306a36Sopenharmony_ci		return OS_TYPE_DIR;
14562306a36Sopenharmony_ci	else if (S_ISLNK(buf.ust_mode))
14662306a36Sopenharmony_ci		return OS_TYPE_SYMLINK;
14762306a36Sopenharmony_ci	else if (S_ISCHR(buf.ust_mode))
14862306a36Sopenharmony_ci		return OS_TYPE_CHARDEV;
14962306a36Sopenharmony_ci	else if (S_ISBLK(buf.ust_mode))
15062306a36Sopenharmony_ci		return OS_TYPE_BLOCKDEV;
15162306a36Sopenharmony_ci	else if (S_ISFIFO(buf.ust_mode))
15262306a36Sopenharmony_ci		return OS_TYPE_FIFO;
15362306a36Sopenharmony_ci	else if (S_ISSOCK(buf.ust_mode))
15462306a36Sopenharmony_ci		return OS_TYPE_SOCK;
15562306a36Sopenharmony_ci	else return OS_TYPE_FILE;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ciint os_file_mode(const char *file, struct openflags *mode_out)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	int err;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	*mode_out = OPENFLAGS();
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	err = access(file, W_OK);
16562306a36Sopenharmony_ci	if (err && (errno != EACCES))
16662306a36Sopenharmony_ci		return -errno;
16762306a36Sopenharmony_ci	else if (!err)
16862306a36Sopenharmony_ci		*mode_out = of_write(*mode_out);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	err = access(file, R_OK);
17162306a36Sopenharmony_ci	if (err && (errno != EACCES))
17262306a36Sopenharmony_ci		return -errno;
17362306a36Sopenharmony_ci	else if (!err)
17462306a36Sopenharmony_ci		*mode_out = of_read(*mode_out);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	return err;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciint os_open_file(const char *file, struct openflags flags, int mode)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	int fd, err, f = 0;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (flags.r && flags.w)
18462306a36Sopenharmony_ci		f = O_RDWR;
18562306a36Sopenharmony_ci	else if (flags.r)
18662306a36Sopenharmony_ci		f = O_RDONLY;
18762306a36Sopenharmony_ci	else if (flags.w)
18862306a36Sopenharmony_ci		f = O_WRONLY;
18962306a36Sopenharmony_ci	else f = 0;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (flags.s)
19262306a36Sopenharmony_ci		f |= O_SYNC;
19362306a36Sopenharmony_ci	if (flags.c)
19462306a36Sopenharmony_ci		f |= O_CREAT;
19562306a36Sopenharmony_ci	if (flags.t)
19662306a36Sopenharmony_ci		f |= O_TRUNC;
19762306a36Sopenharmony_ci	if (flags.e)
19862306a36Sopenharmony_ci		f |= O_EXCL;
19962306a36Sopenharmony_ci	if (flags.a)
20062306a36Sopenharmony_ci		f |= O_APPEND;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	fd = open64(file, f, mode);
20362306a36Sopenharmony_ci	if (fd < 0)
20462306a36Sopenharmony_ci		return -errno;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (flags.cl && fcntl(fd, F_SETFD, 1)) {
20762306a36Sopenharmony_ci		err = -errno;
20862306a36Sopenharmony_ci		close(fd);
20962306a36Sopenharmony_ci		return err;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return fd;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ciint os_connect_socket(const char *name)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct sockaddr_un sock;
21862306a36Sopenharmony_ci	int fd, err;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	sock.sun_family = AF_UNIX;
22162306a36Sopenharmony_ci	snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	fd = socket(AF_UNIX, SOCK_STREAM, 0);
22462306a36Sopenharmony_ci	if (fd < 0) {
22562306a36Sopenharmony_ci		err = -errno;
22662306a36Sopenharmony_ci		goto out;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
23062306a36Sopenharmony_ci	if (err) {
23162306a36Sopenharmony_ci		err = -errno;
23262306a36Sopenharmony_ci		goto out_close;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return fd;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ciout_close:
23862306a36Sopenharmony_ci	close(fd);
23962306a36Sopenharmony_ciout:
24062306a36Sopenharmony_ci	return err;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_civoid os_close_file(int fd)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	close(fd);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ciint os_fsync_file(int fd)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	if (fsync(fd) < 0)
25062306a36Sopenharmony_ci	    return -errno;
25162306a36Sopenharmony_ci	return 0;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ciint os_seek_file(int fd, unsigned long long offset)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	unsigned long long actual;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	actual = lseek64(fd, offset, SEEK_SET);
25962306a36Sopenharmony_ci	if (actual != offset)
26062306a36Sopenharmony_ci		return -errno;
26162306a36Sopenharmony_ci	return 0;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ciint os_read_file(int fd, void *buf, int len)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	int n = read(fd, buf, len);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (n < 0)
26962306a36Sopenharmony_ci		return -errno;
27062306a36Sopenharmony_ci	return n;
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ciint os_pread_file(int fd, void *buf, int len, unsigned long long offset)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	int n = pread(fd, buf, len, offset);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (n < 0)
27862306a36Sopenharmony_ci		return -errno;
27962306a36Sopenharmony_ci	return n;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ciint os_write_file(int fd, const void *buf, int len)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	int n = write(fd, (void *) buf, len);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	if (n < 0)
28762306a36Sopenharmony_ci		return -errno;
28862306a36Sopenharmony_ci	return n;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciint os_sync_file(int fd)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	int n = fdatasync(fd);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (n < 0)
29662306a36Sopenharmony_ci		return -errno;
29762306a36Sopenharmony_ci	return n;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ciint os_pwrite_file(int fd, const void *buf, int len, unsigned long long offset)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	int n = pwrite(fd, (void *) buf, len, offset);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (n < 0)
30562306a36Sopenharmony_ci		return -errno;
30662306a36Sopenharmony_ci	return n;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ciint os_file_size(const char *file, unsigned long long *size_out)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	struct uml_stat buf;
31362306a36Sopenharmony_ci	int err;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	err = os_stat_file(file, &buf);
31662306a36Sopenharmony_ci	if (err < 0) {
31762306a36Sopenharmony_ci		printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
31862306a36Sopenharmony_ci		       -err);
31962306a36Sopenharmony_ci		return err;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if (S_ISBLK(buf.ust_mode)) {
32362306a36Sopenharmony_ci		int fd;
32462306a36Sopenharmony_ci		long blocks;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		fd = open(file, O_RDONLY, 0);
32762306a36Sopenharmony_ci		if (fd < 0) {
32862306a36Sopenharmony_ci			err = -errno;
32962306a36Sopenharmony_ci			printk(UM_KERN_ERR "Couldn't open \"%s\", "
33062306a36Sopenharmony_ci			       "errno = %d\n", file, errno);
33162306a36Sopenharmony_ci			return err;
33262306a36Sopenharmony_ci		}
33362306a36Sopenharmony_ci		if (ioctl(fd, BLKGETSIZE, &blocks) < 0) {
33462306a36Sopenharmony_ci			err = -errno;
33562306a36Sopenharmony_ci			printk(UM_KERN_ERR "Couldn't get the block size of "
33662306a36Sopenharmony_ci			       "\"%s\", errno = %d\n", file, errno);
33762306a36Sopenharmony_ci			close(fd);
33862306a36Sopenharmony_ci			return err;
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci		*size_out = ((long long) blocks) * 512;
34162306a36Sopenharmony_ci		close(fd);
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci	else *size_out = buf.ust_size;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return 0;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ciint os_file_modtime(const char *file, long long *modtime)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	struct uml_stat buf;
35162306a36Sopenharmony_ci	int err;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	err = os_stat_file(file, &buf);
35462306a36Sopenharmony_ci	if (err < 0) {
35562306a36Sopenharmony_ci		printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
35662306a36Sopenharmony_ci		       -err);
35762306a36Sopenharmony_ci		return err;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	*modtime = buf.ust_mtime;
36162306a36Sopenharmony_ci	return 0;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ciint os_set_exec_close(int fd)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	int err;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	CATCH_EINTR(err = fcntl(fd, F_SETFD, FD_CLOEXEC));
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (err < 0)
37162306a36Sopenharmony_ci		return -errno;
37262306a36Sopenharmony_ci	return err;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ciint os_pipe(int *fds, int stream, int close_on_exec)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	err = socketpair(AF_UNIX, type, 0, fds);
38062306a36Sopenharmony_ci	if (err < 0)
38162306a36Sopenharmony_ci		return -errno;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (!close_on_exec)
38462306a36Sopenharmony_ci		return 0;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	err = os_set_exec_close(fds[0]);
38762306a36Sopenharmony_ci	if (err < 0)
38862306a36Sopenharmony_ci		goto error;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	err = os_set_exec_close(fds[1]);
39162306a36Sopenharmony_ci	if (err < 0)
39262306a36Sopenharmony_ci		goto error;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return 0;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci error:
39762306a36Sopenharmony_ci	printk(UM_KERN_ERR "os_pipe : Setting FD_CLOEXEC failed, err = %d\n",
39862306a36Sopenharmony_ci	       -err);
39962306a36Sopenharmony_ci	close(fds[1]);
40062306a36Sopenharmony_ci	close(fds[0]);
40162306a36Sopenharmony_ci	return err;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ciint os_set_fd_async(int fd)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	int err, flags;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	flags = fcntl(fd, F_GETFL);
40962306a36Sopenharmony_ci	if (flags < 0)
41062306a36Sopenharmony_ci		return -errno;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	flags |= O_ASYNC | O_NONBLOCK;
41362306a36Sopenharmony_ci	if (fcntl(fd, F_SETFL, flags) < 0) {
41462306a36Sopenharmony_ci		err = -errno;
41562306a36Sopenharmony_ci		printk(UM_KERN_ERR "os_set_fd_async : failed to set O_ASYNC "
41662306a36Sopenharmony_ci		       "and O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
41762306a36Sopenharmony_ci		return err;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if ((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
42162306a36Sopenharmony_ci	    (fcntl(fd, F_SETOWN, os_getpid()) < 0)) {
42262306a36Sopenharmony_ci		err = -errno;
42362306a36Sopenharmony_ci		printk(UM_KERN_ERR "os_set_fd_async : Failed to fcntl F_SETOWN "
42462306a36Sopenharmony_ci		       "(or F_SETSIG) fd %d, errno = %d\n", fd, errno);
42562306a36Sopenharmony_ci		return err;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return 0;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ciint os_clear_fd_async(int fd)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	int flags;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	flags = fcntl(fd, F_GETFL);
43662306a36Sopenharmony_ci	if (flags < 0)
43762306a36Sopenharmony_ci		return -errno;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	flags &= ~(O_ASYNC | O_NONBLOCK);
44062306a36Sopenharmony_ci	if (fcntl(fd, F_SETFL, flags) < 0)
44162306a36Sopenharmony_ci		return -errno;
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ciint os_set_fd_block(int fd, int blocking)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	int flags;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	flags = fcntl(fd, F_GETFL);
45062306a36Sopenharmony_ci	if (flags < 0)
45162306a36Sopenharmony_ci		return -errno;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (blocking)
45462306a36Sopenharmony_ci		flags &= ~O_NONBLOCK;
45562306a36Sopenharmony_ci	else
45662306a36Sopenharmony_ci		flags |= O_NONBLOCK;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (fcntl(fd, F_SETFL, flags) < 0)
45962306a36Sopenharmony_ci		return -errno;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	return 0;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ciint os_accept_connection(int fd)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	int new;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	new = accept(fd, NULL, 0);
46962306a36Sopenharmony_ci	if (new < 0)
47062306a36Sopenharmony_ci		return -errno;
47162306a36Sopenharmony_ci	return new;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci#ifndef SHUT_RD
47562306a36Sopenharmony_ci#define SHUT_RD 0
47662306a36Sopenharmony_ci#endif
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci#ifndef SHUT_WR
47962306a36Sopenharmony_ci#define SHUT_WR 1
48062306a36Sopenharmony_ci#endif
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci#ifndef SHUT_RDWR
48362306a36Sopenharmony_ci#define SHUT_RDWR 2
48462306a36Sopenharmony_ci#endif
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ciint os_shutdown_socket(int fd, int r, int w)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	int what, err;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (r && w)
49162306a36Sopenharmony_ci		what = SHUT_RDWR;
49262306a36Sopenharmony_ci	else if (r)
49362306a36Sopenharmony_ci		what = SHUT_RD;
49462306a36Sopenharmony_ci	else if (w)
49562306a36Sopenharmony_ci		what = SHUT_WR;
49662306a36Sopenharmony_ci	else
49762306a36Sopenharmony_ci		return -EINVAL;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	err = shutdown(fd, what);
50062306a36Sopenharmony_ci	if (err < 0)
50162306a36Sopenharmony_ci		return -errno;
50262306a36Sopenharmony_ci	return 0;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ciint os_rcv_fd(int fd, int *helper_pid_out)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	int new, n;
50862306a36Sopenharmony_ci	char buf[CMSG_SPACE(sizeof(new))];
50962306a36Sopenharmony_ci	struct msghdr msg;
51062306a36Sopenharmony_ci	struct cmsghdr *cmsg;
51162306a36Sopenharmony_ci	struct iovec iov;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	msg.msg_name = NULL;
51462306a36Sopenharmony_ci	msg.msg_namelen = 0;
51562306a36Sopenharmony_ci	iov = ((struct iovec) { .iov_base  = helper_pid_out,
51662306a36Sopenharmony_ci				.iov_len   = sizeof(*helper_pid_out) });
51762306a36Sopenharmony_ci	msg.msg_iov = &iov;
51862306a36Sopenharmony_ci	msg.msg_iovlen = 1;
51962306a36Sopenharmony_ci	msg.msg_control = buf;
52062306a36Sopenharmony_ci	msg.msg_controllen = sizeof(buf);
52162306a36Sopenharmony_ci	msg.msg_flags = 0;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	n = recvmsg(fd, &msg, 0);
52462306a36Sopenharmony_ci	if (n < 0)
52562306a36Sopenharmony_ci		return -errno;
52662306a36Sopenharmony_ci	else if (n != iov.iov_len)
52762306a36Sopenharmony_ci		*helper_pid_out = -1;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	cmsg = CMSG_FIRSTHDR(&msg);
53062306a36Sopenharmony_ci	if (cmsg == NULL) {
53162306a36Sopenharmony_ci		printk(UM_KERN_ERR "rcv_fd didn't receive anything, "
53262306a36Sopenharmony_ci		       "error = %d\n", errno);
53362306a36Sopenharmony_ci		return -1;
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci	if ((cmsg->cmsg_level != SOL_SOCKET) ||
53662306a36Sopenharmony_ci	    (cmsg->cmsg_type != SCM_RIGHTS)) {
53762306a36Sopenharmony_ci		printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n");
53862306a36Sopenharmony_ci		return -1;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	new = ((int *) CMSG_DATA(cmsg))[0];
54262306a36Sopenharmony_ci	return new;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ciint os_create_unix_socket(const char *file, int len, int close_on_exec)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct sockaddr_un addr;
54862306a36Sopenharmony_ci	int sock, err;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
55162306a36Sopenharmony_ci	if (sock < 0)
55262306a36Sopenharmony_ci		return -errno;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (close_on_exec) {
55562306a36Sopenharmony_ci		err = os_set_exec_close(sock);
55662306a36Sopenharmony_ci		if (err < 0)
55762306a36Sopenharmony_ci			printk(UM_KERN_ERR "create_unix_socket : "
55862306a36Sopenharmony_ci			       "close_on_exec failed, err = %d", -err);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	addr.sun_family = AF_UNIX;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	snprintf(addr.sun_path, len, "%s", file);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
56662306a36Sopenharmony_ci	if (err < 0)
56762306a36Sopenharmony_ci		return -errno;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	return sock;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_civoid os_flush_stdout(void)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	fflush(stdout);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ciint os_lock_file(int fd, int excl)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	int type = excl ? F_WRLCK : F_RDLCK;
58062306a36Sopenharmony_ci	struct flock lock = ((struct flock) { .l_type	= type,
58162306a36Sopenharmony_ci					      .l_whence	= SEEK_SET,
58262306a36Sopenharmony_ci					      .l_start	= 0,
58362306a36Sopenharmony_ci					      .l_len	= 0 } );
58462306a36Sopenharmony_ci	int err, save;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	err = fcntl(fd, F_SETLK, &lock);
58762306a36Sopenharmony_ci	if (!err)
58862306a36Sopenharmony_ci		goto out;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	save = -errno;
59162306a36Sopenharmony_ci	err = fcntl(fd, F_GETLK, &lock);
59262306a36Sopenharmony_ci	if (err) {
59362306a36Sopenharmony_ci		err = -errno;
59462306a36Sopenharmony_ci		goto out;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	printk(UM_KERN_ERR "F_SETLK failed, file already locked by pid %d\n",
59862306a36Sopenharmony_ci	       lock.l_pid);
59962306a36Sopenharmony_ci	err = save;
60062306a36Sopenharmony_ci out:
60162306a36Sopenharmony_ci	return err;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ciunsigned os_major(unsigned long long dev)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	return major(dev);
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ciunsigned os_minor(unsigned long long dev)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	return minor(dev);
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ciunsigned long long os_makedev(unsigned major, unsigned minor)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	return makedev(major, minor);
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ciint os_falloc_punch(int fd, unsigned long long offset, int len)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	int n = fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, offset, len);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (n < 0)
62462306a36Sopenharmony_ci		return -errno;
62562306a36Sopenharmony_ci	return n;
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ciint os_falloc_zeroes(int fd, unsigned long long offset, int len)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	int n = fallocate(fd, FALLOC_FL_ZERO_RANGE|FALLOC_FL_KEEP_SIZE, offset, len);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (n < 0)
63362306a36Sopenharmony_ci		return -errno;
63462306a36Sopenharmony_ci	return n;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ciint os_eventfd(unsigned int initval, int flags)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	int fd = eventfd(initval, flags);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (fd < 0)
64262306a36Sopenharmony_ci		return -errno;
64362306a36Sopenharmony_ci	return fd;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ciint os_sendmsg_fds(int fd, const void *buf, unsigned int len, const int *fds,
64762306a36Sopenharmony_ci		   unsigned int fds_num)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	struct iovec iov = {
65062306a36Sopenharmony_ci		.iov_base = (void *) buf,
65162306a36Sopenharmony_ci		.iov_len = len,
65262306a36Sopenharmony_ci	};
65362306a36Sopenharmony_ci	union {
65462306a36Sopenharmony_ci		char control[CMSG_SPACE(sizeof(*fds) * OS_SENDMSG_MAX_FDS)];
65562306a36Sopenharmony_ci		struct cmsghdr align;
65662306a36Sopenharmony_ci	} u;
65762306a36Sopenharmony_ci	unsigned int fds_size = sizeof(*fds) * fds_num;
65862306a36Sopenharmony_ci	struct msghdr msg = {
65962306a36Sopenharmony_ci		.msg_iov = &iov,
66062306a36Sopenharmony_ci		.msg_iovlen = 1,
66162306a36Sopenharmony_ci		.msg_control = u.control,
66262306a36Sopenharmony_ci		.msg_controllen = CMSG_SPACE(fds_size),
66362306a36Sopenharmony_ci	};
66462306a36Sopenharmony_ci	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
66562306a36Sopenharmony_ci	int err;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	if (fds_num > OS_SENDMSG_MAX_FDS)
66862306a36Sopenharmony_ci		return -EINVAL;
66962306a36Sopenharmony_ci	memset(u.control, 0, sizeof(u.control));
67062306a36Sopenharmony_ci	cmsg->cmsg_level = SOL_SOCKET;
67162306a36Sopenharmony_ci	cmsg->cmsg_type = SCM_RIGHTS;
67262306a36Sopenharmony_ci	cmsg->cmsg_len = CMSG_LEN(fds_size);
67362306a36Sopenharmony_ci	memcpy(CMSG_DATA(cmsg), fds, fds_size);
67462306a36Sopenharmony_ci	err = sendmsg(fd, &msg, 0);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	if (err < 0)
67762306a36Sopenharmony_ci		return -errno;
67862306a36Sopenharmony_ci	return err;
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ciint os_poll(unsigned int n, const int *fds)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	/* currently need 2 FDs at most so avoid dynamic allocation */
68462306a36Sopenharmony_ci	struct pollfd pollfds[2] = {};
68562306a36Sopenharmony_ci	unsigned int i;
68662306a36Sopenharmony_ci	int ret;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	if (n > ARRAY_SIZE(pollfds))
68962306a36Sopenharmony_ci		return -EINVAL;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
69262306a36Sopenharmony_ci		pollfds[i].fd = fds[i];
69362306a36Sopenharmony_ci		pollfds[i].events = POLLIN;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	ret = poll(pollfds, n, -1);
69762306a36Sopenharmony_ci	if (ret < 0)
69862306a36Sopenharmony_ci		return -errno;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	/* Return the index of the available FD */
70162306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
70262306a36Sopenharmony_ci		if (pollfds[i].revents)
70362306a36Sopenharmony_ci			return i;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	return -EIO;
70762306a36Sopenharmony_ci}
708