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