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