xref: /openbmc/linux/arch/um/os-Linux/file.c (revision d2a0a616)
197870c34SAlex Dewar // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31adfd609SJeff Dike  * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <stdio.h>
71da177e4SLinus Torvalds #include <unistd.h>
888ce6424SJohannes Berg #include <stdlib.h>
938bccfbeSZach van Rijn #include <string.h>
101da177e4SLinus Torvalds #include <errno.h>
111da177e4SLinus Torvalds #include <fcntl.h>
121da177e4SLinus Torvalds #include <signal.h>
1335f34013SAlan Maguire #include <linux/falloc.h>
141da177e4SLinus Torvalds #include <sys/ioctl.h>
151da177e4SLinus Torvalds #include <sys/mount.h>
161adfd609SJeff Dike #include <sys/socket.h>
171adfd609SJeff Dike #include <sys/stat.h>
18530ba6c7SJason A. Donenfeld #include <sys/sysmacros.h>
191adfd609SJeff Dike #include <sys/un.h>
208eeba4e9SHans-Werner Hilse #include <sys/types.h>
215d38f324SErel Geron #include <sys/eventfd.h>
2288ce6424SJohannes Berg #include <poll.h>
2337185b33SAl Viro #include <os.h>
241da177e4SLinus Torvalds 
copy_stat(struct uml_stat * dst,const struct stat64 * src)25c9a3072dSWANG Cong static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
261da177e4SLinus Torvalds {
271da177e4SLinus Torvalds 	*dst = ((struct uml_stat) {
281da177e4SLinus Torvalds 		.ust_dev     = src->st_dev,     /* device */
291da177e4SLinus Torvalds 		.ust_ino     = src->st_ino,     /* inode */
301da177e4SLinus Torvalds 		.ust_mode    = src->st_mode,    /* protection */
311da177e4SLinus Torvalds 		.ust_nlink   = src->st_nlink,   /* number of hard links */
321da177e4SLinus Torvalds 		.ust_uid     = src->st_uid,     /* user ID of owner */
331da177e4SLinus Torvalds 		.ust_gid     = src->st_gid,     /* group ID of owner */
341da177e4SLinus Torvalds 		.ust_size    = src->st_size,    /* total size, in bytes */
351da177e4SLinus Torvalds 		.ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
361da177e4SLinus Torvalds 		.ust_blocks  = src->st_blocks,  /* number of blocks allocated */
371da177e4SLinus Torvalds 		.ust_atime   = src->st_atime,   /* time of last access */
381da177e4SLinus Torvalds 		.ust_mtime   = src->st_mtime,   /* time of last modification */
391da177e4SLinus Torvalds 		.ust_ctime   = src->st_ctime,   /* time of last change */
401da177e4SLinus Torvalds 	});
411da177e4SLinus Torvalds }
421da177e4SLinus Torvalds 
os_stat_fd(const int fd,struct uml_stat * ubuf)431da177e4SLinus Torvalds int os_stat_fd(const int fd, struct uml_stat *ubuf)
441da177e4SLinus Torvalds {
451da177e4SLinus Torvalds 	struct stat64 sbuf;
461da177e4SLinus Torvalds 	int err;
471da177e4SLinus Torvalds 
489ead6feeSJeff Dike 	CATCH_EINTR(err = fstat64(fd, &sbuf));
491da177e4SLinus Torvalds 	if (err < 0)
50108ffa8cSJeff Dike 		return -errno;
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	if (ubuf != NULL)
531da177e4SLinus Torvalds 		copy_stat(ubuf, &sbuf);
54108ffa8cSJeff Dike 	return err;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
os_stat_file(const char * file_name,struct uml_stat * ubuf)571da177e4SLinus Torvalds int os_stat_file(const char *file_name, struct uml_stat *ubuf)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds 	struct stat64 sbuf;
601da177e4SLinus Torvalds 	int err;
611da177e4SLinus Torvalds 
621adfd609SJeff Dike 	CATCH_EINTR(err = stat64(file_name, &sbuf));
631da177e4SLinus Torvalds 	if (err < 0)
64108ffa8cSJeff Dike 		return -errno;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	if (ubuf != NULL)
671da177e4SLinus Torvalds 		copy_stat(ubuf, &sbuf);
68108ffa8cSJeff Dike 	return err;
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
os_access(const char * file,int mode)711da177e4SLinus Torvalds int os_access(const char *file, int mode)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	int amode, err;
741da177e4SLinus Torvalds 
751adfd609SJeff Dike 	amode = (mode & OS_ACC_R_OK ? R_OK : 0) |
761adfd609SJeff Dike 		(mode & OS_ACC_W_OK ? W_OK : 0) |
771adfd609SJeff Dike 		(mode & OS_ACC_X_OK ? X_OK : 0) |
781adfd609SJeff Dike 		(mode & OS_ACC_F_OK ? F_OK : 0);
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 	err = access(file, amode);
811da177e4SLinus Torvalds 	if (err < 0)
82108ffa8cSJeff Dike 		return -errno;
831da177e4SLinus Torvalds 
84108ffa8cSJeff Dike 	return 0;
851da177e4SLinus Torvalds }
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds /* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
os_ioctl_generic(int fd,unsigned int cmd,unsigned long arg)881da177e4SLinus Torvalds int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
891da177e4SLinus Torvalds {
901da177e4SLinus Torvalds 	int err;
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds 	err = ioctl(fd, cmd, arg);
931da177e4SLinus Torvalds 	if (err < 0)
94108ffa8cSJeff Dike 		return -errno;
951da177e4SLinus Torvalds 
96108ffa8cSJeff Dike 	return err;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds /* FIXME: ensure namebuf in os_get_if_name is big enough */
os_get_ifname(int fd,char * namebuf)1001da177e4SLinus Torvalds int os_get_ifname(int fd, char* namebuf)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds 	if (ioctl(fd, SIOCGIFNAME, namebuf) < 0)
103108ffa8cSJeff Dike 		return -errno;
1041da177e4SLinus Torvalds 
105108ffa8cSJeff Dike 	return 0;
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds 
os_set_slip(int fd)1081da177e4SLinus Torvalds int os_set_slip(int fd)
1091da177e4SLinus Torvalds {
1101da177e4SLinus Torvalds 	int disc, sencap;
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds 	disc = N_SLIP;
113b4fd310eSJeff Dike 	if (ioctl(fd, TIOCSETD, &disc) < 0)
114b4fd310eSJeff Dike 		return -errno;
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	sencap = 0;
117b4fd310eSJeff Dike 	if (ioctl(fd, SIOCSIFENCAP, &sencap) < 0)
118b4fd310eSJeff Dike 		return -errno;
1191da177e4SLinus Torvalds 
120108ffa8cSJeff Dike 	return 0;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
os_mode_fd(int fd,int mode)1231da177e4SLinus Torvalds int os_mode_fd(int fd, int mode)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	int err;
1261da177e4SLinus Torvalds 
1271adfd609SJeff Dike 	CATCH_EINTR(err = fchmod(fd, mode));
1281da177e4SLinus Torvalds 	if (err < 0)
129108ffa8cSJeff Dike 		return -errno;
1301da177e4SLinus Torvalds 
131108ffa8cSJeff Dike 	return 0;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds 
os_file_type(char * file)1341da177e4SLinus Torvalds int os_file_type(char *file)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds 	struct uml_stat buf;
1371da177e4SLinus Torvalds 	int err;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	err = os_stat_file(file, &buf);
1401da177e4SLinus Torvalds 	if (err < 0)
141108ffa8cSJeff Dike 		return err;
1421da177e4SLinus Torvalds 
143108ffa8cSJeff Dike 	if (S_ISDIR(buf.ust_mode))
144108ffa8cSJeff Dike 		return OS_TYPE_DIR;
145108ffa8cSJeff Dike 	else if (S_ISLNK(buf.ust_mode))
146108ffa8cSJeff Dike 		return OS_TYPE_SYMLINK;
147108ffa8cSJeff Dike 	else if (S_ISCHR(buf.ust_mode))
148108ffa8cSJeff Dike 		return OS_TYPE_CHARDEV;
149108ffa8cSJeff Dike 	else if (S_ISBLK(buf.ust_mode))
150108ffa8cSJeff Dike 		return OS_TYPE_BLOCKDEV;
151108ffa8cSJeff Dike 	else if (S_ISFIFO(buf.ust_mode))
152108ffa8cSJeff Dike 		return OS_TYPE_FIFO;
153108ffa8cSJeff Dike 	else if (S_ISSOCK(buf.ust_mode))
154108ffa8cSJeff Dike 		return OS_TYPE_SOCK;
155108ffa8cSJeff Dike 	else return OS_TYPE_FILE;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
os_file_mode(const char * file,struct openflags * mode_out)158c9a3072dSWANG Cong int os_file_mode(const char *file, struct openflags *mode_out)
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds 	int err;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	*mode_out = OPENFLAGS();
1631da177e4SLinus Torvalds 
164512b6fb1SJeff Dike 	err = access(file, W_OK);
165512b6fb1SJeff Dike 	if (err && (errno != EACCES))
166512b6fb1SJeff Dike 		return -errno;
167512b6fb1SJeff Dike 	else if (!err)
1681da177e4SLinus Torvalds 		*mode_out = of_write(*mode_out);
1691da177e4SLinus Torvalds 
170512b6fb1SJeff Dike 	err = access(file, R_OK);
171512b6fb1SJeff Dike 	if (err && (errno != EACCES))
172512b6fb1SJeff Dike 		return -errno;
173512b6fb1SJeff Dike 	else if (!err)
1741da177e4SLinus Torvalds 		*mode_out = of_read(*mode_out);
1751da177e4SLinus Torvalds 
176512b6fb1SJeff Dike 	return err;
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds 
os_open_file(const char * file,struct openflags flags,int mode)179c9a3072dSWANG Cong int os_open_file(const char *file, struct openflags flags, int mode)
1801da177e4SLinus Torvalds {
181b4fd310eSJeff Dike 	int fd, err, f = 0;
1821da177e4SLinus Torvalds 
1831adfd609SJeff Dike 	if (flags.r && flags.w)
1841adfd609SJeff Dike 		f = O_RDWR;
1851adfd609SJeff Dike 	else if (flags.r)
1861adfd609SJeff Dike 		f = O_RDONLY;
1871adfd609SJeff Dike 	else if (flags.w)
1881adfd609SJeff Dike 		f = O_WRONLY;
1891da177e4SLinus Torvalds 	else f = 0;
1901da177e4SLinus Torvalds 
1911adfd609SJeff Dike 	if (flags.s)
1921adfd609SJeff Dike 		f |= O_SYNC;
1931adfd609SJeff Dike 	if (flags.c)
1941adfd609SJeff Dike 		f |= O_CREAT;
1951adfd609SJeff Dike 	if (flags.t)
1961adfd609SJeff Dike 		f |= O_TRUNC;
1971adfd609SJeff Dike 	if (flags.e)
1981adfd609SJeff Dike 		f |= O_EXCL;
199bf53d85eSJeff Dike 	if (flags.a)
200bf53d85eSJeff Dike 		f |= O_APPEND;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	fd = open64(file, f, mode);
2031da177e4SLinus Torvalds 	if (fd < 0)
204512b6fb1SJeff Dike 		return -errno;
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	if (flags.cl && fcntl(fd, F_SETFD, 1)) {
207b4fd310eSJeff Dike 		err = -errno;
208512b6fb1SJeff Dike 		close(fd);
209b4fd310eSJeff Dike 		return err;
2101da177e4SLinus Torvalds 	}
2111da177e4SLinus Torvalds 
212512b6fb1SJeff Dike 	return fd;
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds 
os_connect_socket(const char * name)215c9a3072dSWANG Cong int os_connect_socket(const char *name)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	struct sockaddr_un sock;
2181da177e4SLinus Torvalds 	int fd, err;
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds 	sock.sun_family = AF_UNIX;
2211da177e4SLinus Torvalds 	snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
224dc1561acSPaolo 'Blaisorblade' Giarrusso 	if (fd < 0) {
225dc1561acSPaolo 'Blaisorblade' Giarrusso 		err = -errno;
226dc1561acSPaolo 'Blaisorblade' Giarrusso 		goto out;
227dc1561acSPaolo 'Blaisorblade' Giarrusso 	}
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 	err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
230dc1561acSPaolo 'Blaisorblade' Giarrusso 	if (err) {
231dc1561acSPaolo 'Blaisorblade' Giarrusso 		err = -errno;
232dc1561acSPaolo 'Blaisorblade' Giarrusso 		goto out_close;
233dc1561acSPaolo 'Blaisorblade' Giarrusso 	}
2341da177e4SLinus Torvalds 
235dc1561acSPaolo 'Blaisorblade' Giarrusso 	return fd;
236dc1561acSPaolo 'Blaisorblade' Giarrusso 
237dc1561acSPaolo 'Blaisorblade' Giarrusso out_close:
238dc1561acSPaolo 'Blaisorblade' Giarrusso 	close(fd);
239dc1561acSPaolo 'Blaisorblade' Giarrusso out:
240dc1561acSPaolo 'Blaisorblade' Giarrusso 	return err;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
os_close_file(int fd)2431da177e4SLinus Torvalds void os_close_file(int fd)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds 	close(fd);
2461da177e4SLinus Torvalds }
os_fsync_file(int fd)2470565103dSAnton Ivanov int os_fsync_file(int fd)
2480565103dSAnton Ivanov {
2490565103dSAnton Ivanov 	if (fsync(fd) < 0)
2500565103dSAnton Ivanov 	    return -errno;
2510565103dSAnton Ivanov 	return 0;
2520565103dSAnton Ivanov }
2531da177e4SLinus Torvalds 
os_seek_file(int fd,unsigned long long offset)254ba180fd4SJeff Dike int os_seek_file(int fd, unsigned long long offset)
2551da177e4SLinus Torvalds {
256ba180fd4SJeff Dike 	unsigned long long actual;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	actual = lseek64(fd, offset, SEEK_SET);
2591da177e4SLinus Torvalds 	if (actual != offset)
260108ffa8cSJeff Dike 		return -errno;
261108ffa8cSJeff Dike 	return 0;
2621da177e4SLinus Torvalds }
2631da177e4SLinus Torvalds 
os_read_file(int fd,void * buf,int len)2641da177e4SLinus Torvalds int os_read_file(int fd, void *buf, int len)
2651da177e4SLinus Torvalds {
2663d564047SJeff Dike 	int n = read(fd, buf, len);
2673d564047SJeff Dike 
2683d564047SJeff Dike 	if (n < 0)
2693d564047SJeff Dike 		return -errno;
2703d564047SJeff Dike 	return n;
2713d564047SJeff Dike }
2723d564047SJeff Dike 
os_pread_file(int fd,void * buf,int len,unsigned long long offset)2738c6157b6SAnton Ivanov int os_pread_file(int fd, void *buf, int len, unsigned long long offset)
2748c6157b6SAnton Ivanov {
2758c6157b6SAnton Ivanov 	int n = pread(fd, buf, len, offset);
2768c6157b6SAnton Ivanov 
2778c6157b6SAnton Ivanov 	if (n < 0)
2788c6157b6SAnton Ivanov 		return -errno;
2798c6157b6SAnton Ivanov 	return n;
2808c6157b6SAnton Ivanov }
2818c6157b6SAnton Ivanov 
os_write_file(int fd,const void * buf,int len)2821da177e4SLinus Torvalds int os_write_file(int fd, const void *buf, int len)
2831da177e4SLinus Torvalds {
2843d564047SJeff Dike 	int n = write(fd, (void *) buf, len);
2853d564047SJeff Dike 
2863d564047SJeff Dike 	if (n < 0)
2873d564047SJeff Dike 		return -errno;
2883d564047SJeff Dike 	return n;
2893d564047SJeff Dike }
2903d564047SJeff Dike 
os_sync_file(int fd)291805f11a0SRichard Weinberger int os_sync_file(int fd)
292805f11a0SRichard Weinberger {
29354ebe406SAnton Ivanov 	int n = fdatasync(fd);
294805f11a0SRichard Weinberger 
295805f11a0SRichard Weinberger 	if (n < 0)
296805f11a0SRichard Weinberger 		return -errno;
297805f11a0SRichard Weinberger 	return n;
298805f11a0SRichard Weinberger }
299805f11a0SRichard Weinberger 
os_pwrite_file(int fd,const void * buf,int len,unsigned long long offset)3008c6157b6SAnton Ivanov int os_pwrite_file(int fd, const void *buf, int len, unsigned long long offset)
3018c6157b6SAnton Ivanov {
3028c6157b6SAnton Ivanov 	int n = pwrite(fd, (void *) buf, len, offset);
3038c6157b6SAnton Ivanov 
3048c6157b6SAnton Ivanov 	if (n < 0)
3058c6157b6SAnton Ivanov 		return -errno;
3068c6157b6SAnton Ivanov 	return n;
3078c6157b6SAnton Ivanov }
3088c6157b6SAnton Ivanov 
3098c6157b6SAnton Ivanov 
os_file_size(const char * file,unsigned long long * size_out)310c9a3072dSWANG Cong int os_file_size(const char *file, unsigned long long *size_out)
3111da177e4SLinus Torvalds {
3121da177e4SLinus Torvalds 	struct uml_stat buf;
3131da177e4SLinus Torvalds 	int err;
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	err = os_stat_file(file, &buf);
3161da177e4SLinus Torvalds 	if (err < 0) {
3171adfd609SJeff Dike 		printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
3181adfd609SJeff Dike 		       -err);
319512b6fb1SJeff Dike 		return err;
3201da177e4SLinus Torvalds 	}
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 	if (S_ISBLK(buf.ust_mode)) {
3232c392a4fSNicolas George 		int fd;
3242c392a4fSNicolas George 		long blocks;
3251da177e4SLinus Torvalds 
326512b6fb1SJeff Dike 		fd = open(file, O_RDONLY, 0);
3271da177e4SLinus Torvalds 		if (fd < 0) {
328512b6fb1SJeff Dike 			err = -errno;
3291adfd609SJeff Dike 			printk(UM_KERN_ERR "Couldn't open \"%s\", "
3301adfd609SJeff Dike 			       "errno = %d\n", file, errno);
331512b6fb1SJeff Dike 			return err;
3321da177e4SLinus Torvalds 		}
3331da177e4SLinus Torvalds 		if (ioctl(fd, BLKGETSIZE, &blocks) < 0) {
334b4fd310eSJeff Dike 			err = -errno;
3351adfd609SJeff Dike 			printk(UM_KERN_ERR "Couldn't get the block size of "
3361adfd609SJeff Dike 			       "\"%s\", errno = %d\n", file, errno);
337512b6fb1SJeff Dike 			close(fd);
338512b6fb1SJeff Dike 			return err;
3391da177e4SLinus Torvalds 		}
3401da177e4SLinus Torvalds 		*size_out = ((long long) blocks) * 512;
341512b6fb1SJeff Dike 		close(fd);
3421da177e4SLinus Torvalds 	}
343512b6fb1SJeff Dike 	else *size_out = buf.ust_size;
344512b6fb1SJeff Dike 
345512b6fb1SJeff Dike 	return 0;
3461da177e4SLinus Torvalds }
3471da177e4SLinus Torvalds 
os_file_modtime(const char * file,long long * modtime)348853bc0abSArnd Bergmann int os_file_modtime(const char *file, long long *modtime)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds 	struct uml_stat buf;
3511da177e4SLinus Torvalds 	int err;
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	err = os_stat_file(file, &buf);
3541da177e4SLinus Torvalds 	if (err < 0) {
3551adfd609SJeff Dike 		printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
3561adfd609SJeff Dike 		       -err);
357108ffa8cSJeff Dike 		return err;
3581da177e4SLinus Torvalds 	}
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 	*modtime = buf.ust_mtime;
361108ffa8cSJeff Dike 	return 0;
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds 
os_set_exec_close(int fd)364512b6fb1SJeff Dike int os_set_exec_close(int fd)
3651da177e4SLinus Torvalds {
366512b6fb1SJeff Dike 	int err;
3671da177e4SLinus Torvalds 
368512b6fb1SJeff Dike 	CATCH_EINTR(err = fcntl(fd, F_SETFD, FD_CLOEXEC));
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	if (err < 0)
371512b6fb1SJeff Dike 		return -errno;
372512b6fb1SJeff Dike 	return err;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds 
os_pipe(int * fds,int stream,int close_on_exec)3751da177e4SLinus Torvalds int os_pipe(int *fds, int stream, int close_on_exec)
3761da177e4SLinus Torvalds {
3771da177e4SLinus Torvalds 	int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	err = socketpair(AF_UNIX, type, 0, fds);
3801da177e4SLinus Torvalds 	if (err < 0)
381512b6fb1SJeff Dike 		return -errno;
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 	if (!close_on_exec)
384512b6fb1SJeff Dike 		return 0;
3851da177e4SLinus Torvalds 
386512b6fb1SJeff Dike 	err = os_set_exec_close(fds[0]);
3871da177e4SLinus Torvalds 	if (err < 0)
3881da177e4SLinus Torvalds 		goto error;
3891da177e4SLinus Torvalds 
390512b6fb1SJeff Dike 	err = os_set_exec_close(fds[1]);
3911da177e4SLinus Torvalds 	if (err < 0)
3921da177e4SLinus Torvalds 		goto error;
3931da177e4SLinus Torvalds 
394108ffa8cSJeff Dike 	return 0;
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds  error:
3971adfd609SJeff Dike 	printk(UM_KERN_ERR "os_pipe : Setting FD_CLOEXEC failed, err = %d\n",
3981adfd609SJeff Dike 	       -err);
399512b6fb1SJeff Dike 	close(fds[1]);
400512b6fb1SJeff Dike 	close(fds[0]);
401512b6fb1SJeff Dike 	return err;
4021da177e4SLinus Torvalds }
4031da177e4SLinus Torvalds 
os_set_fd_async(int fd)404bf8fde78SJeff Dike int os_set_fd_async(int fd)
4051da177e4SLinus Torvalds {
406bf8fde78SJeff Dike 	int err, flags;
407b4fd310eSJeff Dike 
408bf8fde78SJeff Dike 	flags = fcntl(fd, F_GETFL);
409bf8fde78SJeff Dike 	if (flags < 0)
410bf8fde78SJeff Dike 		return -errno;
411bf8fde78SJeff Dike 
412bf8fde78SJeff Dike 	flags |= O_ASYNC | O_NONBLOCK;
413bf8fde78SJeff Dike 	if (fcntl(fd, F_SETFL, flags) < 0) {
414b4fd310eSJeff Dike 		err = -errno;
4151adfd609SJeff Dike 		printk(UM_KERN_ERR "os_set_fd_async : failed to set O_ASYNC "
4161adfd609SJeff Dike 		       "and O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
417b4fd310eSJeff Dike 		return err;
4181da177e4SLinus Torvalds 	}
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	if ((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
421bf8fde78SJeff Dike 	    (fcntl(fd, F_SETOWN, os_getpid()) < 0)) {
422b4fd310eSJeff Dike 		err = -errno;
4231adfd609SJeff Dike 		printk(UM_KERN_ERR "os_set_fd_async : Failed to fcntl F_SETOWN "
424bf8fde78SJeff Dike 		       "(or F_SETSIG) fd %d, errno = %d\n", fd, errno);
425b4fd310eSJeff Dike 		return err;
4261da177e4SLinus Torvalds 	}
4271da177e4SLinus Torvalds 
428108ffa8cSJeff Dike 	return 0;
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds 
os_clear_fd_async(int fd)4311da177e4SLinus Torvalds int os_clear_fd_async(int fd)
4321da177e4SLinus Torvalds {
4331adfd609SJeff Dike 	int flags;
4341adfd609SJeff Dike 
4351adfd609SJeff Dike 	flags = fcntl(fd, F_GETFL);
4361adfd609SJeff Dike 	if (flags < 0)
4371adfd609SJeff Dike 		return -errno;
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 	flags &= ~(O_ASYNC | O_NONBLOCK);
4401da177e4SLinus Torvalds 	if (fcntl(fd, F_SETFL, flags) < 0)
441108ffa8cSJeff Dike 		return -errno;
442108ffa8cSJeff Dike 	return 0;
4431da177e4SLinus Torvalds }
4441da177e4SLinus Torvalds 
os_set_fd_block(int fd,int blocking)4451da177e4SLinus Torvalds int os_set_fd_block(int fd, int blocking)
4461da177e4SLinus Torvalds {
4471da177e4SLinus Torvalds 	int flags;
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds 	flags = fcntl(fd, F_GETFL);
4501adfd609SJeff Dike 	if (flags < 0)
4511adfd609SJeff Dike 		return -errno;
4521da177e4SLinus Torvalds 
4531adfd609SJeff Dike 	if (blocking)
4541adfd609SJeff Dike 		flags &= ~O_NONBLOCK;
4551adfd609SJeff Dike 	else
4561adfd609SJeff Dike 		flags |= O_NONBLOCK;
4571da177e4SLinus Torvalds 
458b4fd310eSJeff Dike 	if (fcntl(fd, F_SETFL, flags) < 0)
459b4fd310eSJeff Dike 		return -errno;
460b4fd310eSJeff Dike 
461108ffa8cSJeff Dike 	return 0;
4621da177e4SLinus Torvalds }
4631da177e4SLinus Torvalds 
os_accept_connection(int fd)4641da177e4SLinus Torvalds int os_accept_connection(int fd)
4651da177e4SLinus Torvalds {
4661da177e4SLinus Torvalds 	int new;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	new = accept(fd, NULL, 0);
4691da177e4SLinus Torvalds 	if (new < 0)
470108ffa8cSJeff Dike 		return -errno;
471108ffa8cSJeff Dike 	return new;
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds #ifndef SHUT_RD
4751da177e4SLinus Torvalds #define SHUT_RD 0
4761da177e4SLinus Torvalds #endif
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds #ifndef SHUT_WR
4791da177e4SLinus Torvalds #define SHUT_WR 1
4801da177e4SLinus Torvalds #endif
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds #ifndef SHUT_RDWR
4831da177e4SLinus Torvalds #define SHUT_RDWR 2
4841da177e4SLinus Torvalds #endif
4851da177e4SLinus Torvalds 
os_shutdown_socket(int fd,int r,int w)4861da177e4SLinus Torvalds int os_shutdown_socket(int fd, int r, int w)
4871da177e4SLinus Torvalds {
4881da177e4SLinus Torvalds 	int what, err;
4891da177e4SLinus Torvalds 
4901adfd609SJeff Dike 	if (r && w)
4911adfd609SJeff Dike 		what = SHUT_RDWR;
4921adfd609SJeff Dike 	else if (r)
4931adfd609SJeff Dike 		what = SHUT_RD;
4941adfd609SJeff Dike 	else if (w)
4951adfd609SJeff Dike 		what = SHUT_WR;
4961adfd609SJeff Dike 	else
497108ffa8cSJeff Dike 		return -EINVAL;
4981adfd609SJeff Dike 
4991da177e4SLinus Torvalds 	err = shutdown(fd, what);
5001da177e4SLinus Torvalds 	if (err < 0)
501108ffa8cSJeff Dike 		return -errno;
502108ffa8cSJeff Dike 	return 0;
5031da177e4SLinus Torvalds }
5041da177e4SLinus Torvalds 
os_rcv_fd(int fd,int * helper_pid_out)5051da177e4SLinus Torvalds int os_rcv_fd(int fd, int *helper_pid_out)
5061da177e4SLinus Torvalds {
5071da177e4SLinus Torvalds 	int new, n;
5081da177e4SLinus Torvalds 	char buf[CMSG_SPACE(sizeof(new))];
5091da177e4SLinus Torvalds 	struct msghdr msg;
5101da177e4SLinus Torvalds 	struct cmsghdr *cmsg;
5111da177e4SLinus Torvalds 	struct iovec iov;
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 	msg.msg_name = NULL;
5141da177e4SLinus Torvalds 	msg.msg_namelen = 0;
5151da177e4SLinus Torvalds 	iov = ((struct iovec) { .iov_base  = helper_pid_out,
5161da177e4SLinus Torvalds 				.iov_len   = sizeof(*helper_pid_out) });
5171da177e4SLinus Torvalds 	msg.msg_iov = &iov;
5181da177e4SLinus Torvalds 	msg.msg_iovlen = 1;
5191da177e4SLinus Torvalds 	msg.msg_control = buf;
5201da177e4SLinus Torvalds 	msg.msg_controllen = sizeof(buf);
5211da177e4SLinus Torvalds 	msg.msg_flags = 0;
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 	n = recvmsg(fd, &msg, 0);
5241da177e4SLinus Torvalds 	if (n < 0)
525108ffa8cSJeff Dike 		return -errno;
526d4d5d205SJeff Dike 	else if (n != iov.iov_len)
5271da177e4SLinus Torvalds 		*helper_pid_out = -1;
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 	cmsg = CMSG_FIRSTHDR(&msg);
5301da177e4SLinus Torvalds 	if (cmsg == NULL) {
5311adfd609SJeff Dike 		printk(UM_KERN_ERR "rcv_fd didn't receive anything, "
5321adfd609SJeff Dike 		       "error = %d\n", errno);
533108ffa8cSJeff Dike 		return -1;
5341da177e4SLinus Torvalds 	}
5351da177e4SLinus Torvalds 	if ((cmsg->cmsg_level != SOL_SOCKET) ||
5361da177e4SLinus Torvalds 	    (cmsg->cmsg_type != SCM_RIGHTS)) {
5371adfd609SJeff Dike 		printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n");
538108ffa8cSJeff Dike 		return -1;
5391da177e4SLinus Torvalds 	}
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 	new = ((int *) CMSG_DATA(cmsg))[0];
542108ffa8cSJeff Dike 	return new;
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds 
os_create_unix_socket(const char * file,int len,int close_on_exec)545c9a3072dSWANG Cong int os_create_unix_socket(const char *file, int len, int close_on_exec)
5461da177e4SLinus Torvalds {
5471da177e4SLinus Torvalds 	struct sockaddr_un addr;
5481da177e4SLinus Torvalds 	int sock, err;
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
551b4fd310eSJeff Dike 	if (sock < 0)
552b4fd310eSJeff Dike 		return -errno;
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds 	if (close_on_exec) {
555512b6fb1SJeff Dike 		err = os_set_exec_close(sock);
5561da177e4SLinus Torvalds 		if (err < 0)
5571adfd609SJeff Dike 			printk(UM_KERN_ERR "create_unix_socket : "
5581adfd609SJeff Dike 			       "close_on_exec failed, err = %d", -err);
5591da177e4SLinus Torvalds 	}
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds 	addr.sun_family = AF_UNIX;
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 	snprintf(addr.sun_path, len, "%s", file);
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds 	err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
566b4fd310eSJeff Dike 	if (err < 0)
567b4fd310eSJeff Dike 		return -errno;
5681da177e4SLinus Torvalds 
569108ffa8cSJeff Dike 	return sock;
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds 
os_flush_stdout(void)5721da177e4SLinus Torvalds void os_flush_stdout(void)
5731da177e4SLinus Torvalds {
5741da177e4SLinus Torvalds 	fflush(stdout);
5751da177e4SLinus Torvalds }
5761da177e4SLinus Torvalds 
os_lock_file(int fd,int excl)5771da177e4SLinus Torvalds int os_lock_file(int fd, int excl)
5781da177e4SLinus Torvalds {
5791da177e4SLinus Torvalds 	int type = excl ? F_WRLCK : F_RDLCK;
5801da177e4SLinus Torvalds 	struct flock lock = ((struct flock) { .l_type	= type,
5811da177e4SLinus Torvalds 					      .l_whence	= SEEK_SET,
5821da177e4SLinus Torvalds 					      .l_start	= 0,
5831da177e4SLinus Torvalds 					      .l_len	= 0 } );
5841da177e4SLinus Torvalds 	int err, save;
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds 	err = fcntl(fd, F_SETLK, &lock);
5871da177e4SLinus Torvalds 	if (!err)
5881da177e4SLinus Torvalds 		goto out;
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 	save = -errno;
5911da177e4SLinus Torvalds 	err = fcntl(fd, F_GETLK, &lock);
5921da177e4SLinus Torvalds 	if (err) {
5931da177e4SLinus Torvalds 		err = -errno;
5941da177e4SLinus Torvalds 		goto out;
5951da177e4SLinus Torvalds 	}
5961da177e4SLinus Torvalds 
5971adfd609SJeff Dike 	printk(UM_KERN_ERR "F_SETLK failed, file already locked by pid %d\n",
5981adfd609SJeff Dike 	       lock.l_pid);
5991da177e4SLinus Torvalds 	err = save;
6001da177e4SLinus Torvalds  out:
601108ffa8cSJeff Dike 	return err;
6021da177e4SLinus Torvalds }
603005a59ecSAl Viro 
os_major(unsigned long long dev)604005a59ecSAl Viro unsigned os_major(unsigned long long dev)
605005a59ecSAl Viro {
606005a59ecSAl Viro 	return major(dev);
607005a59ecSAl Viro }
608005a59ecSAl Viro 
os_minor(unsigned long long dev)609005a59ecSAl Viro unsigned os_minor(unsigned long long dev)
610005a59ecSAl Viro {
611005a59ecSAl Viro 	return minor(dev);
612005a59ecSAl Viro }
613005a59ecSAl Viro 
os_makedev(unsigned major,unsigned minor)614005a59ecSAl Viro unsigned long long os_makedev(unsigned major, unsigned minor)
615005a59ecSAl Viro {
616005a59ecSAl Viro 	return makedev(major, minor);
617005a59ecSAl Viro }
61850109b5aSAnton Ivanov 
os_falloc_punch(int fd,unsigned long long offset,int len)61950109b5aSAnton Ivanov int os_falloc_punch(int fd, unsigned long long offset, int len)
62050109b5aSAnton Ivanov {
62150109b5aSAnton Ivanov 	int n = fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, offset, len);
62250109b5aSAnton Ivanov 
62350109b5aSAnton Ivanov 	if (n < 0)
62450109b5aSAnton Ivanov 		return -errno;
62550109b5aSAnton Ivanov 	return n;
62650109b5aSAnton Ivanov }
62750109b5aSAnton Ivanov 
os_falloc_zeroes(int fd,unsigned long long offset,int len)628*d2a0a616SFrédéric Danis int os_falloc_zeroes(int fd, unsigned long long offset, int len)
629*d2a0a616SFrédéric Danis {
630*d2a0a616SFrédéric Danis 	int n = fallocate(fd, FALLOC_FL_ZERO_RANGE|FALLOC_FL_KEEP_SIZE, offset, len);
631*d2a0a616SFrédéric Danis 
632*d2a0a616SFrédéric Danis 	if (n < 0)
633*d2a0a616SFrédéric Danis 		return -errno;
634*d2a0a616SFrédéric Danis 	return n;
635*d2a0a616SFrédéric Danis }
636*d2a0a616SFrédéric Danis 
os_eventfd(unsigned int initval,int flags)6375d38f324SErel Geron int os_eventfd(unsigned int initval, int flags)
6385d38f324SErel Geron {
6395d38f324SErel Geron 	int fd = eventfd(initval, flags);
6405d38f324SErel Geron 
6415d38f324SErel Geron 	if (fd < 0)
6425d38f324SErel Geron 		return -errno;
6435d38f324SErel Geron 	return fd;
6445d38f324SErel Geron }
6455d38f324SErel Geron 
os_sendmsg_fds(int fd,const void * buf,unsigned int len,const int * fds,unsigned int fds_num)6465d38f324SErel Geron int os_sendmsg_fds(int fd, const void *buf, unsigned int len, const int *fds,
6475d38f324SErel Geron 		   unsigned int fds_num)
6485d38f324SErel Geron {
6495d38f324SErel Geron 	struct iovec iov = {
6505d38f324SErel Geron 		.iov_base = (void *) buf,
6515d38f324SErel Geron 		.iov_len = len,
6525d38f324SErel Geron 	};
6535d38f324SErel Geron 	union {
6545d38f324SErel Geron 		char control[CMSG_SPACE(sizeof(*fds) * OS_SENDMSG_MAX_FDS)];
6555d38f324SErel Geron 		struct cmsghdr align;
6565d38f324SErel Geron 	} u;
6575d38f324SErel Geron 	unsigned int fds_size = sizeof(*fds) * fds_num;
6585d38f324SErel Geron 	struct msghdr msg = {
6595d38f324SErel Geron 		.msg_iov = &iov,
6605d38f324SErel Geron 		.msg_iovlen = 1,
6615d38f324SErel Geron 		.msg_control = u.control,
6625d38f324SErel Geron 		.msg_controllen = CMSG_SPACE(fds_size),
6635d38f324SErel Geron 	};
6645d38f324SErel Geron 	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
6655d38f324SErel Geron 	int err;
6665d38f324SErel Geron 
6675d38f324SErel Geron 	if (fds_num > OS_SENDMSG_MAX_FDS)
6685d38f324SErel Geron 		return -EINVAL;
6695d38f324SErel Geron 	memset(u.control, 0, sizeof(u.control));
6705d38f324SErel Geron 	cmsg->cmsg_level = SOL_SOCKET;
6715d38f324SErel Geron 	cmsg->cmsg_type = SCM_RIGHTS;
6725d38f324SErel Geron 	cmsg->cmsg_len = CMSG_LEN(fds_size);
6735d38f324SErel Geron 	memcpy(CMSG_DATA(cmsg), fds, fds_size);
6745d38f324SErel Geron 	err = sendmsg(fd, &msg, 0);
6755d38f324SErel Geron 
6765d38f324SErel Geron 	if (err < 0)
6775d38f324SErel Geron 		return -errno;
6785d38f324SErel Geron 	return err;
6795d38f324SErel Geron }
68088ce6424SJohannes Berg 
os_poll(unsigned int n,const int * fds)68188ce6424SJohannes Berg int os_poll(unsigned int n, const int *fds)
68288ce6424SJohannes Berg {
68388ce6424SJohannes Berg 	/* currently need 2 FDs at most so avoid dynamic allocation */
68488ce6424SJohannes Berg 	struct pollfd pollfds[2] = {};
68588ce6424SJohannes Berg 	unsigned int i;
68688ce6424SJohannes Berg 	int ret;
68788ce6424SJohannes Berg 
68888ce6424SJohannes Berg 	if (n > ARRAY_SIZE(pollfds))
68988ce6424SJohannes Berg 		return -EINVAL;
69088ce6424SJohannes Berg 
69188ce6424SJohannes Berg 	for (i = 0; i < n; i++) {
69288ce6424SJohannes Berg 		pollfds[i].fd = fds[i];
69388ce6424SJohannes Berg 		pollfds[i].events = POLLIN;
69488ce6424SJohannes Berg 	}
69588ce6424SJohannes Berg 
69688ce6424SJohannes Berg 	ret = poll(pollfds, n, -1);
69788ce6424SJohannes Berg 	if (ret < 0)
69888ce6424SJohannes Berg 		return -errno;
69988ce6424SJohannes Berg 
70088ce6424SJohannes Berg 	/* Return the index of the available FD */
70188ce6424SJohannes Berg 	for (i = 0; i < n; i++) {
70288ce6424SJohannes Berg 		if (pollfds[i].revents)
70388ce6424SJohannes Berg 			return i;
70488ce6424SJohannes Berg 	}
70588ce6424SJohannes Berg 
70688ce6424SJohannes Berg 	return -EIO;
70788ce6424SJohannes Berg }
708