OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [sparc/] [kernel/] [sys_sunos.c] - Blame information for rev 3

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.