1/* $Id: sys_sunos.c,v 1.1.1.1 2007/08/03 18:52:17 Exp $ 2 * sys_sunos.c: SunOS specific syscall compatibility support. 3 * 4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 5 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) 6 * 7 * Based upon preliminary work which is: 8 * 9 * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) 10 * 11 */ 12 13#include <linux/kernel.h> 14#include <linux/sched.h> 15#include <linux/types.h> 16#include <linux/mman.h> 17#include <linux/mm.h> 18#include <linux/swap.h> 19#include <linux/fs.h> 20#include <linux/file.h> 21#include <linux/resource.h> 22#include <linux/ipc.h> 23#include <linux/shm.h> 24#include <linux/msg.h> 25#include <linux/sem.h> 26#include <linux/signal.h> 27#include <linux/uio.h> 28#include <linux/utsname.h> 29#include <linux/major.h> 30#include <linux/stat.h> 31#include <linux/slab.h> 32#include <linux/pagemap.h> 33#include <linux/capability.h> 34#include <linux/errno.h> 35#include <linux/smp.h> 36#include <linux/smp_lock.h> 37#include <linux/syscalls.h> 38 39#include <net/sock.h> 40 41#include <asm/uaccess.h> 42#ifndef KERNEL_DS 43#include <linux/segment.h> 44#endif 45 46#include <asm/page.h> 47#include <asm/pgtable.h> 48#include <asm/pconf.h> 49#include <asm/idprom.h> /* for gethostid() */ 50#include <asm/unistd.h> 51#include <asm/system.h> 52 53/* For the nfs mount emulation */ 54#include <linux/socket.h> 55#include <linux/in.h> 56#include <linux/nfs.h> 57#include <linux/nfs2.h> 58#include <linux/nfs_mount.h> 59 60/* for sunos_select */ 61#include <linux/time.h> 62#include <linux/personality.h> 63 64/* NR_OPEN is now larger and dynamic in recent kernels. */ 65#define SUNOS_NR_OPEN 256 66 67/* We use the SunOS mmap() semantics. */ 68asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, 69 unsigned long prot, unsigned long flags, 70 unsigned long fd, unsigned long off) 71{ 72 struct file * file = NULL; 73 unsigned long retval, ret_type; 74 75 if (flags & MAP_NORESERVE) { 76 static int cnt; 77 if (cnt++ < 10) 78 printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", 79 current->comm); 80 flags &= ~MAP_NORESERVE; 81 } 82 retval = -EBADF; 83 if (!(flags & MAP_ANONYMOUS)) { 84 if (fd >= SUNOS_NR_OPEN) 85 goto out; 86 file = fget(fd); 87 if (!file) 88 goto out; 89 } 90 91 retval = -EINVAL; 92 /* If this is ld.so or a shared library doing an mmap 93 * of /dev/zero, transform it into an anonymous mapping. 94 * SunOS is so stupid some times... hmph! 95 */ 96 if (file) { 97 if (imajor(file->f_path.dentry->d_inode) == MEM_MAJOR && 98 iminor(file->f_path.dentry->d_inode) == 5) { 99 flags |= MAP_ANONYMOUS; 100 fput(file); 101 file = NULL; 102 } 103 } 104 ret_type = flags & _MAP_NEW; 105 flags &= ~_MAP_NEW; 106 107 if (!(flags & MAP_FIXED)) 108 addr = 0; 109 else { 110 if (ARCH_SUN4C_SUN4 && 111 (len > 0x20000000 || 112 ((flags & MAP_FIXED) && 113 addr < 0xe0000000 && addr + len > 0x20000000))) 114 goto out_putf; 115 116 /* See asm-sparc/uaccess.h */ 117 if (len > TASK_SIZE - PAGE_SIZE || 118 addr + len > TASK_SIZE - PAGE_SIZE) 119 goto out_putf; 120 } 121 122 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 123 down_write(¤t->mm->mmap_sem); 124 retval = do_mmap(file, addr, len, prot, flags, off); 125 up_write(¤t->mm->mmap_sem); 126 if (!ret_type) 127 retval = ((retval < PAGE_OFFSET) ? 0 : retval); 128 129out_putf: 130 if (file) 131 fput(file); 132out: 133 return retval; 134} 135 136/* lmbench calls this, just say "yeah, ok" */ 137asmlinkage int sunos_mctl(unsigned long addr, unsigned long len, int function, char *arg) 138{ 139 return 0; 140} 141 142/* SunOS is completely broken... it returns 0 on success, otherwise 143 * ENOMEM. For sys_sbrk() it wants the old brk value as a return 144 * on success and ENOMEM as before on failure. 145 */ 146asmlinkage int sunos_brk(unsigned long brk) 147{ 148 int freepages, retval = -ENOMEM; 149 unsigned long rlim; 150 unsigned long newbrk, oldbrk; 151 152 down_write(¤t->mm->mmap_sem); 153 if (ARCH_SUN4C_SUN4) { 154 if (brk >= 0x20000000 && brk < 0xe0000000) { 155 goto out; 156 } 157 } 158 159 if (brk < current->mm->end_code) 160 goto out; 161 162 newbrk = PAGE_ALIGN(brk); 163 oldbrk = PAGE_ALIGN(current->mm->brk); 164 retval = 0; 165 if (oldbrk == newbrk) { 166 current->mm->brk = brk; 167 goto out; 168 } 169 170 /* 171 * Always allow shrinking brk 172 */ 173 if (brk <= current->mm->brk) { 174 current->mm->brk = brk; 175 do_munmap(current->mm, newbrk, oldbrk-newbrk); 176 goto out; 177 } 178 /* 179 * Check against rlimit and stack.. 180 */ 181 retval = -ENOMEM; 182 rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; 183 if (rlim >= RLIM_INFINITY) 184 rlim = ~0; 185 if (brk - current->mm->end_code > rlim) 186 goto out; 187 188 /* 189 * Check against existing mmap mappings. 190 */ 191 if (find_vma_intersection(current->mm, oldbrk, newbrk+PAGE_SIZE)) 192 goto out; 193 194 /* 195 * stupid algorithm to decide if we have enough memory: while 196 * simple, it hopefully works in most obvious cases.. Easy to 197 * fool it, but this should catch most mistakes. 198 */ 199 freepages = global_page_state(NR_FILE_PAGES); 200 freepages >>= 1; 201 freepages += nr_free_pages(); 202 freepages += nr_swap_pages; 203 freepages -= num_physpages >> 4; 204 freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; 205 if (freepages < 0) 206 goto out; 207 /* 208 * Ok, we have probably got enough memory - let it rip. 209 */ 210 current->mm->brk = brk; 211 do_brk(oldbrk, newbrk-oldbrk); 212 retval = 0; 213out: 214 up_write(¤t->mm->mmap_sem); 215 return retval; 216} 217 218asmlinkage unsigned long sunos_sbrk(int increment) 219{ 220 int error; 221 unsigned long oldbrk; 222 223 /* This should do it hopefully... */ 224 lock_kernel(); 225 oldbrk = current->mm->brk; 226 error = sunos_brk(((int) current->mm->brk) + increment); 227 if (!error) 228 error = oldbrk; 229 unlock_kernel(); 230 return error; 231} 232 233asmlinkage unsigned long sunos_sstk(int increment) 234{ 235 lock_kernel(); 236 printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n", 237 current->comm, increment); 238 unlock_kernel(); 239 return -1; 240} 241 242/* Give hints to the kernel as to what paging strategy to use... 243 * Completely bogus, don't remind me. 244 */ 245#define VA_NORMAL 0 /* Normal vm usage expected */ 246#define VA_ABNORMAL 1 /* Abnormal/random vm usage probable */ 247#define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */ 248#define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */ 249static char *vstrings[] = { 250 "VA_NORMAL", 251 "VA_ABNORMAL", 252 "VA_SEQUENTIAL", 253 "VA_INVALIDATE", 254}; 255 256asmlinkage void sunos_vadvise(unsigned long strategy) 257{ 258 /* I wanna see who uses this... */ 259 lock_kernel(); 260 printk("%s: Advises us to use %s paging strategy\n", 261 current->comm, 262 strategy <= 3 ? vstrings[strategy] : "BOGUS"); 263 unlock_kernel(); 264} 265 266/* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE 267 * resource limit and is for backwards compatibility with older sunos 268 * revs. 269 */ 270asmlinkage long sunos_getdtablesize(void) 271{ 272 return SUNOS_NR_OPEN; 273} 274 275#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 276 277asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask) 278{ 279 unsigned long old; 280 281 spin_lock_irq(¤t->sighand->siglock); 282 old = current->blocked.sig[0]; 283 current->blocked.sig[0] |= (blk_mask & _BLOCKABLE); 284 recalc_sigpending(); 285 spin_unlock_irq(¤t->sighand->siglock); 286 return old; 287} 288 289asmlinkage unsigned long sunos_sigsetmask(unsigned long newmask) 290{ 291 unsigned long retval; 292 293 spin_lock_irq(¤t->sighand->siglock); 294 retval = current->blocked.sig[0]; 295 current->blocked.sig[0] = (newmask & _BLOCKABLE); 296 recalc_sigpending(); 297 spin_unlock_irq(¤t->sighand->siglock); 298 return retval; 299} 300 301/* SunOS getdents is very similar to the newer Linux (iBCS2 compliant) */ 302/* getdents system call, the format of the structure just has a different */ 303/* layout (d_off+d_ino instead of d_ino+d_off) */ 304struct sunos_dirent { 305 long d_off; 306 unsigned long d_ino; 307 unsigned short d_reclen; 308 unsigned short d_namlen; 309 char d_name[1]; 310}; 311 312struct sunos_dirent_callback { 313 struct sunos_dirent __user *curr; 314 struct sunos_dirent __user *previous; 315 int count; 316 int error; 317}; 318 319#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) 320#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) 321 322static int sunos_filldir(void * __buf, const char * name, int namlen, 323 loff_t offset, u64 ino, unsigned int d_type) 324{ 325 struct sunos_dirent __user *dirent; 326 struct sunos_dirent_callback * buf = __buf; 327 unsigned long d_ino; 328 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 329 330 buf->error = -EINVAL; /* only used if we fail.. */ 331 if (reclen > buf->count) 332 return -EINVAL; 333 d_ino = ino; 334 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) 335 return -EOVERFLOW; 336 dirent = buf->previous; 337 if (dirent) 338 put_user(offset, &dirent->d_off); 339 dirent = buf->curr; 340 buf->previous = dirent; 341 put_user(d_ino, &dirent->d_ino); 342 put_user(namlen, &dirent->d_namlen); 343 put_user(reclen, &dirent->d_reclen); 344 copy_to_user(dirent->d_name, name, namlen); 345 put_user(0, dirent->d_name + namlen); 346 dirent = (void __user *) dirent + reclen; 347 buf->curr = dirent; 348 buf->count -= reclen; 349 return 0; 350} 351 352asmlinkage int sunos_getdents(unsigned int fd, void __user *dirent, int cnt) 353{ 354 struct file * file; 355 struct sunos_dirent __user *lastdirent; 356 struct sunos_dirent_callback buf; 357 int error = -EBADF; 358 359 if (fd >= SUNOS_NR_OPEN) 360 goto out; 361 362 file = fget(fd); 363 if (!file) 364 goto out; 365 366 error = -EINVAL; 367 if (cnt < (sizeof(struct sunos_dirent) + 255)) 368 goto out_putf; 369 370 buf.curr = (struct sunos_dirent __user *) dirent; 371 buf.previous = NULL; 372 buf.count = cnt; 373 buf.error = 0; 374 375 error = vfs_readdir(file, sunos_filldir, &buf); 376 if (error < 0) 377 goto out_putf; 378 379 lastdirent = buf.previous; 380 error = buf.error; 381 if (lastdirent) { 382 put_user(file->f_pos, &lastdirent->d_off); 383 error = cnt - buf.count; 384 } 385 386out_putf: 387 fput(file); 388out: 389 return error; 390} 391 392/* Old sunos getdirentries, severely broken compatibility stuff here. */ 393struct sunos_direntry { 394 unsigned long d_ino; 395 unsigned short d_reclen; 396 unsigned short d_namlen; 397 char d_name[1]; 398}; 399 400struct sunos_direntry_callback { 401 struct sunos_direntry __user *curr; 402 struct sunos_direntry __user *previous; 403 int count; 404 int error; 405}; 406 407static int sunos_filldirentry(void * __buf, const char * name, int namlen, 408 loff_t offset, u64 ino, unsigned int d_type) 409{ 410 struct sunos_direntry __user *dirent; 411 struct sunos_direntry_callback *buf = __buf; 412 unsigned long d_ino; 413 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 414 415 buf->error = -EINVAL; /* only used if we fail.. */ 416 if (reclen > buf->count) 417 return -EINVAL; 418 d_ino = ino; 419 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) 420 return -EOVERFLOW; 421 dirent = buf->previous; 422 dirent = buf->curr; 423 buf->previous = dirent; 424 put_user(d_ino, &dirent->d_ino); 425 put_user(namlen, &dirent->d_namlen); 426 put_user(reclen, &dirent->d_reclen); 427 copy_to_user(dirent->d_name, name, namlen); 428 put_user(0, dirent->d_name + namlen); 429 dirent = (void __user *) dirent + reclen; 430 buf->curr = dirent; 431 buf->count -= reclen; 432 return 0; 433} 434 435asmlinkage int sunos_getdirentries(unsigned int fd, void __user *dirent, 436 int cnt, unsigned int __user *basep) 437{ 438 struct file * file; 439 struct sunos_direntry __user *lastdirent; 440 struct sunos_direntry_callback buf; 441 int error = -EBADF; 442 443 if (fd >= SUNOS_NR_OPEN) 444 goto out; 445 446 file = fget(fd); 447 if (!file) 448 goto out; 449 450 error = -EINVAL; 451 if (cnt < (sizeof(struct sunos_direntry) + 255)) 452 goto out_putf; 453 454 buf.curr = (struct sunos_direntry __user *) dirent; 455 buf.previous = NULL; 456 buf.count = cnt; 457 buf.error = 0; 458 459 error = vfs_readdir(file, sunos_filldirentry, &buf); 460 if (error < 0) 461 goto out_putf; 462 463 lastdirent = buf.previous; 464 error = buf.error; 465 if (lastdirent) { 466 put_user(file->f_pos, basep); 467 error = cnt - buf.count; 468 } 469 470out_putf: 471 fput(file); 472out: 473 return error; 474} 475 476struct sunos_utsname { 477 char sname[9]; 478 char nname[9]; 479 char nnext[56]; 480 char rel[9]; 481 char ver[9]; 482 char mach[9]; 483}; 484 485asmlinkage int sunos_uname(struct sunos_utsname __user *name) 486{ 487 int ret; 488 down_read(&uts_sem); 489 ret = copy_to_user(&name->sname[0], &utsname()->sysname[0], 490 sizeof(name->sname) - 1); 491 if (!ret) { 492 ret |= __copy_to_user(&name->nname[0], &utsname()->nodename[0], 493 sizeof(name->nname) - 1); 494 ret |= __put_user('\0', &name->nname[8]); 495 ret |= __copy_to_user(&name->rel[0], &utsname()->release[0], 496 sizeof(name->rel) - 1); 497 ret |= __copy_to_user(&name->ver[0], &utsname()->version[0], 498 sizeof(name->ver) - 1); 499 ret |= __copy_to_user(&name->mach[0], &utsname()->machine[0], 500 sizeof(name->mach) - 1); 501 } 502 up_read(&uts_sem); 503 return ret ? -EFAULT : 0; 504} 505 506asmlinkage int sunos_nosys(void) 507{ 508 struct pt_regs *regs; 509 siginfo_t info; 510 static int cnt; 511 512 lock_kernel(); 513 regs = current->thread.kregs; 514 info.si_signo = SIGSYS; 515 info.si_errno = 0; 516 info.si_code = __SI_FAULT|0x100; 517 info.si_addr = (void __user *)regs->pc; 518 info.si_trapno = regs->u_regs[UREG_G1]; 519 send_sig_info(SIGSYS, &info, current); 520 if (cnt++ < 4) { 521 printk("Process makes ni_syscall number %d, register dump:\n", 522 (int) regs->u_regs[UREG_G1]); 523 show_regs(regs); 524 } 525 unlock_kernel(); 526 return -ENOSYS; 527} 528 529/* This is not a real and complete implementation yet, just to keep 530 * the easy SunOS binaries happy. 531 */ 532asmlinkage int sunos_fpathconf(int fd, int name) 533{ 534 int ret; 535 536 switch(name) { 537 case _PCONF_LINK: 538 ret = LINK_MAX; 539 break; 540 case _PCONF_CANON: 541 ret = MAX_CANON; 542 break; 543 case _PCONF_INPUT: 544 ret = MAX_INPUT; 545 break; 546 case _PCONF_NAME: 547 ret = NAME_MAX; 548 break; 549 case _PCONF_PATH: 550 ret = PATH_MAX; 551 break; 552 case _PCONF_PIPE: 553 ret = PIPE_BUF; 554 break; 555 case _PCONF_CHRESTRICT: 556 ret = 1; 557 break; 558 case _PCONF_NOTRUNC: 559 case _PCONF_VDISABLE: 560 ret = 0; 561 break; 562 default: 563 ret = -EINVAL; 564 break; 565 } 566 return ret; 567} 568 569asmlinkage int sunos_pathconf(char __user *path, int name) 570{ 571 int ret; 572 573 ret = sunos_fpathconf(0, name); 574 return ret; 575} 576 577/* SunOS mount system call emulation */ 578 579asmlinkage int sunos_select(int width, fd_set __user *inp, fd_set __user *outp, 580 fd_set __user *exp, struct timeval __user *tvp) 581{ 582 int ret; 583 584 /* SunOS binaries expect that select won't change the tvp contents */ 585 ret = sys_select (width, inp, outp, exp, tvp); 586 if (ret == -EINTR && tvp) { 587 time_t sec, usec; 588 589 __get_user(sec, &tvp->tv_sec); 590 __get_user(usec, &tvp->tv_usec); 591 592 if (sec == 0 && usec == 0) 593 ret = 0; 594 } 595 return ret; 596} 597 598asmlinkage void sunos_nop(void) 599{ 600 return; 601} 602 603/* SunOS mount/umount. */ 604#define SMNT_RDONLY 1 605#define SMNT_NOSUID 2 606#define SMNT_NEWTYPE 4 607#define SMNT_GRPID 8 608#define SMNT_REMOUNT 16 609#define SMNT_NOSUB 32 610#define SMNT_MULTI 64 611#define SMNT_SYS5 128 612 613struct sunos_fh_t { 614 char fh_data [NFS_FHSIZE]; 615}; 616 617struct sunos_nfs_mount_args { 618 struct sockaddr_in __user *addr; /* file server address */ 619 struct nfs_fh __user *fh; /* File handle to be mounted */ 620 int flags; /* flags */ 621 int wsize; /* write size in bytes */ 622 int rsize; /* read size in bytes */ 623 int timeo; /* initial timeout in .1 secs */ 624 int retrans; /* times to retry send */ 625 char __user *hostname; /* server's hostname */ 626 int acregmin; /* attr cache file min secs */ 627 int acregmax; /* attr cache file max secs */ 628 int acdirmin; /* attr cache dir min secs */ 629 int acdirmax; /* attr cache dir max secs */ 630 char __user *netname; /* server's netname */ 631}; 632 633 634/* Bind the socket on a local reserved port and connect it to the 635 * remote server. This on Linux/i386 is done by the mount program, 636 * not by the kernel. 637 */ 638static int 639sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr) 640{ 641 struct sockaddr_in local; 642 struct sockaddr_in server; 643 int try_port; 644 struct socket *socket; 645 struct inode *inode; 646 struct file *file; 647 int ret, result = 0; 648 649 file = fget(fd); 650 if (!file) 651 goto out; 652 653 inode = file->f_path.dentry->d_inode; 654 655 socket = SOCKET_I(inode); 656 local.sin_family = AF_INET; 657 local.sin_addr.s_addr = INADDR_ANY; 658 659 /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */ 660 try_port = 1024; 661 do { 662 local.sin_port = htons (--try_port); 663 ret = socket->ops->bind(socket, (struct sockaddr*)&local, 664 sizeof(local)); 665 } while (ret && try_port > (1024 / 2)); 666 667 if (ret) 668 goto out_putf; 669 670 server.sin_family = AF_INET; 671 server.sin_addr = addr->sin_addr; 672 server.sin_port = NFS_PORT; 673 674 /* Call sys_connect */ 675 ret = socket->ops->connect (socket, (struct sockaddr *) &server, 676 sizeof (server), file->f_flags); 677 if (ret >= 0) 678 result = 1; 679 680out_putf: 681 fput(file); 682out: 683 return result; 684} 685 686static int get_default (int value, int def_value) 687{ 688 if (value) 689 return value; 690 else 691 return def_value; 692} 693 694static int sunos_nfs_mount(char *dir_name, int linux_flags, void __user *data) 695{ 696 int server_fd, err; 697 char *the_name, *mount_page; 698 struct nfs_mount_data linux_nfs_mount; 699 struct sunos_nfs_mount_args sunos_mount; 700 701 /* Ok, here comes the fun part: Linux's nfs mount needs a 702 * socket connection to the server, but SunOS mount does not 703 * require this, so we use the information on the destination 704 * address to create a socket and bind it to a reserved 705 * port on this system 706 */ 707 if (copy_from_user(&sunos_mount, data, sizeof(sunos_mount))) 708 return -EFAULT; 709 710 server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); 711 if (server_fd < 0) 712 return -ENXIO; 713 714 if (copy_from_user(&linux_nfs_mount.addr,sunos_mount.addr, 715 sizeof(*sunos_mount.addr)) || 716 copy_from_user(&linux_nfs_mount.root,sunos_mount.fh, 717 sizeof(*sunos_mount.fh))) { 718 sys_close (server_fd); 719 return -EFAULT; 720 } 721 722 if (!sunos_nfs_get_server_fd (server_fd, &linux_nfs_mount.addr)){ 723 sys_close (server_fd); 724 return -ENXIO; 725 } 726 727 /* Now, bind it to a locally reserved port */ 728 linux_nfs_mount.version = NFS_MOUNT_VERSION; 729 linux_nfs_mount.flags = sunos_mount.flags; 730 linux_nfs_mount.fd = server_fd; 731 732 linux_nfs_mount.rsize = get_default (sunos_mount.rsize, 8192); 733 linux_nfs_mount.wsize = get_default (sunos_mount.wsize, 8192); 734 linux_nfs_mount.timeo = get_default (sunos_mount.timeo, 10); 735 linux_nfs_mount.retrans = sunos_mount.retrans; 736 737 linux_nfs_mount.acregmin = sunos_mount.acregmin; 738 linux_nfs_mount.acregmax = sunos_mount.acregmax; 739 linux_nfs_mount.acdirmin = sunos_mount.acdirmin; 740 linux_nfs_mount.acdirmax = sunos_mount.acdirmax; 741 742 the_name = getname(sunos_mount.hostname); 743 if (IS_ERR(the_name)) 744 return PTR_ERR(the_name); 745 746 strlcpy(linux_nfs_mount.hostname, the_name, 747 sizeof(linux_nfs_mount.hostname)); 748 putname (the_name); 749 750 mount_page = (char *) get_zeroed_page(GFP_KERNEL); 751 if (!mount_page) 752 return -ENOMEM; 753 754 memcpy(mount_page, &linux_nfs_mount, sizeof(linux_nfs_mount)); 755 756 err = do_mount("", dir_name, "nfs", linux_flags, mount_page); 757 758 free_page((unsigned long) mount_page); 759 return err; 760} 761 762asmlinkage int 763sunos_mount(char __user *type, char __user *dir, int flags, void __user *data) 764{ 765 int linux_flags = 0; 766 int ret = -EINVAL; 767 char *dev_fname = NULL; 768 char *dir_page, *type_page; 769 770 if (!capable (CAP_SYS_ADMIN)) 771 return -EPERM; 772 773 lock_kernel(); 774 /* We don't handle the integer fs type */ 775 if ((flags & SMNT_NEWTYPE) == 0) 776 goto out; 777 778 /* Do not allow for those flags we don't support */ 779 if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5)) 780 goto out; 781 782 if (flags & SMNT_REMOUNT) 783 linux_flags |= MS_REMOUNT; 784 if (flags & SMNT_RDONLY) 785 linux_flags |= MS_RDONLY; 786 if (flags & SMNT_NOSUID) 787 linux_flags |= MS_NOSUID; 788 789 dir_page = getname(dir); 790 ret = PTR_ERR(dir_page); 791 if (IS_ERR(dir_page)) 792 goto out; 793 794 type_page = getname(type); 795 ret = PTR_ERR(type_page); 796 if (IS_ERR(type_page)) 797 goto out1; 798 799 if (strcmp(type_page, "ext2") == 0) { 800 dev_fname = getname(data); 801 } else if (strcmp(type_page, "iso9660") == 0) { 802 dev_fname = getname(data); 803 } else if (strcmp(type_page, "minix") == 0) { 804 dev_fname = getname(data); 805 } else if (strcmp(type_page, "nfs") == 0) { 806 ret = sunos_nfs_mount (dir_page, flags, data); 807 goto out2; 808 } else if (strcmp(type_page, "ufs") == 0) { 809 printk("Warning: UFS filesystem mounts unsupported.\n"); 810 ret = -ENODEV; 811 goto out2; 812 } else if (strcmp(type_page, "proc")) { 813 ret = -ENODEV; 814 goto out2; 815 } 816 ret = PTR_ERR(dev_fname); 817 if (IS_ERR(dev_fname)) 818 goto out2; 819 ret = do_mount(dev_fname, dir_page, type_page, linux_flags, NULL); 820 if (dev_fname) 821 putname(dev_fname); 822out2: 823 putname(type_page); 824out1: 825 putname(dir_page); 826out: 827 unlock_kernel(); 828 return ret; 829} 830 831 832asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid) 833{ 834 int ret; 835 836 /* So stupid... */ 837 if ((!pid || pid == current->pid) && 838 !pgid) { 839 sys_setsid(); 840 ret = 0; 841 } else { 842 ret = sys_setpgid(pid, pgid); 843 } 844 return ret; 845} 846 847/* So stupid... */ 848asmlinkage int sunos_wait4(pid_t pid, unsigned int __user *stat_addr, 849 int options, struct rusage __user*ru) 850{ 851 int ret; 852 853 ret = sys_wait4((pid ? pid : -1), stat_addr, options, ru); 854 return ret; 855} 856 857asmlinkage int sunos_killpg(int pgrp, int sig) 858{ 859 int ret; 860 861 rcu_read_lock(); 862 ret = -EINVAL; 863 if (pgrp > 0) 864 ret = kill_pgrp(find_pid(pgrp), sig, 0); 865 rcu_read_unlock(); 866 867 return ret; 868} 869 870asmlinkage int sunos_audit(void) 871{ 872 lock_kernel(); 873 printk ("sys_audit\n"); 874 unlock_kernel(); 875 return -1; 876} 877 878asmlinkage unsigned long sunos_gethostid(void) 879{ 880 unsigned long ret; 881 882 lock_kernel(); 883 ret = ((unsigned long)idprom->id_machtype << 24) | 884 (unsigned long)idprom->id_sernum; 885 unlock_kernel(); 886 return ret; 887} 888 889/* sysconf options, for SunOS compatibility */ 890#define _SC_ARG_MAX 1 891#define _SC_CHILD_MAX 2 892#define _SC_CLK_TCK 3 893#define _SC_NGROUPS_MAX 4 894#define _SC_OPEN_MAX 5 895#define _SC_JOB_CONTROL 6 896#define _SC_SAVED_IDS 7 897#define _SC_VERSION 8 898 899asmlinkage long sunos_sysconf (int name) 900{ 901 long ret; 902 903 switch (name){ 904 case _SC_ARG_MAX: 905 ret = ARG_MAX; 906 break; 907 case _SC_CHILD_MAX: 908 ret = current->signal->rlim[RLIMIT_NPROC].rlim_cur; 909 break; 910 case _SC_CLK_TCK: 911 ret = HZ; 912 break; 913 case _SC_NGROUPS_MAX: 914 ret = NGROUPS_MAX; 915 break; 916 case _SC_OPEN_MAX: 917 ret = current->signal->rlim[RLIMIT_NOFILE].rlim_cur; 918 break; 919 case _SC_JOB_CONTROL: 920 ret = 1; /* yes, we do support job control */ 921 break; 922 case _SC_SAVED_IDS: 923 ret = 1; /* yes, we do support saved uids */ 924 break; 925 case _SC_VERSION: 926 /* mhm, POSIX_VERSION is in /usr/include/unistd.h 927 * should it go on /usr/include/linux? 928 */ 929 ret = 199009L; 930 break; 931 default: 932 ret = -1; 933 break; 934 }; 935 return ret; 936} 937 938asmlinkage int sunos_semsys(int op, unsigned long arg1, unsigned long arg2, 939 unsigned long arg3, void *ptr) 940{ 941 union semun arg4; 942 int ret; 943 944 switch (op) { 945 case 0: 946 /* Most arguments match on a 1:1 basis but cmd doesn't */ 947 switch(arg3) { 948 case 4: 949 arg3=GETPID; break; 950 case 5: 951 arg3=GETVAL; break; 952 case 6: 953 arg3=GETALL; break; 954 case 3: 955 arg3=GETNCNT; break; 956 case 7: 957 arg3=GETZCNT; break; 958 case 8: 959 arg3=SETVAL; break; 960 case 9: 961 arg3=SETALL; break; 962 } 963 /* sys_semctl(): */ 964 /* value to modify semaphore to */ 965 arg4.__pad = (void __user *) ptr; 966 ret = sys_semctl((int)arg1, (int)arg2, (int)arg3, arg4 ); 967 break; 968 case 1: 969 /* sys_semget(): */ 970 ret = sys_semget((key_t)arg1, (int)arg2, (int)arg3); 971 break; 972 case 2: 973 /* sys_semop(): */ 974 ret = sys_semop((int)arg1, (struct sembuf __user *)arg2, (unsigned)arg3); 975 break; 976 default: 977 ret = -EINVAL; 978 break; 979 }; 980 return ret; 981} 982 983asmlinkage int sunos_msgsys(int op, unsigned long arg1, unsigned long arg2, 984 unsigned long arg3, unsigned long arg4) 985{ 986 struct sparc_stackf *sp; 987 unsigned long arg5; 988 int rval; 989 990 switch(op) { 991 case 0: 992 rval = sys_msgget((key_t)arg1, (int)arg2); 993 break; 994 case 1: 995 rval = sys_msgctl((int)arg1, (int)arg2, 996 (struct msqid_ds __user *)arg3); 997 break; 998 case 2: 999 lock_kernel(); 1000 sp = (struct sparc_stackf *)current->thread.kregs->u_regs[UREG_FP]; 1001 arg5 = sp->xxargs[0]; 1002 unlock_kernel(); 1003 rval = sys_msgrcv((int)arg1, (struct msgbuf __user *)arg2, 1004 (size_t)arg3, (long)arg4, (int)arg5); 1005 break; 1006 case 3: 1007 rval = sys_msgsnd((int)arg1, (struct msgbuf __user *)arg2, 1008 (size_t)arg3, (int)arg4); 1009 break; 1010 default: 1011 rval = -EINVAL; 1012 break; 1013 } 1014 return rval; 1015} 1016 1017asmlinkage int sunos_shmsys(int op, unsigned long arg1, unsigned long arg2, 1018 unsigned long arg3) 1019{ 1020 unsigned long raddr; 1021 int rval; 1022 1023 switch(op) { 1024 case 0: 1025 /* do_shmat(): attach a shared memory area */ 1026 rval = do_shmat((int)arg1,(char __user *)arg2,(int)arg3,&raddr); 1027 if (!rval) 1028 rval = (int) raddr; 1029 break; 1030 case 1: 1031 /* sys_shmctl(): modify shared memory area attr. */ 1032 rval = sys_shmctl((int)arg1,(int)arg2,(struct shmid_ds __user *)arg3); 1033 break; 1034 case 2: 1035 /* sys_shmdt(): detach a shared memory area */ 1036 rval = sys_shmdt((char __user *)arg1); 1037 break; 1038 case 3: 1039 /* sys_shmget(): get a shared memory area */ 1040 rval = sys_shmget((key_t)arg1,(int)arg2,(int)arg3); 1041 break; 1042 default: 1043 rval = -EINVAL; 1044 break; 1045 }; 1046 return rval; 1047} 1048 1049#define SUNOS_EWOULDBLOCK 35 1050 1051/* see the sunos man page read(2v) for an explanation 1052 of this garbage. We use O_NDELAY to mark 1053 file descriptors that have been set non-blocking 1054 using 4.2BSD style calls. (tridge) */ 1055 1056static inline int check_nonblock(int ret, int fd) 1057{ 1058 if (ret == -EAGAIN) { 1059 struct file * file = fget(fd); 1060 if (file) { 1061 if (file->f_flags & O_NDELAY) 1062 ret = -SUNOS_EWOULDBLOCK; 1063 fput(file); 1064 } 1065 } 1066 return ret; 1067} 1068 1069asmlinkage int sunos_read(unsigned int fd, char __user *buf, int count) 1070{ 1071 int ret; 1072 1073 ret = check_nonblock(sys_read(fd,buf,count),fd); 1074 return ret; 1075} 1076 1077asmlinkage int sunos_readv(unsigned long fd, const struct iovec __user *vector, 1078 long count) 1079{ 1080 int ret; 1081 1082 ret = check_nonblock(sys_readv(fd,vector,count),fd); 1083 return ret; 1084} 1085 1086asmlinkage int sunos_write(unsigned int fd, char __user *buf, int count) 1087{ 1088 int ret; 1089 1090 ret = check_nonblock(sys_write(fd,buf,count),fd); 1091 return ret; 1092} 1093 1094asmlinkage int sunos_writev(unsigned long fd, 1095 const struct iovec __user *vector, long count) 1096{ 1097 int ret; 1098 1099 ret = check_nonblock(sys_writev(fd,vector,count),fd); 1100 return ret; 1101} 1102 1103asmlinkage int sunos_recv(int fd, void __user *ubuf, int size, unsigned flags) 1104{ 1105 int ret; 1106 1107 ret = check_nonblock(sys_recv(fd,ubuf,size,flags),fd); 1108 return ret; 1109} 1110 1111asmlinkage int sunos_send(int fd, void __user *buff, int len, unsigned flags) 1112{ 1113 int ret; 1114 1115 ret = check_nonblock(sys_send(fd,buff,len,flags),fd); 1116 return ret; 1117} 1118 1119asmlinkage int sunos_accept(int fd, struct sockaddr __user *sa, 1120 int __user *addrlen) 1121{ 1122 int ret; 1123 1124 while (1) { 1125 ret = check_nonblock(sys_accept(fd,sa,addrlen),fd); 1126 if (ret != -ENETUNREACH && ret != -EHOSTUNREACH) 1127 break; 1128 } 1129 1130 return ret; 1131} 1132 1133#define SUNOS_SV_INTERRUPT 2 1134 1135asmlinkage int 1136sunos_sigaction(int sig, const struct old_sigaction __user *act, 1137 struct old_sigaction __user *oact) 1138{ 1139 struct k_sigaction new_ka, old_ka; 1140 int ret; 1141 1142 if (act) { 1143 old_sigset_t mask; 1144 1145 if (!access_ok(VERIFY_READ, act, sizeof(*act)) || 1146 __get_user(new_ka.sa.sa_handler, &act->sa_handler) || 1147 __get_user(new_ka.sa.sa_flags, &act->sa_flags)) 1148 return -EFAULT; 1149 __get_user(mask, &act->sa_mask); 1150 new_ka.sa.sa_restorer = NULL; 1151 new_ka.ka_restorer = NULL; 1152 siginitset(&new_ka.sa.sa_mask, mask); 1153 new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; 1154 } 1155 1156 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 1157 1158 if (!ret && oact) { 1159 /* In the clone() case we could copy half consistent 1160 * state to the user, however this could sleep and 1161 * deadlock us if we held the signal lock on SMP. So for 1162 * now I take the easy way out and do no locking. 1163 * But then again we don't support SunOS lwp's anyways ;-) 1164 */ 1165 old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT; 1166 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || 1167 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || 1168 __put_user(old_ka.sa.sa_flags, &oact->sa_flags)) 1169 return -EFAULT; 1170 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); 1171 } 1172 1173 return ret; 1174} 1175 1176 1177asmlinkage int sunos_setsockopt(int fd, int level, int optname, 1178 char __user *optval, int optlen) 1179{ 1180 int tr_opt = optname; 1181 int ret; 1182 1183 if (level == SOL_IP) { 1184 /* Multicast socketopts (ttl, membership) */ 1185 if (tr_opt >=2 && tr_opt <= 6) 1186 tr_opt += 30; 1187 } 1188 ret = sys_setsockopt(fd, level, tr_opt, optval, optlen); 1189 return ret; 1190} 1191 1192asmlinkage int sunos_getsockopt(int fd, int level, int optname, 1193 char __user *optval, int __user *optlen) 1194{ 1195 int tr_opt = optname; 1196 int ret; 1197 1198 if (level == SOL_IP) { 1199 /* Multicast socketopts (ttl, membership) */ 1200 if (tr_opt >=2 && tr_opt <= 6) 1201 tr_opt += 30; 1202 } 1203 ret = sys_getsockopt(fd, level, tr_opt, optval, optlen); 1204 return ret; 1205} 1206