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
  36. sunos_shmsys

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

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