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