1241 lines · 29.8 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.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 <asm/uaccess.h>#include <asm/system.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 osf_dirent __user *dirent;	long __user *basep;	unsigned int count;	int error;}; static intosf_filldir(void *__buf, const char *name, int namlen, loff_t offset,	    u64 ino, unsigned int d_type){	struct osf_dirent __user *dirent;	struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;	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 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)		error = buf.error;	if (count != buf.count)		error = count - buf.count; 	fput(file); out:	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;}  /* * 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;}; 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;} 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_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;} /* * 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(char *dirname, struct ufs_args __user *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 intosf_cdfs_mount(char *dirname, struct cdfs_args __user *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 intosf_procfs_mount(char *dirname, struct procfs_args __user *args, int flags){	struct procfs_args tmp; 	if (copy_from_user(&tmp, args, sizeof(tmp)))		return -EFAULT; 	return do_mount("", dirname, "proc", flags, NULL);} SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path,		int, flag, void __user *, data){	int retval;	char *name; 	name = getname(path);	retval = PTR_ERR(name);	if (IS_ERR(name))		goto out;	switch (typenr) {	case 1:		retval = osf_ufs_mount(name, data, flag);		break;	case 6:		retval = osf_cdfs_mount(name, data, flag);		break;	case 9:		retval = osf_procfs_mount(name, data, flag);		break;	default:		retval = -EINVAL;		printk("osf_mount(%ld, %x)\n", typenr, flag);	}	putname(name); out:	return retval;} SYSCALL_DEFINE1(osf_utsname, char __user *, name){	int error; 	down_read(&uts_sem);	error = -EFAULT;	if (copy_to_user(name + 0, utsname()->sysname, 32))		goto out;	if (copy_to_user(name + 32, utsname()->nodename, 32))		goto out;	if (copy_to_user(name + 64, utsname()->release, 32))		goto out;	if (copy_to_user(name + 96, utsname()->version, 32))		goto out;	if (copy_to_user(name + 128, utsname()->machine, 32))		goto out; 	error = 0; out:	up_read(&uts_sem);		return error;} SYSCALL_DEFINE0(getpagesize){	return PAGE_SIZE;} SYSCALL_DEFINE0(getdtablesize){	return sysctl_nr_open;} /* * For compatibility with OSF/1 only.  Use utsname(2) instead. */SYSCALL_DEFINE2(osf_getdomainname, char __user *, name, int, namelen){	unsigned len;	int i; 	if (!access_ok(VERIFY_WRITE, name, namelen))		return -EFAULT; 	len = namelen;	if (len > 32)		len = 32; 	down_read(&uts_sem);	for (i = 0; i < len; ++i) {		__put_user(utsname()->domainname[i], name + i);		if (utsname()->domainname[i] == '\0')			break;	}	up_read(&uts_sem); 	return 0;} /* * The following stuff should move into a header file should it ever * be labeled "officially supported."  Right now, there is just enough * support to avoid applications (such as tar) printing error * messages.  The attributes are not really implemented. */ /* * Values for Property list entry flag */#define PLE_PROPAGATE_ON_COPY		0x1	/* cp(1) will copy entry						   by default */#define PLE_FLAG_MASK			0x1	/* Valid flag values */#define PLE_FLAG_ALL			-1	/* All flag value */ struct proplistname_args {	unsigned int pl_mask;	unsigned int pl_numnames;	char **pl_names;}; union pl_args {	struct setargs {		char __user *path;		long follow;		long nbytes;		char __user *buf;	} set;	struct fsetargs {		long fd;		long nbytes;		char __user *buf;	} fset;	struct getargs {		char __user *path;		long follow;		struct proplistname_args __user *name_args;		long nbytes;		char __user *buf;		int __user *min_buf_size;	} get;	struct fgetargs {		long fd;		struct proplistname_args __user *name_args;		long nbytes;		char __user *buf;		int __user *min_buf_size;	} fget;	struct delargs {		char __user *path;		long follow;		struct proplistname_args __user *name_args;	} del;	struct fdelargs {		long fd;		struct proplistname_args __user *name_args;	} fdel;}; enum pl_code {	PL_SET = 1, PL_FSET = 2,	PL_GET = 3, PL_FGET = 4,	PL_DEL = 5, PL_FDEL = 6}; SYSCALL_DEFINE2(osf_proplist_syscall, enum pl_code, code,		union pl_args __user *, args){	long error;	int __user *min_buf_size_ptr; 	switch (code) {	case PL_SET:		if (get_user(error, &args->set.nbytes))

Lines 1–500 of 1241.