1439 lines · 33.7 KB · C
RawDownload
/* *  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/signal.h>#include <linux/sched/mm.h>#include <linux/sched/task_stack.h>#include <linux/sched/cputime.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/smp.h>#include <linux/stddef.h>#include <linux/syscalls.h>#include <linux/unistd.h>#include <linux/ptrace.h>#include <linux/user.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 <linux/namei.h>#include <linux/uio.h>#include <linux/vfs.h>#include <linux/rcupdate.h>#include <linux/slab.h> #include <asm/fpu.h>#include <asm/io.h>#include <linux/uaccess.h>#include <asm/sysinfo.h>#include <asm/thread_info.h>#include <asm/hwrpb.h>#include <asm/processor.h> /* * 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. */SYSCALL_DEFINE1(osf_brk, unsigned long, brk){	unsigned long retval = sys_brk(brk);	if (brk && brk != retval)		retval = -ENOMEM;	return retval;} /* * This is pure guess-work.. */SYSCALL_DEFINE4(osf_set_program_attributes, unsigned long, text_start,		unsigned long, text_len, unsigned long, bss_start,		unsigned long, bss_len){	struct mm_struct *mm; 	mm = current->mm;	mm->end_code = bss_start + bss_len;	mm->start_brk = bss_start + bss_len;	mm->brk = bss_start + bss_len;#if 0	printk("set_program_attributes(%lx %lx %lx %lx)\n",		text_start, text_len, bss_start, bss_len);#endif	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	offsetof (struct osf_dirent, d_name) struct osf_dirent {	unsigned int d_ino;	unsigned short d_reclen;	unsigned short d_namlen;	char d_name[1];}; struct osf_dirent_callback {	struct dir_context ctx;	struct osf_dirent __user *dirent;	long __user *basep;	unsigned int count;	int error;}; static intosf_filldir(struct dir_context *ctx, const char *name, int namlen,	    loff_t offset, u64 ino, unsigned int d_type){	struct osf_dirent __user *dirent;	struct osf_dirent_callback *buf =		container_of(ctx, struct osf_dirent_callback, ctx);	unsigned int reclen = ALIGN(NAME_OFFSET + namlen + 1, sizeof(u32));	unsigned int d_ino; 	buf->error = -EINVAL;	/* only used if we fail */	if (reclen > buf->count)		return -EINVAL;	d_ino = ino;	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {		buf->error = -EOVERFLOW;		return -EOVERFLOW;	}	if (buf->basep) {		if (put_user(offset, buf->basep))			goto Efault;		buf->basep = NULL;	}	dirent = buf->dirent;	if (put_user(d_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))		goto Efault;	dirent = (void __user *)dirent + reclen;	buf->dirent = dirent;	buf->count -= reclen;	return 0;Efault:	buf->error = -EFAULT;	return -EFAULT;} SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,		struct osf_dirent __user *, dirent, unsigned int, count,		long __user *, basep){	int error;	struct fd arg = fdget_pos(fd);	struct osf_dirent_callback buf = {		.ctx.actor = osf_filldir,		.dirent = dirent,		.basep = basep,		.count = count	}; 	if (!arg.file)		return -EBADF; 	error = iterate_dir(arg.file, &buf.ctx);	if (error >= 0)		error = buf.error;	if (count != buf.count)		error = count - buf.count; 	fdput_pos(arg);	return error;} #undef NAME_OFFSET SYSCALL_DEFINE6(osf_mmap, unsigned long, addr, unsigned long, len,		unsigned long, prot, unsigned long, flags, unsigned long, fd,		unsigned long, off){	unsigned long ret = -EINVAL; #if 0	if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))		printk("%s: unimplemented OSF mmap flags %04lx\n", 			current->comm, flags);#endif	if ((off + PAGE_ALIGN(len)) < off)		goto out;	if (off & ~PAGE_MASK)		goto out;	ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); out:	return ret;} struct osf_stat {	int		st_dev;	int		st_pad1;	unsigned	st_mode;	unsigned short	st_nlink;	short		st_nlink_reserved;	unsigned	st_uid;	unsigned	st_gid;	int		st_rdev;	int		st_ldev;	long		st_size;	int		st_pad2;	int		st_uatime;	int		st_pad3;	int		st_umtime;	int		st_pad4;	int		st_uctime;	int		st_pad5;	int		st_pad6;	unsigned	st_flags;	unsigned	st_gen;	long		st_spare[4];	unsigned	st_ino;	int		st_ino_reserved;	int		st_atime;	int		st_atime_reserved;	int		st_mtime;	int		st_mtime_reserved;	int		st_ctime;	int		st_ctime_reserved;	long		st_blksize;	long		st_blocks;}; /* * 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;}; struct osf_statfs64 {	short f_type;	short f_flags;	int f_pad1;	int f_pad2;	int f_pad3;	int f_pad4;	int f_pad5;	int f_pad6;	int f_pad7;	__kernel_fsid_t f_fsid;	u_short f_namemax;	short f_reserved1;	int f_spare[8];	char f_pad8[90];	char f_pad9[90];	long mount_info[10];	u_long f_flags2;	long f_spare2[14];	long f_fsize;	long f_bsize;	long f_blocks;	long f_bfree;	long f_bavail;	long f_files;	long f_ffree;}; static intlinux_to_osf_stat(struct kstat *lstat, struct osf_stat __user *osf_stat){	struct osf_stat tmp = { 0 }; 	tmp.st_dev	= lstat->dev;	tmp.st_mode	= lstat->mode;	tmp.st_nlink	= lstat->nlink;	tmp.st_uid	= from_kuid_munged(current_user_ns(), lstat->uid);	tmp.st_gid	= from_kgid_munged(current_user_ns(), lstat->gid);	tmp.st_rdev	= lstat->rdev;	tmp.st_ldev	= lstat->rdev;	tmp.st_size	= lstat->size;	tmp.st_uatime	= lstat->atime.tv_nsec / 1000;	tmp.st_umtime	= lstat->mtime.tv_nsec / 1000;	tmp.st_uctime	= lstat->ctime.tv_nsec / 1000;	tmp.st_ino	= lstat->ino;	tmp.st_atime	= lstat->atime.tv_sec;	tmp.st_mtime	= lstat->mtime.tv_sec;	tmp.st_ctime	= lstat->ctime.tv_sec;	tmp.st_blksize	= lstat->blksize;	tmp.st_blocks	= lstat->blocks; 	return copy_to_user(osf_stat, &tmp, sizeof(tmp)) ? -EFAULT : 0;} static intlinux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *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 */	tmp_stat.f_fsize = linux_stat->f_frsize;	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 intlinux_to_osf_statfs64(struct kstatfs *linux_stat, struct osf_statfs64 __user *osf_stat,		      unsigned long bufsiz){	struct osf_statfs64 tmp_stat = { 0 }; 	tmp_stat.f_type = linux_stat->f_type;	tmp_stat.f_fsize = linux_stat->f_frsize;	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;} SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,		struct osf_statfs __user *, buffer, unsigned long, bufsiz){	struct kstatfs linux_stat;	int error = user_statfs(pathname, &linux_stat);	if (!error)		error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);	return error;	} SYSCALL_DEFINE2(osf_stat, char __user *, name, struct osf_stat __user *, buf){	struct kstat stat;	int error; 	error = vfs_stat(name, &stat);	if (error)		return error; 	return linux_to_osf_stat(&stat, buf);} SYSCALL_DEFINE2(osf_lstat, char __user *, name, struct osf_stat __user *, buf){	struct kstat stat;	int error; 	error = vfs_lstat(name, &stat);	if (error)		return error; 	return linux_to_osf_stat(&stat, buf);} SYSCALL_DEFINE2(osf_fstat, int, fd, struct osf_stat __user *, buf){	struct kstat stat;	int error; 	error = vfs_fstat(fd, &stat);	if (error)		return error; 	return linux_to_osf_stat(&stat, buf);} SYSCALL_DEFINE3(osf_fstatfs, unsigned long, fd,		struct osf_statfs __user *, buffer, unsigned long, bufsiz){	struct kstatfs linux_stat;	int error = fd_statfs(fd, &linux_stat);	if (!error)		error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);	return error;} SYSCALL_DEFINE3(osf_statfs64, char __user *, pathname,		struct osf_statfs64 __user *, buffer, unsigned long, bufsiz){	struct kstatfs linux_stat;	int error = user_statfs(pathname, &linux_stat);	if (!error)		error = linux_to_osf_statfs64(&linux_stat, buffer, bufsiz);	return error;} SYSCALL_DEFINE3(osf_fstatfs64, unsigned long, fd,		struct osf_statfs64 __user *, buffer, unsigned long, bufsiz){	struct kstatfs linux_stat;	int error = fd_statfs(fd, &linux_stat);	if (!error)		error = linux_to_osf_statfs64(&linux_stat, buffer, bufsiz);	return error;} /* * Uhh.. OSF/1 mount parameters aren't exactly obvious.. * * Although to be frank, neither are the native Linux/i386 ones.. */struct ufs_args {	char __user *devname;	int flags;	uid_t exroot;}; struct cdfs_args {	char __user *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 __user *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 intosf_ufs_mount(const char __user *dirname,	      struct ufs_args __user *args, int flags){	int retval;	struct cdfs_args tmp;	struct filename *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->name, dirname, "ext2", flags, NULL);	putname(devname); out:	return retval;} static intosf_cdfs_mount(const char __user *dirname,	       struct cdfs_args __user *args, int flags){	int retval;	struct cdfs_args tmp;	struct filename *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->name, dirname, "iso9660", flags, NULL);	putname(devname); out:	return retval;} static intosf_procfs_mount(const char __user *dirname,		 struct procfs_args __user *args, int flags){	struct procfs_args tmp; 	if (copy_from_user(&tmp, args, sizeof(tmp)))

Lines 1–500 of 1439.