fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / parisc / hpux / sys_hpux.c
index 569895c..04c2ff4 100644 (file)
  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/capability.h>
+#include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/namei.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/utsname.h>
-#include <linux/vmalloc.h>
 #include <linux/vfs.h>
+#include <linux/vmalloc.h>
 
 #include <asm/errno.h>
 #include <asm/pgalloc.h>
@@ -65,7 +68,6 @@ int hpux_wait(int *stat_loc)
 
 int hpux_setpgrp(void)
 {
-       extern int sys_setpgid(int, int);
        return sys_setpgid(0,0);
 }
 
@@ -133,7 +135,7 @@ struct hpux_ustat {
  *  aid in porting forward if and when sys_ustat() is changed from
  *  its form in kernel 2.2.5.
  */
-static int hpux_ustat(dev_t dev, struct hpux_ustat *ubuf)
+static int hpux_ustat(dev_t dev, struct hpux_ustat __user *ubuf)
 {
        struct super_block *s;
        struct hpux_ustat tmp;  /* Changed to hpux_ustat */
@@ -143,19 +145,18 @@ static int hpux_ustat(dev_t dev, struct hpux_ustat *ubuf)
        s = user_get_super(dev);
        if (s == NULL)
                goto out;
-       err = vfs_statfs(s, &sbuf);
+       err = vfs_statfs(s->s_root, &sbuf);
        drop_super(s);
        if (err)
                goto out;
 
-       memset(&tmp,0,sizeof(struct hpux_ustat));  /* Changed to hpux_ustat */
+       memset(&tmp,0,sizeof(tmp));
 
        tmp.f_tfree = (int32_t)sbuf.f_bfree;
        tmp.f_tinode = (u_int32_t)sbuf.f_ffree;
        tmp.f_blksize = (u_int32_t)sbuf.f_bsize;  /*  Added this line  */
 
-       /* Changed to hpux_ustat:  */
-       err = copy_to_user(ubuf,&tmp,sizeof(struct hpux_ustat)) ? -EFAULT : 0;
+       err = copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 out:
        return err;
 }
@@ -185,37 +186,62 @@ struct hpux_statfs {
      int16_t f_pad;
 };
 
-/* hpux statfs */
-int hpux_statfs(const char *path, struct hpux_statfs *buf)
+static int vfs_statfs_hpux(struct dentry *dentry, struct hpux_statfs *buf)
 {
-       int error;
-       int len;
-       char *kpath;
-
-       len = strlen_user((char *)path); 
-
-       kpath = (char *) kmalloc(len+1, GFP_KERNEL);
-       if ( !kpath ) {
-       printk(KERN_DEBUG "failed to kmalloc kpath\n");
-       return 0;
-       }
+       struct kstatfs st;
+       int retval;
+       
+       retval = vfs_statfs(dentry, &st);
+       if (retval)
+               return retval;
+
+       memset(buf, 0, sizeof(*buf));
+       buf->f_type = st.f_type;
+       buf->f_bsize = st.f_bsize;
+       buf->f_blocks = st.f_blocks;
+       buf->f_bfree = st.f_bfree;
+       buf->f_bavail = st.f_bavail;
+       buf->f_files = st.f_files;
+       buf->f_ffree = st.f_ffree;
+       buf->f_fsid[0] = st.f_fsid.val[0];
+       buf->f_fsid[1] = st.f_fsid.val[1];
 
-       if ( copy_from_user(kpath, (char *)path, len+1) ) {
-       printk(KERN_DEBUG "failed to copy_from_user kpath\n");
-       kfree(kpath);
        return 0;
-       }
-
-       printk(KERN_DEBUG "hpux_statfs(\"%s\",-)\n", kpath);
+}
 
-       kfree(kpath);
+/* hpux statfs */
+asmlinkage long hpux_statfs(const char __user *path,
+                                               struct hpux_statfs __user *buf)
+{
+       struct nameidata nd;
+       int error;
 
-       /* just fake it, beginning of structures match */
-       error = sys_statfs(path, (struct statfs *) buf);
+       error = user_path_walk(path, &nd);
+       if (!error) {
+               struct hpux_statfs tmp;
+               error = vfs_statfs_hpux(nd.dentry, &tmp);
+               if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
+                       error = -EFAULT;
+               path_release(&nd);
+       }
+       return error;
+}
 
-       /* ignoring rest of statfs struct, but it should be zeros. Need to do 
-               something with f_fsid[1], which is the fstype for sysfs */
+asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
+{
+       struct file *file;
+       struct hpux_statfs tmp;
+       int error;
 
+       error = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+       error = vfs_statfs_hpux(file->f_path.dentry, &tmp);
+       if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
+               error = -EFAULT;
+       fput(file);
+ out:
        return error;
 }
 
@@ -240,16 +266,21 @@ static int hpux_uname(struct hpux_utsname *name)
 
        down_read(&uts_sem);
 
-       error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1);
-       error |= __put_user(0,name->sysname+HPUX_UTSLEN-1);
-       error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1);
-       error |= __put_user(0,name->nodename+HPUX_UTSLEN-1);
-       error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1);
-       error |= __put_user(0,name->release+HPUX_UTSLEN-1);
-       error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1);
-       error |= __put_user(0,name->version+HPUX_UTSLEN-1);
-       error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1);
-       error |= __put_user(0,name->machine+HPUX_UTSLEN-1);
+       error = __copy_to_user(&name->sysname, &utsname()->sysname,
+                              HPUX_UTSLEN - 1);
+       error |= __put_user(0, name->sysname + HPUX_UTSLEN - 1);
+       error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+                               HPUX_UTSLEN - 1);
+       error |= __put_user(0, name->nodename + HPUX_UTSLEN - 1);
+       error |= __copy_to_user(&name->release, &utsname()->release,
+                               HPUX_UTSLEN - 1);
+       error |= __put_user(0, name->release + HPUX_UTSLEN - 1);
+       error |= __copy_to_user(&name->version, &utsname()->version,
+                               HPUX_UTSLEN - 1);
+       error |= __put_user(0, name->version + HPUX_UTSLEN - 1);
+       error |= __copy_to_user(&name->machine, &utsname()->machine,
+                               HPUX_UTSLEN - 1);
+       error |= __put_user(0, name->machine + HPUX_UTSLEN - 1);
 
        up_read(&uts_sem);
 
@@ -347,8 +378,8 @@ int hpux_utssys(char *ubuf, int n, int type)
                /*  TODO:  print a warning about using this?  */
                down_write(&uts_sem);
                error = -EFAULT;
-               if (!copy_from_user(system_utsname.sysname, ubuf, len)) {
-                       system_utsname.sysname[len] = 0;
+               if (!copy_from_user(utsname()->sysname, ubuf, len)) {
+                       utsname()->sysname[len] = 0;
                        error = 0;
                }
                up_write(&uts_sem);
@@ -374,8 +405,8 @@ int hpux_utssys(char *ubuf, int n, int type)
                /*  TODO:  print a warning about this?  */
                down_write(&uts_sem);
                error = -EFAULT;
-               if (!copy_from_user(system_utsname.release, ubuf, len)) {
-                       system_utsname.release[len] = 0;
+               if (!copy_from_user(utsname()->release, ubuf, len)) {
+                       utsname()->release[len] = 0;
                        error = 0;
                }
                up_write(&uts_sem);
@@ -396,13 +427,13 @@ int hpux_getdomainname(char *name, int len)
        
        down_read(&uts_sem);
        
-       nlen = strlen(system_utsname.domainname) + 1;
+       nlen = strlen(utsname()->domainname) + 1;
 
        if (nlen < len)
                len = nlen;
        if(len > __NEW_UTS_LEN)
                goto done;
-       if(copy_to_user(name, system_utsname.domainname, len))
+       if(copy_to_user(name, utsname()->domainname, len))
                goto done;
        err = 0;
 done:
@@ -442,19 +473,23 @@ int hpux_sysfs(int opcode, unsigned long arg1, unsigned long arg2)
        if ( opcode == 1 ) { /* GETFSIND */     
                len = strlen_user((char *)arg1);
                printk(KERN_DEBUG "len of arg1 = %d\n", len);
-
-               fsname = (char *) kmalloc(len+1, GFP_KERNEL);
+               if (len == 0)
+                       return 0;
+               fsname = kmalloc(len, GFP_KERNEL);
                if ( !fsname ) {
                        printk(KERN_DEBUG "failed to kmalloc fsname\n");
                        return 0;
                }
 
-               if ( copy_from_user(fsname, (char *)arg1, len+1) ) {
+               if ( copy_from_user(fsname, (char *)arg1, len) ) {
                        printk(KERN_DEBUG "failed to copy_from_user fsname\n");
                        kfree(fsname);
                        return 0;
                }
 
+               /* String could be altered by userspace after strlen_user() */
+               fsname[len] = '\0';
+
                printk(KERN_DEBUG "that is '%s' as (char *)\n", fsname);
                if ( !strcmp(fsname, "hfs") ) {
                        fstype = 0;
@@ -671,8 +706,8 @@ static const char *syscall_names[] = {
        "setdomainname",         
        "async_daemon",          
        "getdirentries",          /* 195 */
-       "statfs",                
-       "fstatfs",               
+       NULL,                
+       NULL,               
        "vfsmount",              
        NULL,                    
        "waitpid",                /* 200 */