1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4   */
5  
6  #include <stdio.h>
7  #include <unistd.h>
8  #include <errno.h>
9  #include <fcntl.h>
10  #include <signal.h>
11  #include <sys/ioctl.h>
12  #include <sys/mount.h>
13  #include <sys/socket.h>
14  #include <sys/stat.h>
15  #include <sys/sysmacros.h>
16  #include <sys/un.h>
17  #include <sys/types.h>
18  #include <sys/eventfd.h>
19  #include <os.h>
20  
copy_stat(struct uml_stat * dst,const struct stat64 * src)21  static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
22  {
23  	*dst = ((struct uml_stat) {
24  		.ust_dev     = src->st_dev,     /* device */
25  		.ust_ino     = src->st_ino,     /* inode */
26  		.ust_mode    = src->st_mode,    /* protection */
27  		.ust_nlink   = src->st_nlink,   /* number of hard links */
28  		.ust_uid     = src->st_uid,     /* user ID of owner */
29  		.ust_gid     = src->st_gid,     /* group ID of owner */
30  		.ust_size    = src->st_size,    /* total size, in bytes */
31  		.ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
32  		.ust_blocks  = src->st_blocks,  /* number of blocks allocated */
33  		.ust_atime   = src->st_atime,   /* time of last access */
34  		.ust_mtime   = src->st_mtime,   /* time of last modification */
35  		.ust_ctime   = src->st_ctime,   /* time of last change */
36  	});
37  }
38  
os_stat_fd(const int fd,struct uml_stat * ubuf)39  int os_stat_fd(const int fd, struct uml_stat *ubuf)
40  {
41  	struct stat64 sbuf;
42  	int err;
43  
44  	CATCH_EINTR(err = fstat64(fd, &sbuf));
45  	if (err < 0)
46  		return -errno;
47  
48  	if (ubuf != NULL)
49  		copy_stat(ubuf, &sbuf);
50  	return err;
51  }
52  
os_stat_file(const char * file_name,struct uml_stat * ubuf)53  int os_stat_file(const char *file_name, struct uml_stat *ubuf)
54  {
55  	struct stat64 sbuf;
56  	int err;
57  
58  	CATCH_EINTR(err = stat64(file_name, &sbuf));
59  	if (err < 0)
60  		return -errno;
61  
62  	if (ubuf != NULL)
63  		copy_stat(ubuf, &sbuf);
64  	return err;
65  }
66  
os_access(const char * file,int mode)67  int os_access(const char *file, int mode)
68  {
69  	int amode, err;
70  
71  	amode = (mode & OS_ACC_R_OK ? R_OK : 0) |
72  		(mode & OS_ACC_W_OK ? W_OK : 0) |
73  		(mode & OS_ACC_X_OK ? X_OK : 0) |
74  		(mode & OS_ACC_F_OK ? F_OK : 0);
75  
76  	err = access(file, amode);
77  	if (err < 0)
78  		return -errno;
79  
80  	return 0;
81  }
82  
83  /* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
os_ioctl_generic(int fd,unsigned int cmd,unsigned long arg)84  int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
85  {
86  	int err;
87  
88  	err = ioctl(fd, cmd, arg);
89  	if (err < 0)
90  		return -errno;
91  
92  	return err;
93  }
94  
95  /* FIXME: ensure namebuf in os_get_if_name is big enough */
os_get_ifname(int fd,char * namebuf)96  int os_get_ifname(int fd, char* namebuf)
97  {
98  	if (ioctl(fd, SIOCGIFNAME, namebuf) < 0)
99  		return -errno;
100  
101  	return 0;
102  }
103  
os_set_slip(int fd)104  int os_set_slip(int fd)
105  {
106  	int disc, sencap;
107  
108  	disc = N_SLIP;
109  	if (ioctl(fd, TIOCSETD, &disc) < 0)
110  		return -errno;
111  
112  	sencap = 0;
113  	if (ioctl(fd, SIOCSIFENCAP, &sencap) < 0)
114  		return -errno;
115  
116  	return 0;
117  }
118  
os_mode_fd(int fd,int mode)119  int os_mode_fd(int fd, int mode)
120  {
121  	int err;
122  
123  	CATCH_EINTR(err = fchmod(fd, mode));
124  	if (err < 0)
125  		return -errno;
126  
127  	return 0;
128  }
129  
os_file_type(char * file)130  int os_file_type(char *file)
131  {
132  	struct uml_stat buf;
133  	int err;
134  
135  	err = os_stat_file(file, &buf);
136  	if (err < 0)
137  		return err;
138  
139  	if (S_ISDIR(buf.ust_mode))
140  		return OS_TYPE_DIR;
141  	else if (S_ISLNK(buf.ust_mode))
142  		return OS_TYPE_SYMLINK;
143  	else if (S_ISCHR(buf.ust_mode))
144  		return OS_TYPE_CHARDEV;
145  	else if (S_ISBLK(buf.ust_mode))
146  		return OS_TYPE_BLOCKDEV;
147  	else if (S_ISFIFO(buf.ust_mode))
148  		return OS_TYPE_FIFO;
149  	else if (S_ISSOCK(buf.ust_mode))
150  		return OS_TYPE_SOCK;
151  	else return OS_TYPE_FILE;
152  }
153  
os_file_mode(const char * file,struct openflags * mode_out)154  int os_file_mode(const char *file, struct openflags *mode_out)
155  {
156  	int err;
157  
158  	*mode_out = OPENFLAGS();
159  
160  	err = access(file, W_OK);
161  	if (err && (errno != EACCES))
162  		return -errno;
163  	else if (!err)
164  		*mode_out = of_write(*mode_out);
165  
166  	err = access(file, R_OK);
167  	if (err && (errno != EACCES))
168  		return -errno;
169  	else if (!err)
170  		*mode_out = of_read(*mode_out);
171  
172  	return err;
173  }
174  
os_open_file(const char * file,struct openflags flags,int mode)175  int os_open_file(const char *file, struct openflags flags, int mode)
176  {
177  	int fd, err, f = 0;
178  
179  	if (flags.r && flags.w)
180  		f = O_RDWR;
181  	else if (flags.r)
182  		f = O_RDONLY;
183  	else if (flags.w)
184  		f = O_WRONLY;
185  	else f = 0;
186  
187  	if (flags.s)
188  		f |= O_SYNC;
189  	if (flags.c)
190  		f |= O_CREAT;
191  	if (flags.t)
192  		f |= O_TRUNC;
193  	if (flags.e)
194  		f |= O_EXCL;
195  	if (flags.a)
196  		f |= O_APPEND;
197  
198  	fd = open64(file, f, mode);
199  	if (fd < 0)
200  		return -errno;
201  
202  	if (flags.cl && fcntl(fd, F_SETFD, 1)) {
203  		err = -errno;
204  		close(fd);
205  		return err;
206  	}
207  
208  	return fd;
209  }
210  
os_connect_socket(const char * name)211  int os_connect_socket(const char *name)
212  {
213  	struct sockaddr_un sock;
214  	int fd, err;
215  
216  	sock.sun_family = AF_UNIX;
217  	snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
218  
219  	fd = socket(AF_UNIX, SOCK_STREAM, 0);
220  	if (fd < 0) {
221  		err = -errno;
222  		goto out;
223  	}
224  
225  	err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
226  	if (err) {
227  		err = -errno;
228  		goto out_close;
229  	}
230  
231  	return fd;
232  
233  out_close:
234  	close(fd);
235  out:
236  	return err;
237  }
238  
os_close_file(int fd)239  void os_close_file(int fd)
240  {
241  	close(fd);
242  }
os_fsync_file(int fd)243  int os_fsync_file(int fd)
244  {
245  	if (fsync(fd) < 0)
246  	    return -errno;
247  	return 0;
248  }
249  
os_seek_file(int fd,unsigned long long offset)250  int os_seek_file(int fd, unsigned long long offset)
251  {
252  	unsigned long long actual;
253  
254  	actual = lseek64(fd, offset, SEEK_SET);
255  	if (actual != offset)
256  		return -errno;
257  	return 0;
258  }
259  
os_read_file(int fd,void * buf,int len)260  int os_read_file(int fd, void *buf, int len)
261  {
262  	int n = read(fd, buf, len);
263  
264  	if (n < 0)
265  		return -errno;
266  	return n;
267  }
268  
os_pread_file(int fd,void * buf,int len,unsigned long long offset)269  int os_pread_file(int fd, void *buf, int len, unsigned long long offset)
270  {
271  	int n = pread(fd, buf, len, offset);
272  
273  	if (n < 0)
274  		return -errno;
275  	return n;
276  }
277  
os_write_file(int fd,const void * buf,int len)278  int os_write_file(int fd, const void *buf, int len)
279  {
280  	int n = write(fd, (void *) buf, len);
281  
282  	if (n < 0)
283  		return -errno;
284  	return n;
285  }
286  
os_sync_file(int fd)287  int os_sync_file(int fd)
288  {
289  	int n = fsync(fd);
290  
291  	if (n < 0)
292  		return -errno;
293  	return n;
294  }
295  
os_pwrite_file(int fd,const void * buf,int len,unsigned long long offset)296  int os_pwrite_file(int fd, const void *buf, int len, unsigned long long offset)
297  {
298  	int n = pwrite(fd, (void *) buf, len, offset);
299  
300  	if (n < 0)
301  		return -errno;
302  	return n;
303  }
304  
305  
os_file_size(const char * file,unsigned long long * size_out)306  int os_file_size(const char *file, unsigned long long *size_out)
307  {
308  	struct uml_stat buf;
309  	int err;
310  
311  	err = os_stat_file(file, &buf);
312  	if (err < 0) {
313  		printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
314  		       -err);
315  		return err;
316  	}
317  
318  	if (S_ISBLK(buf.ust_mode)) {
319  		int fd;
320  		long blocks;
321  
322  		fd = open(file, O_RDONLY, 0);
323  		if (fd < 0) {
324  			err = -errno;
325  			printk(UM_KERN_ERR "Couldn't open \"%s\", "
326  			       "errno = %d\n", file, errno);
327  			return err;
328  		}
329  		if (ioctl(fd, BLKGETSIZE, &blocks) < 0) {
330  			err = -errno;
331  			printk(UM_KERN_ERR "Couldn't get the block size of "
332  			       "\"%s\", errno = %d\n", file, errno);
333  			close(fd);
334  			return err;
335  		}
336  		*size_out = ((long long) blocks) * 512;
337  		close(fd);
338  	}
339  	else *size_out = buf.ust_size;
340  
341  	return 0;
342  }
343  
os_file_modtime(const char * file,unsigned long * modtime)344  int os_file_modtime(const char *file, unsigned long *modtime)
345  {
346  	struct uml_stat buf;
347  	int err;
348  
349  	err = os_stat_file(file, &buf);
350  	if (err < 0) {
351  		printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
352  		       -err);
353  		return err;
354  	}
355  
356  	*modtime = buf.ust_mtime;
357  	return 0;
358  }
359  
os_set_exec_close(int fd)360  int os_set_exec_close(int fd)
361  {
362  	int err;
363  
364  	CATCH_EINTR(err = fcntl(fd, F_SETFD, FD_CLOEXEC));
365  
366  	if (err < 0)
367  		return -errno;
368  	return err;
369  }
370  
os_pipe(int * fds,int stream,int close_on_exec)371  int os_pipe(int *fds, int stream, int close_on_exec)
372  {
373  	int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
374  
375  	err = socketpair(AF_UNIX, type, 0, fds);
376  	if (err < 0)
377  		return -errno;
378  
379  	if (!close_on_exec)
380  		return 0;
381  
382  	err = os_set_exec_close(fds[0]);
383  	if (err < 0)
384  		goto error;
385  
386  	err = os_set_exec_close(fds[1]);
387  	if (err < 0)
388  		goto error;
389  
390  	return 0;
391  
392   error:
393  	printk(UM_KERN_ERR "os_pipe : Setting FD_CLOEXEC failed, err = %d\n",
394  	       -err);
395  	close(fds[1]);
396  	close(fds[0]);
397  	return err;
398  }
399  
os_set_fd_async(int fd)400  int os_set_fd_async(int fd)
401  {
402  	int err, flags;
403  
404  	flags = fcntl(fd, F_GETFL);
405  	if (flags < 0)
406  		return -errno;
407  
408  	flags |= O_ASYNC | O_NONBLOCK;
409  	if (fcntl(fd, F_SETFL, flags) < 0) {
410  		err = -errno;
411  		printk(UM_KERN_ERR "os_set_fd_async : failed to set O_ASYNC "
412  		       "and O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
413  		return err;
414  	}
415  
416  	if ((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
417  	    (fcntl(fd, F_SETOWN, os_getpid()) < 0)) {
418  		err = -errno;
419  		printk(UM_KERN_ERR "os_set_fd_async : Failed to fcntl F_SETOWN "
420  		       "(or F_SETSIG) fd %d, errno = %d\n", fd, errno);
421  		return err;
422  	}
423  
424  	return 0;
425  }
426  
os_clear_fd_async(int fd)427  int os_clear_fd_async(int fd)
428  {
429  	int flags;
430  
431  	flags = fcntl(fd, F_GETFL);
432  	if (flags < 0)
433  		return -errno;
434  
435  	flags &= ~(O_ASYNC | O_NONBLOCK);
436  	if (fcntl(fd, F_SETFL, flags) < 0)
437  		return -errno;
438  	return 0;
439  }
440  
os_set_fd_block(int fd,int blocking)441  int os_set_fd_block(int fd, int blocking)
442  {
443  	int flags;
444  
445  	flags = fcntl(fd, F_GETFL);
446  	if (flags < 0)
447  		return -errno;
448  
449  	if (blocking)
450  		flags &= ~O_NONBLOCK;
451  	else
452  		flags |= O_NONBLOCK;
453  
454  	if (fcntl(fd, F_SETFL, flags) < 0)
455  		return -errno;
456  
457  	return 0;
458  }
459  
os_accept_connection(int fd)460  int os_accept_connection(int fd)
461  {
462  	int new;
463  
464  	new = accept(fd, NULL, 0);
465  	if (new < 0)
466  		return -errno;
467  	return new;
468  }
469  
470  #ifndef SHUT_RD
471  #define SHUT_RD 0
472  #endif
473  
474  #ifndef SHUT_WR
475  #define SHUT_WR 1
476  #endif
477  
478  #ifndef SHUT_RDWR
479  #define SHUT_RDWR 2
480  #endif
481  
os_shutdown_socket(int fd,int r,int w)482  int os_shutdown_socket(int fd, int r, int w)
483  {
484  	int what, err;
485  
486  	if (r && w)
487  		what = SHUT_RDWR;
488  	else if (r)
489  		what = SHUT_RD;
490  	else if (w)
491  		what = SHUT_WR;
492  	else
493  		return -EINVAL;
494  
495  	err = shutdown(fd, what);
496  	if (err < 0)
497  		return -errno;
498  	return 0;
499  }
500  
os_rcv_fd(int fd,int * helper_pid_out)501  int os_rcv_fd(int fd, int *helper_pid_out)
502  {
503  	int new, n;
504  	char buf[CMSG_SPACE(sizeof(new))];
505  	struct msghdr msg;
506  	struct cmsghdr *cmsg;
507  	struct iovec iov;
508  
509  	msg.msg_name = NULL;
510  	msg.msg_namelen = 0;
511  	iov = ((struct iovec) { .iov_base  = helper_pid_out,
512  				.iov_len   = sizeof(*helper_pid_out) });
513  	msg.msg_iov = &iov;
514  	msg.msg_iovlen = 1;
515  	msg.msg_control = buf;
516  	msg.msg_controllen = sizeof(buf);
517  	msg.msg_flags = 0;
518  
519  	n = recvmsg(fd, &msg, 0);
520  	if (n < 0)
521  		return -errno;
522  	else if (n != iov.iov_len)
523  		*helper_pid_out = -1;
524  
525  	cmsg = CMSG_FIRSTHDR(&msg);
526  	if (cmsg == NULL) {
527  		printk(UM_KERN_ERR "rcv_fd didn't receive anything, "
528  		       "error = %d\n", errno);
529  		return -1;
530  	}
531  	if ((cmsg->cmsg_level != SOL_SOCKET) ||
532  	    (cmsg->cmsg_type != SCM_RIGHTS)) {
533  		printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n");
534  		return -1;
535  	}
536  
537  	new = ((int *) CMSG_DATA(cmsg))[0];
538  	return new;
539  }
540  
os_create_unix_socket(const char * file,int len,int close_on_exec)541  int os_create_unix_socket(const char *file, int len, int close_on_exec)
542  {
543  	struct sockaddr_un addr;
544  	int sock, err;
545  
546  	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
547  	if (sock < 0)
548  		return -errno;
549  
550  	if (close_on_exec) {
551  		err = os_set_exec_close(sock);
552  		if (err < 0)
553  			printk(UM_KERN_ERR "create_unix_socket : "
554  			       "close_on_exec failed, err = %d", -err);
555  	}
556  
557  	addr.sun_family = AF_UNIX;
558  
559  	snprintf(addr.sun_path, len, "%s", file);
560  
561  	err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
562  	if (err < 0)
563  		return -errno;
564  
565  	return sock;
566  }
567  
os_flush_stdout(void)568  void os_flush_stdout(void)
569  {
570  	fflush(stdout);
571  }
572  
os_lock_file(int fd,int excl)573  int os_lock_file(int fd, int excl)
574  {
575  	int type = excl ? F_WRLCK : F_RDLCK;
576  	struct flock lock = ((struct flock) { .l_type	= type,
577  					      .l_whence	= SEEK_SET,
578  					      .l_start	= 0,
579  					      .l_len	= 0 } );
580  	int err, save;
581  
582  	err = fcntl(fd, F_SETLK, &lock);
583  	if (!err)
584  		goto out;
585  
586  	save = -errno;
587  	err = fcntl(fd, F_GETLK, &lock);
588  	if (err) {
589  		err = -errno;
590  		goto out;
591  	}
592  
593  	printk(UM_KERN_ERR "F_SETLK failed, file already locked by pid %d\n",
594  	       lock.l_pid);
595  	err = save;
596   out:
597  	return err;
598  }
599  
os_major(unsigned long long dev)600  unsigned os_major(unsigned long long dev)
601  {
602  	return major(dev);
603  }
604  
os_minor(unsigned long long dev)605  unsigned os_minor(unsigned long long dev)
606  {
607  	return minor(dev);
608  }
609  
os_makedev(unsigned major,unsigned minor)610  unsigned long long os_makedev(unsigned major, unsigned minor)
611  {
612  	return makedev(major, minor);
613  }
614  
os_falloc_punch(int fd,unsigned long long offset,int len)615  int os_falloc_punch(int fd, unsigned long long offset, int len)
616  {
617  	int n = fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, offset, len);
618  
619  	if (n < 0)
620  		return -errno;
621  	return n;
622  }
623  
os_eventfd(unsigned int initval,int flags)624  int os_eventfd(unsigned int initval, int flags)
625  {
626  	int fd = eventfd(initval, flags);
627  
628  	if (fd < 0)
629  		return -errno;
630  	return fd;
631  }
632  
os_sendmsg_fds(int fd,const void * buf,unsigned int len,const int * fds,unsigned int fds_num)633  int os_sendmsg_fds(int fd, const void *buf, unsigned int len, const int *fds,
634  		   unsigned int fds_num)
635  {
636  	struct iovec iov = {
637  		.iov_base = (void *) buf,
638  		.iov_len = len,
639  	};
640  	union {
641  		char control[CMSG_SPACE(sizeof(*fds) * OS_SENDMSG_MAX_FDS)];
642  		struct cmsghdr align;
643  	} u;
644  	unsigned int fds_size = sizeof(*fds) * fds_num;
645  	struct msghdr msg = {
646  		.msg_iov = &iov,
647  		.msg_iovlen = 1,
648  		.msg_control = u.control,
649  		.msg_controllen = CMSG_SPACE(fds_size),
650  	};
651  	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
652  	int err;
653  
654  	if (fds_num > OS_SENDMSG_MAX_FDS)
655  		return -EINVAL;
656  	memset(u.control, 0, sizeof(u.control));
657  	cmsg->cmsg_level = SOL_SOCKET;
658  	cmsg->cmsg_type = SCM_RIGHTS;
659  	cmsg->cmsg_len = CMSG_LEN(fds_size);
660  	memcpy(CMSG_DATA(cmsg), fds, fds_size);
661  	err = sendmsg(fd, &msg, 0);
662  
663  	if (err < 0)
664  		return -errno;
665  	return err;
666  }
667