root/arch/sparc/kernel/sys_sunos.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sunos_mmap
  2. sunos_mctl
  3. sunos_brk
  4. sunos_sbrk
  5. sunos_sstk
  6. sunos_vadvise
  7. sunos_madvise
  8. sunos_mincore
  9. sunos_getdtablesize
  10. sunos_sigblock
  11. sunos_sigsetmask
  12. sunos_filldir
  13. sunos_getdents
  14. sunos_filldirentry
  15. sunos_getdirentries
  16. sunos_getdomainname
  17. sunos_uname
  18. sunos_nosys
  19. sunos_fpathconf
  20. sunos_pathconf
  21. sunos_select
  22. sunos_nop
  23. sunos_nfs_get_server_fd
  24. get_default
  25. sunos_nfs_mount
  26. sunos_mount
  27. sunos_setpgrp
  28. sunos_wait4
  29. sunos_killpg
  30. sunos_audit
  31. sunos_gethostid
  32. sunos_sysconf
  33. free_wait
  34. check
  35. sunos_poll

   1 /* $Id: sys_sunos.c,v 1.37 1996/04/19 16:52:38 miguel 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  * The sunos_poll routine is based on iBCS2's poll routine, this
  12  * is the copyright message for that file:
  13  *
  14  * This file contains the procedures for the handling of poll.
  15  *
  16  * Copyright (C) 1994 Eric Youngdale
  17  *
  18  * Created for Linux based loosely upon linux select code, which
  19  * in turn is loosely based upon Mathius Lattner's minix
  20  * patches by Peter MacDonald. Heavily edited by Linus.
  21  *
  22  * Poll is used by SVr4 instead of select, and it has considerably
  23  * more functionality.  Parts of it are related to STREAMS, and since
  24  * we do not have streams, we fake it.  In fact, select() still exists
  25  * under SVr4, but libc turns it into a poll() call instead.  We attempt
  26  * to do the inverse mapping.
  27  */
  28 
  29 #include <linux/config.h>
  30 #include <linux/kernel.h>
  31 #include <linux/sched.h>
  32 #include <linux/types.h>
  33 #include <linux/mman.h>
  34 #include <linux/mm.h>
  35 #include <linux/swap.h>
  36 #include <linux/fs.h>
  37 #include <linux/resource.h>
  38 #include <linux/signal.h>
  39 #include <linux/uio.h>
  40 #include <linux/utsname.h>
  41 #include <linux/fs.h>
  42 #include <linux/major.h>
  43 #include <linux/stat.h>
  44 #include <linux/malloc.h>
  45 #include <linux/pagemap.h>
  46 
  47 #include <asm/segment.h>
  48 #ifndef KERNEL_DS
  49 #include <linux/segment.h>
  50 #endif
  51 
  52 #include <asm/page.h>
  53 #include <asm/pgtable.h>
  54 #include <asm/pconf.h>
  55 #include <asm/idprom.h> /* for gethostid() */
  56 #include <asm/unistd.h>
  57 #include <asm/system.h>
  58 
  59 /* For the nfs mount emulation */
  60 #include <linux/socket.h>
  61 #include <linux/in.h>
  62 #include <linux/nfs.h>
  63 #include <linux/nfs_mount.h>
  64 
  65 /* for sunos_select */
  66 #include <linux/time.h>
  67 #include <linux/personality.h>
  68 
  69 extern unsigned long get_sparc_unmapped_area(unsigned long len);
  70 
  71 /* We use the SunOS mmap() semantics. */
  72 asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
     /* [previous][next][first][last][top][bottom][index][help] */
  73                                     unsigned long prot, unsigned long flags,
  74                                     unsigned long fd, unsigned long off)
  75 {
  76         struct file * file = NULL;
  77         unsigned long retval, ret_type;
  78 
  79         if(flags & MAP_NORESERVE) {
  80                 printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n",
  81                        current->comm);
  82                 flags &= ~MAP_NORESERVE;
  83         }
  84         if(!(flags & MAP_ANONYMOUS))
  85                 if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  86                         return -EBADF;
  87         if(!(flags & MAP_FIXED) && !addr) {
  88                 addr = get_sparc_unmapped_area(len);
  89                 if(!addr)
  90                         return -ENOMEM;
  91         }
  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(MAJOR(file->f_inode->i_rdev) == MEM_MAJOR &&
  97            MINOR(file->f_inode->i_rdev) == 5) {
  98                 flags |= MAP_ANONYMOUS;
  99                 file = 0;
 100         }
 101         ret_type = flags & _MAP_NEW;
 102         flags &= ~_MAP_NEW;
 103         retval = do_mmap(file, addr, len, prot, flags, off);
 104         if(ret_type)
 105                 return retval;
 106         else
 107                 return ((retval < KERNBASE) ? 0 : retval);
 108 }
 109 
 110 /* lmbench calls this, just say "yeah, ok" */
 111 asmlinkage int sunos_mctl(unsigned long addr, unsigned long len, int function, char *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113         return 0;
 114 }
 115 
 116 /* SunOS is completely broken... it returns 0 on success, otherwise
 117  * ENOMEM.  For sys_sbrk() it wants the new brk value as a return
 118  * on success and ENOMEM as before on failure.
 119  */
 120 asmlinkage int sunos_brk(unsigned long brk)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         int freepages;
 123         unsigned long rlim;
 124         unsigned long newbrk, oldbrk;
 125 
 126         if (brk < current->mm->end_code)
 127                 return -ENOMEM;
 128 
 129         newbrk = PAGE_ALIGN(brk);
 130         oldbrk = PAGE_ALIGN(current->mm->brk);
 131         if (oldbrk == newbrk) {
 132                 current->mm->brk = brk;
 133                 return 0;
 134         }
 135 
 136         /*
 137          * Always allow shrinking brk
 138          */
 139         if (brk <= current->mm->brk) {
 140                 current->mm->brk = brk;
 141                 do_munmap(newbrk, oldbrk-newbrk);
 142                 return 0;
 143         }
 144         /*
 145          * Check against rlimit and stack..
 146          */
 147         rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 148         if (rlim >= RLIM_INFINITY)
 149                 rlim = ~0;
 150         if (brk - current->mm->end_code > rlim)
 151                 return -ENOMEM;
 152 
 153         /*
 154          * Check against existing mmap mappings.
 155          */
 156         if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
 157                 return -ENOMEM;
 158 
 159         /*
 160          * stupid algorithm to decide if we have enough memory: while
 161          * simple, it hopefully works in most obvious cases.. Easy to
 162          * fool it, but this should catch most mistakes.
 163          */
 164         freepages = buffermem >> PAGE_SHIFT;
 165         freepages += page_cache_size;
 166         freepages >>= 1;
 167         freepages += nr_free_pages;
 168         freepages += nr_swap_pages;
 169         freepages -= MAP_NR(high_memory) >> 4;
 170         freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
 171         if (freepages < 0)
 172                 return -ENOMEM;
 173         /*
 174          * Ok, we have probably got enough memory - let it rip.
 175          */
 176         current->mm->brk = brk;
 177         do_mmap(NULL, oldbrk, newbrk-oldbrk,
 178                 PROT_READ|PROT_WRITE|PROT_EXEC,
 179                 MAP_FIXED|MAP_PRIVATE, 0);
 180         return 0;
 181 }
 182 
 183 asmlinkage unsigned long sunos_sbrk(int increment)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185         int error;
 186 
 187         /* This should do it hopefully... */
 188         error = sunos_brk(((int) current->mm->brk) + increment);
 189         if(error)
 190                 return error;
 191         else
 192                 return current->mm->brk;
 193 }
 194 
 195 /* XXX Completely undocumented, and completely magic...
 196  * XXX I believe it is to increase the size of the stack by
 197  * XXX argument 'increment' and return the new end of stack
 198  * XXX area.  Wheee...
 199  */
 200 asmlinkage unsigned long sunos_sstk(int increment)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202         printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n",
 203                current->comm, increment);
 204         return -1;
 205 }
 206 
 207 /* Give hints to the kernel as to what paging strategy to use...
 208  * Completely bogus, don't remind me.
 209  */
 210 #define VA_NORMAL     0 /* Normal vm usage expected */
 211 #define VA_ABNORMAL   1 /* Abnormal/random vm usage probable */
 212 #define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */
 213 #define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */
 214 static char *vstrings[] = {
 215         "VA_NORMAL",
 216         "VA_ABNORMAL",
 217         "VA_SEQUENTIAL",
 218         "VA_INVALIDATE",
 219 };
 220 
 221 asmlinkage void sunos_vadvise(unsigned long strategy)
     /* [previous][next][first][last][top][bottom][index][help] */
 222 {
 223         /* I wanna see who uses this... */
 224         printk("%s: Advises us to use %s paging strategy\n",
 225                current->comm,
 226                strategy <= 3 ? vstrings[strategy] : "BOGUS");
 227         return; /* We don't do diddly... */
 228 }
 229 
 230 /* Same as vadvise, and just as bogus, but for a range of virtual
 231  * process address space.
 232  */
 233 #define MADV_NORMAL      0 /* Nothing special... */
 234 #define MADV_RANDOM      1 /* I am emacs... */
 235 #define MADV_SEQUENTIAL  2 /* I am researcher code... */
 236 #define MADV_WILLNEED    3 /* Pages in this range will be needed */
 237 #define MADV_DONTNEED    4 /* Pages in this range won't be needed */
 238 
 239 static char *mstrings[] = {
 240         "MADV_NORMAL",
 241         "MADV_RANDOM",
 242         "MADV_SEQUENTIAL",
 243         "MADV_WILLNEED",
 244         "MADV_DONTNEED",
 245 };
 246 
 247 asmlinkage void sunos_madvise(unsigned long address, unsigned long len,
     /* [previous][next][first][last][top][bottom][index][help] */
 248                               unsigned long strategy)
 249 {
 250         /* I wanna see who uses this... */
 251         printk("%s: Advises us to use %s paging strategy for addr<%08lx> len<%08lx>\n",
 252                current->comm,
 253                strategy <= 4 ? mstrings[strategy] : "BOGUS",
 254                address, len);
 255         return; /* We don't do diddly... */
 256 }
 257 
 258 /* Places into character array, the status of all the pages in the passed
 259  * range from 'addr' to 'addr + len'.  -1 on failure, 0 on success...
 260  * The encoding in each character is:
 261  * low-bit is zero == Page is not in physical ram right now
 262  * low-bit is one  == Page is currently residing in core
 263  * All other bits are undefined within the character so there...
 264  * Also, if you try to get stats on an area outside of the user vm area
 265  * *or* the passed base address is not aligned on a page boundary you
 266  * get an error.
 267  */
 268 asmlinkage int sunos_mincore(unsigned long addr, unsigned long len, char *array)
     /* [previous][next][first][last][top][bottom][index][help] */
 269 {
 270         pgd_t *pgdp;
 271         pmd_t *pmdp;
 272         pte_t *ptep;
 273         unsigned long limit;
 274         int num_pages, pnum;
 275 
 276         if(addr & (PAGE_SIZE - 1))
 277                 return -EINVAL;
 278 
 279         num_pages = (len / PAGE_SIZE);
 280         if(verify_area(VERIFY_WRITE, array, num_pages))
 281                 return -EFAULT; /* bum array, you lose... */
 282         if((addr >= KERNBASE) || ((addr + len) > KERNBASE))
 283                 return -ENOMEM; /* I'm sure you're curious about kernel mappings.. */
 284 
 285         /* Wheee, go through pte's */
 286         pnum = 0;
 287         for(limit = addr + len; addr < limit; addr += PAGE_SIZE, pnum++) {
 288                 pgdp = pgd_offset(current->mm, addr);
 289                 if(pgd_none(*pgdp))
 290                         return -ENOMEM; /* As per SunOS manpage */
 291                 pmdp = pmd_offset(pgdp, addr);
 292                 if(pmd_none(*pmdp))
 293                         return -ENOMEM; /* As per SunOS manpage */
 294                 ptep = pte_offset(pmdp, addr);
 295                 if(pte_none(*ptep))
 296                         return -ENOMEM; /* As per SunOS manpage */
 297                 /* Page in core or Swapped page? */
 298                 array[pnum] = pte_present(*ptep) ? 1 : 0;
 299         }
 300         return 0; /* Success... I think... */
 301 }
 302 
 303 /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE
 304  * resource limit and is for backwards compatibility with older sunos
 305  * revs.
 306  */
 307 asmlinkage long sunos_getdtablesize(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309         return NR_OPEN;
 310 }
 311 #define _S(nr) (1<<((nr)-1))
 312 
 313 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 314 
 315 asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317         unsigned long flags;
 318         unsigned long old;
 319 
 320         save_flags(flags); cli();
 321         old = current->blocked;
 322         current->blocked |= (blk_mask & _BLOCKABLE);
 323         restore_flags(flags);
 324         return old;
 325 }
 326 
 327 asmlinkage unsigned long sunos_sigsetmask(unsigned long newmask)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329         unsigned long flags;
 330         unsigned long retval;
 331 
 332         save_flags(flags); cli();
 333         retval = current->blocked;
 334         current->blocked = newmask & _BLOCKABLE;
 335         restore_flags(flags);
 336         return retval;
 337 }
 338 
 339 /* SunOS getdents is very similar to the newer Linux (iBCS2 compliant)    */
 340 /* getdents system call, the format of the structure just has a different */
 341 /* layout (d_off+d_ino instead of d_ino+d_off) */
 342 struct sunos_dirent {
 343     long           d_off;
 344     unsigned long  d_ino;
 345     unsigned short d_reclen;
 346     unsigned short d_namlen;
 347     char           d_name[1];
 348 };
 349 
 350 struct sunos_dirent_callback {
 351     struct sunos_dirent *curr;
 352     struct sunos_dirent *previous;
 353     int count;
 354     int error;
 355 };
 356 
 357 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 358 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
 359 
 360 static int sunos_filldir(void * __buf, const char * name, int namlen,
     /* [previous][next][first][last][top][bottom][index][help] */
 361                          off_t offset, ino_t ino)
 362 {
 363         struct sunos_dirent * dirent;
 364         struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
 365         int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
 366 
 367         buf->error = -EINVAL;   /* only used if we fail.. */
 368         if (reclen > buf->count)
 369                 return -EINVAL;
 370         dirent = buf->previous;
 371         if (dirent)
 372                 put_user(offset, &dirent->d_off);
 373         dirent = buf->curr;
 374         buf->previous = dirent;
 375         put_user(ino, &dirent->d_ino);
 376         put_user(namlen, &dirent->d_namlen);
 377         put_user(reclen, &dirent->d_reclen);
 378         memcpy_tofs(dirent->d_name, name, namlen);
 379         put_user(0, dirent->d_name + namlen);
 380         ((char *) dirent) += reclen;
 381         buf->curr = dirent;
 382         buf->count -= reclen;
 383         return 0;
 384 }
 385 
 386 asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 387 {
 388         struct file * file;
 389         struct sunos_dirent * lastdirent;
 390         struct sunos_dirent_callback buf;
 391         int error;
 392 
 393         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 394                 return -EBADF;
 395         if (!file->f_op || !file->f_op->readdir)
 396                 return -ENOTDIR;
 397         if(verify_area(VERIFY_WRITE, dirent, cnt))
 398                 return -EFAULT;
 399         if(cnt < (sizeof(struct sunos_dirent) + 255))
 400                 return -EINVAL;
 401 
 402         buf.curr = (struct sunos_dirent *) dirent;
 403         buf.previous = NULL;
 404         buf.count = cnt;
 405         buf.error = 0;
 406         error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir);
 407         if (error < 0)
 408                 return error;
 409         lastdirent = buf.previous;
 410         if (!lastdirent)
 411                 return buf.error;
 412         put_user(file->f_pos, &lastdirent->d_off);
 413         return cnt - buf.count;
 414 }
 415 
 416 /* Old sunos getdirentries, severely broken compatibility stuff here. */
 417 struct sunos_direntry {
 418     unsigned long  d_ino;
 419     unsigned short d_reclen;
 420     unsigned short d_namlen;
 421     char           d_name[1];
 422 };
 423 
 424 struct sunos_direntry_callback {
 425     struct sunos_direntry *curr;
 426     struct sunos_direntry *previous;
 427     int count;
 428     int error;
 429 };
 430 
 431 static int sunos_filldirentry(void * __buf, const char * name, int namlen,
     /* [previous][next][first][last][top][bottom][index][help] */
 432                               off_t offset, ino_t ino)
 433 {
 434         struct sunos_direntry * dirent;
 435         struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf;
 436         int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
 437 
 438         buf->error = -EINVAL;   /* only used if we fail.. */
 439         if (reclen > buf->count)
 440                 return -EINVAL;
 441         dirent = buf->previous;
 442         dirent = buf->curr;
 443         buf->previous = dirent;
 444         put_user(ino, &dirent->d_ino);
 445         put_user(namlen, &dirent->d_namlen);
 446         put_user(reclen, &dirent->d_reclen);
 447         memcpy_tofs(dirent->d_name, name, namlen);
 448         put_user(0, dirent->d_name + namlen);
 449         ((char *) dirent) += reclen;
 450         buf->curr = dirent;
 451         buf->count -= reclen;
 452         return 0;
 453 }
 454 
 455 asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep)
     /* [previous][next][first][last][top][bottom][index][help] */
 456 {
 457         struct file * file;
 458         struct sunos_direntry * lastdirent;
 459         struct sunos_direntry_callback buf;
 460         int error;
 461 
 462         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 463                 return -EBADF;
 464         if (!file->f_op || !file->f_op->readdir)
 465                 return -ENOTDIR;
 466         if(verify_area(VERIFY_WRITE, dirent, cnt) ||
 467            verify_area(VERIFY_WRITE, basep, sizeof(unsigned int)))
 468                 return -EFAULT;
 469         if(cnt < (sizeof(struct sunos_direntry) + 255))
 470                 return -EINVAL;
 471 
 472         buf.curr = (struct sunos_direntry *) dirent;
 473         buf.previous = NULL;
 474         buf.count = cnt;
 475         buf.error = 0;
 476         error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry);
 477         if (error < 0)
 478                 return error;
 479         lastdirent = buf.previous;
 480         if (!lastdirent)
 481                 return buf.error;
 482         put_user(file->f_pos, basep);
 483         return cnt - buf.count;
 484 }
 485 
 486 asmlinkage int sunos_getdomainname(char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 487 {
 488         int error;
 489 
 490         if(len > __NEW_UTS_LEN)
 491                 return -EFAULT;
 492         error = verify_area(VERIFY_WRITE, name, len);
 493         if(error)
 494                 return -EFAULT;
 495         memcpy_tofs(name, system_utsname.domainname, len);
 496         return 0;
 497 }
 498 
 499 struct sunos_utsname {
 500         char sname[9];
 501         char nname[9];
 502         char nnext[56];
 503         char rel[9];
 504         char ver[9];
 505         char mach[9];
 506 };
 507 
 508 asmlinkage int sunos_uname(struct sunos_utsname *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 509 {
 510         int error;
 511         if(!name)
 512                 return -EFAULT;
 513         error = verify_area(VERIFY_WRITE, name, sizeof *name);
 514         if(error)
 515                 return error;
 516         memcpy_tofs(&name->sname[0], &system_utsname.sysname[0],
 517                     sizeof(name->sname) - 1);
 518         memcpy_tofs(&name->nname[0], &system_utsname.nodename[0],
 519                     sizeof(name->nname) - 1);
 520         name->nname[8] = '\0';
 521         memcpy_tofs(&name->rel[0], &system_utsname.release[0],
 522                     sizeof(name->rel) - 1);
 523         memcpy_tofs(&name->ver[0], &system_utsname.version[0],
 524                     sizeof(name->ver) - 1);
 525         memcpy_tofs(&name->mach[0], &system_utsname.machine[0],
 526                     sizeof(name->mach) - 1);
 527         return 0;
 528 }
 529 
 530 asmlinkage int sunos_nosys(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 531 {
 532         struct pt_regs *regs;
 533 
 534         regs = (struct pt_regs *) (current->saved_kernel_stack +
 535                                    sizeof(struct reg_window));
 536         current->tss.sig_address = regs->pc;
 537         current->tss.sig_desc = regs->u_regs[UREG_G1];
 538         send_sig(SIGSYS, current, 1);
 539         printk("Process makes ni_syscall number %d, register dump:\n",
 540                (int) regs->u_regs[UREG_G1]);
 541         show_regs(regs);
 542         return -ENOSYS;
 543 }
 544 
 545 /* This is not a real and complete implementation yet, just to keep
 546  * the easy SunOS binaries happy.
 547  */
 548 asmlinkage int sunos_fpathconf(int fd, int name)
     /* [previous][next][first][last][top][bottom][index][help] */
 549 {
 550         switch(name) {
 551         case _PCONF_LINK:
 552                 return LINK_MAX;
 553         case _PCONF_CANON:
 554                 return MAX_CANON;
 555         case _PCONF_INPUT:
 556                 return MAX_INPUT;
 557         case _PCONF_NAME:
 558                 return NAME_MAX;
 559         case _PCONF_PATH:
 560                 return PATH_MAX;
 561         case _PCONF_PIPE:
 562                 return PIPE_BUF;
 563         case _PCONF_CHRESTRICT:
 564                 return 1; /* XXX Investigate XXX */
 565         case _PCONF_NOTRUNC:
 566                 return 0; /* XXX Investigate XXX */
 567         case _PCONF_VDISABLE:
 568                 return 30; /* XXX Investigate XXX */
 569         default:
 570                 return -EINVAL;
 571         }
 572 }
 573 
 574 asmlinkage int sunos_pathconf(char *path, int name)
     /* [previous][next][first][last][top][bottom][index][help] */
 575 {
 576         return sunos_fpathconf(0, name); /* XXX cheese XXX */
 577 }
 578 
 579 /* SunOS mount system call emulation */
 580 extern asmlinkage int
 581 sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
 582 
 583 asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
     /* [previous][next][first][last][top][bottom][index][help] */
 584 {
 585         /* SunOS binaries expect that select won't change the tvp contents */
 586         current->personality |= STICKY_TIMEOUTS;
 587         return sys_select (width, inp, outp, exp, tvp);
 588 }
 589 
 590 asmlinkage void sunos_nop(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592         return;
 593 }
 594 
 595 /* SunOS mount/umount. */
 596 #define SMNT_RDONLY       1
 597 #define SMNT_NOSUID       2
 598 #define SMNT_NEWTYPE      4
 599 #define SMNT_GRPID        8
 600 #define SMNT_REMOUNT      16
 601 #define SMNT_NOSUB        32
 602 #define SMNT_MULTI        64
 603 #define SMNT_SYS5         128
 604 
 605 struct sunos_fh_t {
 606         char fh_data [NFS_FHSIZE];
 607 };
 608 
 609 struct sunos_nfs_mount_args {
 610         struct sockaddr_in  *addr; /* file server address */
 611         struct nfs_fh *fh;     /* File handle to be mounted */
 612         int        flags;      /* flags */
 613         int        wsize;      /* write size in bytes */
 614         int        rsize;      /* read size in bytes */
 615         int        timeo;      /* initial timeout in .1 secs */
 616         int        retrans;    /* times to retry send */
 617         char       *hostname;  /* server's hostname */
 618         int        acregmin;   /* attr cache file min secs */
 619         int        acregmax;   /* attr cache file max secs */
 620         int        acdirmin;   /* attr cache dir min secs */
 621         int        acdirmax;   /* attr cache dir max secs */
 622         char       *netname;   /* server's netname */
 623 };
 624 
 625 
 626 extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
 627 extern dev_t get_unnamed_dev(void);
 628 extern void put_unnamed_dev(dev_t);
 629 extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
 630 extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
 631 extern asmlinkage int sys_socket(int family, int type, int protocol);
 632 extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
 633 
 634 
 635 /* Bind the socket on a local reserved port and connect it to the
 636  * remote server.  This on Linux/i386 is done by the mount program,
 637  * not by the kernel. 
 638  */
 639 static int
 640 sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 641 {
 642         struct sockaddr_in local;
 643         struct sockaddr_in server;
 644         int    try_port;
 645         int    ret;
 646         struct socket *socket;
 647         struct inode  *inode;
 648         struct file   *file;
 649 
 650         file = current->files->fd [fd];
 651         inode = file->f_inode;
 652         if (!inode || !inode->i_sock)
 653                 return 0;
 654 
 655         socket = &inode->u.socket_i;
 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                 return 0;
 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                 return 0;
 679         return 1;
 680 }
 681 
 682 static int get_default (int value, int def_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 683 {
 684     if (value)
 685         return value;
 686     else
 687         return def_value;
 688 }
 689 
 690 asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 691 {
 692         int  ret = -ENODEV, error;
 693         int  server_fd;
 694         char *the_name;
 695         struct nfs_mount_data linux_nfs_mount;
 696         struct sunos_nfs_mount_args *sunos_mount = data;
 697         dev_t dev;
 698 
 699         error = verify_area(VERIFY_READ, data, sizeof (struct sunos_nfs_mount_args));
 700         if (error)
 701                 return error;
 702         /* Ok, here comes the fun part: Linux's nfs mount needs a
 703          * socket connection to the server, but SunOS mount does not
 704          * require this, so we use the information on the destination
 705          * address to create a socket and bind it to a reserved
 706          * port on this system
 707          */
 708         server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 709         if (server_fd < 0)
 710                 return -ENXIO;
 711 
 712         if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){
 713                 sys_close (server_fd);
 714                 return -ENXIO;
 715         }
 716 
 717         /* Now, bind it to a locally reserved port */
 718         linux_nfs_mount.version  = NFS_MOUNT_VERSION;
 719         linux_nfs_mount.flags    = sunos_mount->flags;
 720         linux_nfs_mount.addr     = *sunos_mount->addr;
 721         linux_nfs_mount.root     = *sunos_mount->fh;
 722         linux_nfs_mount.fd       = server_fd;
 723         
 724         linux_nfs_mount.rsize    = get_default (sunos_mount->rsize, 8192);
 725         linux_nfs_mount.wsize    = get_default (sunos_mount->wsize, 8192);
 726         linux_nfs_mount.timeo    = get_default (sunos_mount->timeo, 10);
 727         linux_nfs_mount.retrans  = sunos_mount->retrans;
 728         
 729         linux_nfs_mount.acregmin = sunos_mount->acregmin;
 730         linux_nfs_mount.acregmax = sunos_mount->acregmax;
 731         linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
 732         linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
 733 
 734         if (getname (sunos_mount->hostname, &the_name))
 735                 return -EFAULT;
 736 
 737         strncpy (linux_nfs_mount.hostname, the_name, 254);
 738         linux_nfs_mount.hostname [255] = 0;
 739         putname (the_name);
 740 
 741         dev = get_unnamed_dev ();
 742         
 743         ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
 744         if (ret)
 745             put_unnamed_dev(dev);
 746 
 747         return ret;
 748 }
 749 
 750 asmlinkage int
 751 sunos_mount(char *type, char *dir, int flags, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 752 {
 753         int linux_flags = MS_MGC_MSK; /* new semantics */
 754         int error;
 755         char *dev_fname = 0;
 756 
 757         /* We don't handle the integer fs type */
 758         if ((flags & SMNT_NEWTYPE) == 0)
 759                 return -EINVAL;
 760 
 761         /* Do not allow for those flags we don't support */
 762         if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5))
 763                 return -EINVAL;
 764 
 765         if(flags & SMNT_REMOUNT)
 766                 linux_flags |= MS_REMOUNT;
 767         if(flags & SMNT_RDONLY)
 768                 linux_flags |= MS_RDONLY;
 769         if(flags & SMNT_NOSUID)
 770                 linux_flags |= MS_NOSUID;
 771         error = verify_area(VERIFY_READ, type, 16);
 772         if(error)
 773                 return error;
 774         if(strcmp(type, "ext2") == 0) {
 775                 dev_fname = (char *) data;
 776         } else if(strcmp(type, "iso9660") == 0) {
 777                 dev_fname = (char *) data;
 778         } else if(strcmp(type, "minix") == 0) {
 779                 dev_fname = (char *) data;
 780         } else if(strcmp(type, "ext") == 0) {
 781                 dev_fname = (char *) data;
 782         } else if(strcmp(type, "xiafs") == 0) {
 783                 dev_fname = (char *) data;
 784         } else if(strcmp(type, "nfs") == 0) {
 785                 error = sunos_nfs_mount (dir, flags, data);
 786                 return error;
 787         } else if(strcmp(type, "ufs") == 0) {
 788                 printk("Warning: UFS filesystem mounts unsupported.\n");
 789                 return -ENODEV;
 790         } else if(strcmp(type, "proc")) {
 791                 return -ENODEV;
 792         }
 793         if(error)
 794                 return error;
 795         error = sys_mount(dev_fname, dir, type, linux_flags, NULL);
 796         return error;
 797 }
 798 
 799 extern asmlinkage int sys_setsid(void);
 800 extern asmlinkage int sys_setpgid(pid_t, pid_t);
 801 
 802 asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid)
     /* [previous][next][first][last][top][bottom][index][help] */
 803 {
 804         /* So stupid... */
 805         if((!pid || pid == current->pid) &&
 806            !pgid) {
 807                 sys_setsid();
 808                 return 0;
 809         } else {
 810                 return sys_setpgid(pid, pgid);
 811         }
 812 }
 813 
 814 /* So stupid... */
 815 extern asmlinkage int sys_wait4(pid_t, unsigned int *, int, struct rusage *);
 816 asmlinkage int sunos_wait4(pid_t pid, unsigned int *stat_addr, int options, struct rusage *ru)
     /* [previous][next][first][last][top][bottom][index][help] */
 817 {
 818         return sys_wait4((pid ? pid : -1), stat_addr, options, ru);
 819 }
 820 
 821 extern int kill_pg(int, int, int);
 822 asmlinkage int sunos_killpg(int pgrp, int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 823 {
 824         return kill_pg(pgrp, sig, 0);
 825 }
 826 
 827 asmlinkage int sunos_audit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 828 {
 829         printk ("sys_audit\n");
 830         return -1;
 831 }
 832 
 833 extern asmlinkage unsigned long sunos_gethostid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 834 {
 835         return (unsigned long) idprom->id_sernum;
 836 }
 837 
 838 extern asmlinkage long sunos_sysconf (int name)
     /* [previous][next][first][last][top][bottom][index][help] */
 839 {
 840         switch (name){
 841         case _SC_ARG_MAX:
 842                 return ARG_MAX;
 843         case _SC_CHILD_MAX:
 844                 return CHILD_MAX;
 845         case _SC_CLK_TCK:
 846                 return HZ;
 847         case _SC_NGROUPS_MAX:
 848                 return NGROUPS_MAX;
 849         case _SC_OPEN_MAX:
 850                 return OPEN_MAX;
 851         case _SC_JOB_CONTROL:
 852                 return 1;       /* yes, we do support job control */
 853         case _SC_SAVED_IDS:
 854                 return 1;       /* yes, we do support saved uids  */
 855         case _SC_VERSION:
 856                 /* mhm, POSIX_VERSION is in /usr/include/unistd.h
 857                  * should it go on /usr/include/linux?
 858                  */
 859                 return  199009L; 
 860         }
 861         return -1;
 862 }
 863 
 864 #define POLL_ROUND_UP(x,y) (((x)+(y)-1)/(y))
 865 
 866 #define POLLIN 1
 867 #define POLLPRI 2
 868 #define POLLOUT 4
 869 #define POLLERR 8
 870 #define POLLHUP 16
 871 #define POLLNVAL 32
 872 #define POLLRDNORM 64
 873 #define POLLWRNORM POLLOUT
 874 #define POLLRDBAND 128
 875 #define POLLWRBAND 256
 876 
 877 #define LINUX_POLLIN (POLLRDNORM | POLLRDBAND | POLLIN)
 878 #define LINUX_POLLOUT (POLLWRBAND | POLLWRNORM | POLLOUT)
 879 #define LINUX_POLLERR (POLLERR)
 880 
 881 static inline void free_wait(select_table * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 882 {
 883         struct select_table_entry * entry = p->entry + p->nr;
 884 
 885         while (p->nr > 0) {
 886                 p->nr--;
 887                 entry--;
 888                 remove_wait_queue(entry->wait_address,&entry->wait);
 889         }
 890 }
 891 
 892 
 893 /* Copied directly from fs/select.c */
 894 static int check(int flag, select_table * wait, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 895 {
 896         struct inode * inode;
 897         struct file_operations *fops;
 898         int (*select) (struct inode *, struct file *, int, select_table *);
 899 
 900         inode = file->f_inode;
 901         if ((fops = file->f_op) && (select = fops->select))
 902                 return select(inode, file, flag, wait)
 903                     || (wait && select(inode, file, flag, NULL));
 904         if (S_ISREG(inode->i_mode))
 905                 return 1;
 906         return 0;
 907 }
 908 
 909 struct poll {
 910         int fd;
 911         short events;
 912         short revents;
 913 };
 914 
 915 int sunos_poll(struct poll * ufds, size_t nfds, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 916 {
 917         int i,j, count, fdcount, error, retflag;
 918         struct poll * fdpnt;
 919         struct poll * fds, *fds1;
 920         select_table wait_table, *wait;
 921         struct select_table_entry *entry;
 922 
 923         if ((error = verify_area(VERIFY_READ, ufds, nfds*sizeof(struct poll))))
 924                 return error;
 925 
 926         if (nfds > NR_OPEN)
 927                 return -EINVAL;
 928 
 929         if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL))
 930         || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL)))
 931                 return -ENOMEM;
 932 
 933         memcpy_fromfs(fds, ufds, nfds*sizeof(struct poll));
 934 
 935         if (timeout < 0)
 936                 current->timeout = 0x7fffffff;
 937         else {
 938                 current->timeout = jiffies + POLL_ROUND_UP(timeout, (1000/HZ));
 939                 if (current->timeout <= jiffies)
 940                         current->timeout = 0;
 941         }
 942 
 943         count = 0;
 944         wait_table.nr = 0;
 945         wait_table.entry = entry;
 946         wait = &wait_table;
 947 
 948         for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
 949                 i = fdpnt->fd;
 950                 fdpnt->revents = 0;
 951                 if (!current->files->fd[i] || !current->files->fd[i]->f_inode)
 952                         fdpnt->revents = POLLNVAL;
 953         }
 954 repeat:
 955         current->state = TASK_INTERRUPTIBLE;
 956         for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
 957                 i = fdpnt->fd;
 958 
 959                 if(i < 0) continue;
 960                 if (!current->files->fd[i] || !current->files->fd[i]->f_inode) continue;
 961 
 962                 if ((fdpnt->events & LINUX_POLLIN)
 963                 && check(SEL_IN, wait, current->files->fd[i])) {
 964                         if (fdpnt->events & POLLIN)
 965                                 retflag = POLLIN;
 966                         if (fdpnt->events & POLLRDNORM)
 967                                 retflag = POLLRDNORM;
 968                         fdpnt->revents |= retflag; 
 969                         count++;
 970                         wait = NULL;
 971                 }
 972 
 973                 if ((fdpnt->events & LINUX_POLLOUT) &&
 974                 check(SEL_OUT, wait, current->files->fd[i])) {
 975                         fdpnt->revents |= (LINUX_POLLOUT & fdpnt->events);
 976                         count++;
 977                         wait = NULL;
 978                 }
 979 
 980                 if (check(SEL_EX, wait, current->files->fd[i])) {
 981                         fdpnt->revents |= POLLHUP;
 982                         count++;
 983                         wait = NULL;
 984                 }
 985         }
 986 
 987         if ((current->signal & (~current->blocked)))
 988                 return -EINTR;
 989 
 990         wait = NULL;
 991         if (!count && current->timeout > jiffies) {
 992                 schedule();
 993                 goto repeat;
 994         }
 995 
 996         free_wait(&wait_table);
 997         free_page((unsigned long) entry);
 998 
 999         /* OK, now copy the revents fields back to user space. */
1000         fds1 = fds;
1001         fdcount = 0;
1002         for(i=0; i < (int)nfds; i++, ufds++, fds++) {
1003                 if (fds->revents) {
1004                         fdcount++;
1005                 }
1006                 put_fs_word(fds->revents, &ufds->revents);
1007         }
1008         kfree(fds1);
1009         current->timeout = 0;
1010         current->state = TASK_RUNNING;
1011         return fdcount;
1012 }
1013 

/* [previous][next][first][last][top][bottom][index][help] */