📄 osf_sys.c
字号:
/* * linux/arch/alpha/kernel/osf_sys.c * * Copyright (C) 1995 Linus Torvalds *//* * This file handles some of the stranger OSF/1 system call interfaces. * Some of the system calls expect a non-C calling standard, others have * special parameter blocks.. */#include <linux/errno.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/stddef.h>#include <linux/unistd.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/user.h>#include <linux/a.out.h>#include <linux/utsname.h>#include <linux/time.h>#include <linux/timex.h>#include <linux/major.h>#include <linux/stat.h>#include <linux/mman.h>#include <linux/shm.h>#include <linux/poll.h>#include <linux/file.h>#include <linux/types.h>#include <linux/ipc.h>#include <asm/fpu.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/sysinfo.h>#include <asm/hwrpb.h>#include <asm/processor.h>extern int do_pipe(int *);extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);extern asmlinkage unsigned long sys_brk(unsigned long);/* * Brk needs to return an error. Still support Linux's brk(0) query idiom, * which OSF programs just shouldn't be doing. We're still not quite * identical to OSF as we don't return 0 on success, but doing otherwise * would require changes to libc. Hopefully this is good enough. */asmlinkage unsigned long osf_brk(unsigned long brk){ unsigned long retval = sys_brk(brk); if (brk && brk != retval) retval = -ENOMEM; return retval;} /* * This is pure guess-work.. */asmlinkage int osf_set_program_attributes( unsigned long text_start, unsigned long text_len, unsigned long bss_start, unsigned long bss_len){ struct mm_struct *mm; lock_kernel(); mm = current->mm; mm->end_code = bss_start + bss_len; mm->brk = bss_start + bss_len; printk("set_program_attributes(%lx %lx %lx %lx)\n", text_start, text_len, bss_start, bss_len); unlock_kernel(); return 0;}/* * OSF/1 directory handling functions... * * The "getdents()" interface is much more sane: the "basep" stuff is * braindamage (it can't really handle filesystems where the directory * offset differences aren't the same as "d_reclen"). */#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))#define ROUND_UP(x) (((x)+3) & ~3)struct osf_dirent { unsigned int d_ino; unsigned short d_reclen; unsigned short d_namlen; char d_name[1];};struct osf_dirent_callback { struct osf_dirent *dirent; long *basep; int count; int error;};static int osf_filldir(void *__buf, const char *name, int namlen, off_t offset, ino_t ino, unsigned int d_type){ struct osf_dirent *dirent; struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail */ if (reclen > buf->count) return -EINVAL; if (buf->basep) { put_user(offset, buf->basep); buf->basep = NULL; } dirent = buf->dirent; put_user(ino, &dirent->d_ino); put_user(namlen, &dirent->d_namlen); put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); ((char *) dirent) += reclen; buf->dirent = dirent; buf->count -= reclen; return 0;}asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, unsigned int count, long *basep){ int error; struct file *file; struct osf_dirent_callback buf; error = -EBADF; file = fget(fd); if (!file) goto out; buf.dirent = dirent; buf.basep = basep; buf.count = count; buf.error = 0; error = vfs_readdir(file, osf_filldir, &buf); if (error < 0) goto out_putf; error = buf.error; if (count != buf.count) error = count - buf.count;out_putf: fput(file);out: return error;}#undef ROUND_UP#undef NAME_OFFSET/* * Alpha syscall convention has no problem returning negative * values: */asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4, int a5, struct pt_regs regs){ extern int sys_getpriority(int, int); int prio; /* * We don't need to acquire the kernel lock here, because * all of these operations are local. sys_getpriority * will get the lock as required.. */ prio = sys_getpriority(which, who); if (prio >= 0) { regs.r0 = 0; /* special return: no errors */ prio = 20 - prio; } return prio;}/* * No need to acquire the kernel lock, we're local.. */asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs){ struct task_struct * tsk = current; (®s)->r20 = tsk->euid; return tsk->uid;}asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs){ struct task_struct * tsk = current; (®s)->r20 = tsk->egid; return tsk->gid;}asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs){ struct task_struct *tsk = current; /* * This isn't strictly "local" any more and we should actually * acquire the kernel lock. The "p_opptr" pointer might change * if the parent goes away (or due to ptrace). But any race * isn't actually going to matter, as if the parent happens * to change we can happily return either of the pids. */ (®s)->r20 = tsk->p_opptr->pid; return tsk->pid;}asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off){ struct file *file = NULL; unsigned long ret = -EBADF;#if 0 if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags);#endif if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); down(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, off); up(¤t->mm->mmap_sem); if (file) fput(file);out: return ret;}/* * The OSF/1 statfs structure is much larger, but this should * match the beginning, at least. */struct osf_statfs { short f_type; short f_flags; int f_fsize; int f_bsize; int f_blocks; int f_bfree; int f_bavail; int f_files; int f_ffree; __kernel_fsid_t f_fsid;} *osf_stat;static int linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat, unsigned long bufsiz){ struct osf_statfs tmp_stat; tmp_stat.f_type = linux_stat->f_type; tmp_stat.f_flags = 0; /* mount flags */ /* Linux doesn't provide a "fundamental filesystem block size": */ tmp_stat.f_fsize = linux_stat->f_bsize; tmp_stat.f_bsize = linux_stat->f_bsize; tmp_stat.f_blocks = linux_stat->f_blocks; tmp_stat.f_bfree = linux_stat->f_bfree; tmp_stat.f_bavail = linux_stat->f_bavail; tmp_stat.f_files = linux_stat->f_files; tmp_stat.f_ffree = linux_stat->f_ffree; tmp_stat.f_fsid = linux_stat->f_fsid; if (bufsiz > sizeof(tmp_stat)) bufsiz = sizeof(tmp_stat); return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;}static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz){ struct statfs linux_stat; int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat); if (!error) error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz); return error; }asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long bufsiz){ struct nameidata nd; int retval; retval = user_path_walk(path, &nd); if (!retval) { retval = do_osf_statfs(nd.dentry, buffer, bufsiz); path_release(&nd); } return retval;}asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz){ struct file *file; int retval; retval = -EBADF; file = fget(fd); if (file) { retval = do_osf_statfs(file->f_dentry, buffer, bufsiz); fput(file); } return retval;}/* * Uhh.. OSF/1 mount parameters aren't exactly obvious.. * * Although to be frank, neither are the native Linux/i386 ones.. */struct ufs_args { char *devname; int flags; uid_t exroot;};struct cdfs_args { char *devname; int flags; uid_t exroot;/* * This has lots more here, which Linux handles with the option block * but I'm too lazy to do the translation into ASCII. */};struct procfs_args { char *devname; int flags; uid_t exroot;};/* * We can't actually handle ufs yet, so we translate UFS mounts to * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS * layout is so braindead it's a major headache doing it. * * Just how long ago was it written? OTOH our UFS driver may be still * unhappy with OSF UFS. [CHECKME] */static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags){ int retval; struct cdfs_args tmp; char *devname; retval = -EFAULT; if (copy_from_user(&tmp, args, sizeof(tmp))) goto out; devname = getname(tmp.devname); retval = PTR_ERR(devname); if (IS_ERR(devname)) goto out; retval = do_mount(devname, dirname, "ext2", flags, NULL); putname(devname);out: return retval;}static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags){ int retval; struct cdfs_args tmp; char *devname; retval = -EFAULT; if (copy_from_user(&tmp, args, sizeof(tmp))) goto out; devname = getname(tmp.devname); retval = PTR_ERR(devname); if (IS_ERR(devname)) goto out; retval = do_mount(devname, dirname, "iso9660", flags, NULL); putname(devname);out: return retval;}static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags){ struct procfs_args tmp; if (copy_from_user(&tmp, args, sizeof(tmp))) return -EFAULT; return do_mount("", dirname, "proc", flags, NULL);}asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data){ int retval = -EINVAL; char *name; lock_kernel(); name = getname(path); retval = PTR_ERR(name); if (IS_ERR(name)) goto out; switch (typenr) { case 1: retval = osf_ufs_mount(name, (struct ufs_args *) data, flag); break; case 6: retval = osf_cdfs_mount(name, (struct cdfs_args *) data, flag); break; case 9: retval = osf_procfs_mount(name, (struct procfs_args *) data, flag); break; default: printk("osf_mount(%ld, %x)\n", typenr, flag); } putname(name);out: unlock_kernel(); return retval;}asmlinkage int osf_utsname(char *name){ int error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -