sys_sunos.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:29k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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