File: /usr/src/linux/arch/sparc64/solaris/fs.c

1     /* $Id: fs.c,v 1.25 2001/09/19 00:04:30 davem Exp $
2      * fs.c: fs related syscall emulation for Solaris
3      *
4      * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5      *
6      * 1999-08-19 Implemented solaris F_FREESP (truncate)
7      *            fcntl, by Jason Rappleye (rappleye@ccr.buffalo.edu)
8      */
9     
10     #include <linux/types.h>
11     #include <linux/sched.h>
12     #include <linux/slab.h>
13     #include <linux/fs.h>
14     #include <linux/mm.h>
15     #include <linux/file.h>
16     #include <linux/stat.h>
17     #include <linux/smp_lock.h>
18     #include <linux/limits.h>
19     #include <linux/resource.h>
20     #include <linux/quotaops.h>
21     
22     #include <asm/uaccess.h>
23     #include <asm/string.h>
24     #include <asm/ptrace.h>
25     
26     #include "conv.h"
27     
28     #define R4_DEV(DEV) ((DEV & 0xff) | ((DEV & 0xff00) << 10))
29     #define R4_MAJOR(DEV) (((DEV) >> 18) & 0x3fff)
30     #define R4_MINOR(DEV) ((DEV) & 0x3ffff)
31     #define R3_VERSION	1
32     #define R4_VERSION	2
33     
34     typedef struct {
35     	s32	tv_sec;
36     	s32	tv_nsec;
37     } timestruct_t;
38     
39     struct sol_stat {
40     	u32		st_dev;
41     	s32		st_pad1[3];     /* network id */
42     	u32		st_ino;
43     	u32		st_mode;
44     	u32		st_nlink;
45     	u32		st_uid;
46     	u32		st_gid;
47     	u32		st_rdev;
48     	s32		st_pad2[2];
49     	s32		st_size;
50     	s32		st_pad3;	/* st_size, off_t expansion */
51     	timestruct_t	st_atime;
52     	timestruct_t	st_mtime;
53     	timestruct_t	st_ctime;
54     	s32		st_blksize;
55     	s32		st_blocks;
56     	char		st_fstype[16];
57     	s32		st_pad4[8];     /* expansion area */
58     };
59     
60     struct sol_stat64 {
61     	u32		st_dev;
62     	s32		st_pad1[3];     /* network id */
63     	u64		st_ino;
64     	u32		st_mode;
65     	u32		st_nlink;
66     	u32		st_uid;
67     	u32		st_gid;
68     	u32		st_rdev;
69     	s32		st_pad2[2];
70     	s64		st_size;
71     	timestruct_t	st_atime;
72     	timestruct_t	st_mtime;
73     	timestruct_t	st_ctime;
74     	s64		st_blksize;
75     	s32		st_blocks;
76     	char		st_fstype[16];
77     	s32		st_pad4[4];     /* expansion area */
78     };
79     
80     #define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8))
81     
82     static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf)
83     {
84     	if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev)	||
85     	    __put_user (kbuf->st_ino, &ubuf->st_ino)		||
86     	    __put_user (kbuf->st_mode, &ubuf->st_mode)		||
87     	    __put_user (kbuf->st_nlink, &ubuf->st_nlink)	||
88     	    __put_user (kbuf->st_uid, &ubuf->st_uid)		||
89     	    __put_user (kbuf->st_gid, &ubuf->st_gid)		||
90     	    __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev)	||
91     	    __put_user (kbuf->st_size, &ubuf->st_size)		||
92     	    __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec)	||
93     	    __put_user (0, &ubuf->st_atime.tv_nsec)		||
94     	    __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec)	||
95     	    __put_user (0, &ubuf->st_mtime.tv_nsec)		||
96     	    __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec)	||
97     	    __put_user (0, &ubuf->st_ctime.tv_nsec)		||
98     	    __put_user (kbuf->st_blksize, &ubuf->st_blksize)	||
99     	    __put_user (kbuf->st_blocks, &ubuf->st_blocks)	||
100     	    __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype))
101     		return -EFAULT;
102     	return 0;
103     }
104     
105     static inline int putstat64(struct sol_stat64 *ubuf, struct stat *kbuf)
106     {
107     	if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev)	||
108     	    __put_user (kbuf->st_ino, &ubuf->st_ino)		||
109     	    __put_user (kbuf->st_mode, &ubuf->st_mode)		||
110     	    __put_user (kbuf->st_nlink, &ubuf->st_nlink)	||
111     	    __put_user (kbuf->st_uid, &ubuf->st_uid)		||
112     	    __put_user (kbuf->st_gid, &ubuf->st_gid)		||
113     	    __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev)	||
114     	    __put_user (kbuf->st_size, &ubuf->st_size)		||
115     	    __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec)	||
116     	    __put_user (0, &ubuf->st_atime.tv_nsec)		||
117     	    __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec)	||
118     	    __put_user (0, &ubuf->st_mtime.tv_nsec)		||
119     	    __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec)	||
120     	    __put_user (0, &ubuf->st_ctime.tv_nsec)		||
121     	    __put_user (kbuf->st_blksize, &ubuf->st_blksize)	||
122     	    __put_user (kbuf->st_blocks, &ubuf->st_blocks)	||
123     	    __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype))
124     		return -EFAULT;
125     	return 0;
126     }
127     
128     asmlinkage int solaris_stat(u32 filename, u32 statbuf)
129     {
130     	int ret;
131     	struct stat s;
132     	char *filenam;
133     	mm_segment_t old_fs = get_fs();
134     	int (*sys_newstat)(char *,struct stat *) = 
135     		(int (*)(char *,struct stat *))SYS(stat);
136     	
137     	filenam = getname ((char *)A(filename));
138     	ret = PTR_ERR(filenam);
139     	if (!IS_ERR(filenam)) {
140     		set_fs (KERNEL_DS);
141     		ret = sys_newstat(filenam, &s);
142     		set_fs (old_fs);
143     		putname (filenam);
144     		if (putstat ((struct sol_stat *)A(statbuf), &s))
145     			return -EFAULT;
146     	}
147     	return ret;
148     }
149     
150     asmlinkage int solaris_xstat(int vers, u32 filename, u32 statbuf)
151     {
152     	/* Solaris doesn't bother with looking at vers, so we do neither */
153     	return solaris_stat(filename, statbuf);
154     }
155     
156     asmlinkage int solaris_stat64(u32 filename, u32 statbuf)
157     {
158     	int ret;
159     	struct stat s;
160     	char *filenam;
161     	mm_segment_t old_fs = get_fs();
162     	int (*sys_newstat)(char *,struct stat *) = 
163     		(int (*)(char *,struct stat *))SYS(stat);
164     	
165     	filenam = getname ((char *)A(filename));
166     	ret = PTR_ERR(filenam);
167     	if (!IS_ERR(filenam)) {
168     		set_fs (KERNEL_DS);
169     		ret = sys_newstat(filenam, &s);
170     		set_fs (old_fs);
171     		putname (filenam);
172     		if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
173     			return -EFAULT;
174     	}
175     	return ret;
176     }
177     
178     asmlinkage int solaris_lstat(u32 filename, u32 statbuf)
179     {
180     	int ret;
181     	struct stat s;
182     	char *filenam;
183     	mm_segment_t old_fs = get_fs();
184     	int (*sys_newlstat)(char *,struct stat *) = 
185     		(int (*)(char *,struct stat *))SYS(lstat);
186     	
187     	filenam = getname ((char *)A(filename));
188     	ret = PTR_ERR(filenam);
189     	if (!IS_ERR(filenam)) {
190     		set_fs (KERNEL_DS);
191     		ret = sys_newlstat(filenam, &s);
192     		set_fs (old_fs);
193     		putname (filenam);
194     		if (putstat ((struct sol_stat *)A(statbuf), &s))
195     			return -EFAULT;
196     	}
197     	return ret;
198     }
199     
200     asmlinkage int solaris_lxstat(int vers, u32 filename, u32 statbuf)
201     {
202     	return solaris_lstat(filename, statbuf);
203     }
204     
205     asmlinkage int solaris_lstat64(u32 filename, u32 statbuf)
206     {
207     	int ret;
208     	struct stat s;
209     	char *filenam;
210     	mm_segment_t old_fs = get_fs();
211     	int (*sys_newlstat)(char *,struct stat *) = 
212     		(int (*)(char *,struct stat *))SYS(lstat);
213     	
214     	filenam = getname ((char *)A(filename));
215     	ret = PTR_ERR(filenam);
216     	if (!IS_ERR(filenam)) {
217     		set_fs (KERNEL_DS);
218     		ret = sys_newlstat(filenam, &s);
219     		set_fs (old_fs);
220     		putname (filenam);
221     		if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
222     			return -EFAULT;
223     	}
224     	return ret;
225     }
226     
227     asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf)
228     {
229     	int ret;
230     	struct stat s;
231     	mm_segment_t old_fs = get_fs();
232     	int (*sys_newfstat)(unsigned,struct stat *) = 
233     		(int (*)(unsigned,struct stat *))SYS(fstat);
234     	
235     	set_fs (KERNEL_DS);
236     	ret = sys_newfstat(fd, &s);
237     	set_fs (old_fs);
238     	if (putstat ((struct sol_stat *)A(statbuf), &s))
239     		return -EFAULT;
240     	return ret;
241     }
242     
243     asmlinkage int solaris_fxstat(int vers, u32 fd, u32 statbuf)
244     {
245     	return solaris_fstat(fd, statbuf);
246     }
247     
248     asmlinkage int solaris_fstat64(unsigned int fd, u32 statbuf)
249     {
250     	int ret;
251     	struct stat s;
252     	mm_segment_t old_fs = get_fs();
253     	int (*sys_newfstat)(unsigned,struct stat *) = 
254     		(int (*)(unsigned,struct stat *))SYS(fstat);
255     	
256     	set_fs (KERNEL_DS);
257     	ret = sys_newfstat(fd, &s);
258     	set_fs (old_fs);
259     	if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
260     		return -EFAULT;
261     	return ret;
262     }
263     
264     asmlinkage int solaris_mknod(u32 path, u32 mode, s32 dev)
265     {
266     	int (*sys_mknod)(const char *,int,dev_t) = 
267     		(int (*)(const char *,int,dev_t))SYS(mknod);
268     	int major, minor;
269     
270     	if ((major = R4_MAJOR(dev)) > 255 || 
271     	    (minor = R4_MINOR(dev)) > 255) return -EINVAL;
272     	return sys_mknod((const char *)A(path), mode, MKDEV(major,minor));
273     }
274     
275     asmlinkage int solaris_xmknod(int vers, u32 path, u32 mode, s32 dev)
276     {
277     	return solaris_mknod(path, mode, dev);
278     }
279     
280     asmlinkage int solaris_getdents64(unsigned int fd, void *dirent, unsigned int count)
281     {
282     	int (*sys_getdents)(unsigned int, void *, unsigned int) =
283     		(int (*)(unsigned int, void *, unsigned int))SYS(getdents);
284     		
285     	return sys_getdents(fd, dirent, count);
286     }
287     
288     /* This statfs thingie probably will go in the near future, but... */
289     
290     struct sol_statfs {
291     	short	f_type;
292     	s32	f_bsize;
293     	s32	f_frsize;
294     	s32	f_blocks;
295     	s32	f_bfree;
296     	u32	f_files;
297     	u32	f_ffree;
298     	char	f_fname[6];
299     	char	f_fpack[6];
300     };
301     
302     asmlinkage int solaris_statfs(u32 path, u32 buf, int len, int fstype)
303     {
304     	int ret;
305     	struct statfs s;
306     	mm_segment_t old_fs = get_fs();
307     	int (*sys_statfs)(const char *,struct statfs *) = 
308     		(int (*)(const char *,struct statfs *))SYS(statfs);
309     	struct sol_statfs *ss = (struct sol_statfs *)A(buf);
310     	
311     	if (len != sizeof(struct sol_statfs)) return -EINVAL;
312     	if (!fstype) {
313     		set_fs (KERNEL_DS);
314     		ret = sys_statfs((const char *)A(path), &s);
315     		set_fs (old_fs);
316     		if (!ret) {
317     			if (put_user (s.f_type, &ss->f_type)		||
318     			    __put_user (s.f_bsize, &ss->f_bsize)	||
319     			    __put_user (0, &ss->f_frsize)		||
320     			    __put_user (s.f_blocks, &ss->f_blocks)	||
321     			    __put_user (s.f_bfree, &ss->f_bfree)	||
322     			    __put_user (s.f_files, &ss->f_files)	||
323     			    __put_user (s.f_ffree, &ss->f_ffree)	||
324     			    __clear_user (&ss->f_fname, 12))
325     				return -EFAULT;
326     		}
327     		return ret;
328     	}
329     /* Linux can't stat unmounted filesystems so we
330      * simply lie and claim 100MB of 1GB is free. Sorry.
331      */
332     	if (put_user (fstype, &ss->f_type)		||
333     	    __put_user (1024, &ss->f_bsize)		||
334     	    __put_user (0, &ss->f_frsize)		||
335     	    __put_user (1024*1024, &ss->f_blocks)	||
336     	    __put_user (100*1024, &ss->f_bfree)		||
337     	    __put_user (60000, &ss->f_files)		||
338     	    __put_user (50000, &ss->f_ffree)		||
339     	    __clear_user (&ss->f_fname, 12))
340     		return -EFAULT;
341     	return 0;
342     }
343     
344     asmlinkage int solaris_fstatfs(u32 fd, u32 buf, int len, int fstype)
345     {
346     	int ret;
347     	struct statfs s;
348     	mm_segment_t old_fs = get_fs();
349     	int (*sys_fstatfs)(unsigned,struct statfs *) = 
350     		(int (*)(unsigned,struct statfs *))SYS(fstatfs);
351     	struct sol_statfs *ss = (struct sol_statfs *)A(buf);
352     	
353     	if (len != sizeof(struct sol_statfs)) return -EINVAL;
354     	if (!fstype) {
355     		set_fs (KERNEL_DS);
356     		ret = sys_fstatfs(fd, &s);
357     		set_fs (old_fs);
358     		if (!ret) {
359     			if (put_user (s.f_type, &ss->f_type)		||
360     			    __put_user (s.f_bsize, &ss->f_bsize)	||
361     			    __put_user (0, &ss->f_frsize)		||
362     			    __put_user (s.f_blocks, &ss->f_blocks)	||
363     			    __put_user (s.f_bfree, &ss->f_bfree)	||
364     			    __put_user (s.f_files, &ss->f_files)	||
365     			    __put_user (s.f_ffree, &ss->f_ffree)	||
366     			    __clear_user (&ss->f_fname, 12))
367     				return -EFAULT;
368     		}
369     		return ret;
370     	}
371     	/* Otherwise fstatfs is the same as statfs */
372     	return solaris_statfs(0, buf, len, fstype);
373     }
374     
375     struct sol_statvfs {
376     	u32	f_bsize;
377     	u32	f_frsize;
378     	u32	f_blocks;
379     	u32	f_bfree;
380     	u32	f_bavail;
381     	u32	f_files;
382     	u32	f_ffree;
383     	u32	f_favail;
384     	u32	f_fsid;
385     	char	f_basetype[16];
386     	u32	f_flag;
387     	u32	f_namemax;
388     	char	f_fstr[32];
389     	u32	f_filler[16];
390     };
391     
392     struct sol_statvfs64 {
393     	u32	f_bsize;
394     	u32	f_frsize;
395     	u64	f_blocks;
396     	u64	f_bfree;
397     	u64	f_bavail;
398     	u64	f_files;
399     	u64	f_ffree;
400     	u64	f_favail;
401     	u32	f_fsid;
402     	char	f_basetype[16];
403     	u32	f_flag;
404     	u32	f_namemax;
405     	char	f_fstr[32];
406     	u32	f_filler[16];
407     };
408     
409     static int report_statvfs(struct vfsmount *mnt, struct inode *inode, u32 buf)
410     {
411     	struct statfs s;
412     	int error;
413     	struct sol_statvfs *ss = (struct sol_statvfs *)A(buf);
414     
415     	error = vfs_statfs(mnt->mnt_sb, &s);
416     	if (!error) {
417     		const char *p = mnt->mnt_sb->s_type->name;
418     		int i = 0;
419     		int j = strlen (p);
420     		
421     		if (j > 15) j = 15;
422     		if (IS_RDONLY(inode)) i = 1;
423     		if (mnt->mnt_flags & MNT_NOSUID) i |= 2;
424     		if (put_user (s.f_bsize, &ss->f_bsize)		||
425     		    __put_user (0, &ss->f_frsize)		||
426     		    __put_user (s.f_blocks, &ss->f_blocks)	||
427     		    __put_user (s.f_bfree, &ss->f_bfree)	||
428     		    __put_user (s.f_bavail, &ss->f_bavail)	||
429     		    __put_user (s.f_files, &ss->f_files)	||
430     		    __put_user (s.f_ffree, &ss->f_ffree)	||
431     		    __put_user (s.f_ffree, &ss->f_favail)	||
432     		    __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
433     		    __copy_to_user (ss->f_basetype,p,j)		||
434     		    __put_user (0, (char *)&ss->f_basetype[j])	||
435     		    __put_user (s.f_namelen, &ss->f_namemax)	||
436     		    __put_user (i, &ss->f_flag)			||		    
437     		    __clear_user (&ss->f_fstr, 32))
438     			return -EFAULT;
439     	}
440     	return error;
441     }
442     
443     static int report_statvfs64(struct vfsmount *mnt, struct inode *inode, u32 buf)
444     {
445     	struct statfs s;
446     	int error;
447     	struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf);
448     			
449     	error = vfs_statfs(mnt->mnt_sb, &s);
450     	if (!error) {
451     		const char *p = mnt->mnt_sb->s_type->name;
452     		int i = 0;
453     		int j = strlen (p);
454     		
455     		if (j > 15) j = 15;
456     		if (IS_RDONLY(inode)) i = 1;
457     		if (mnt->mnt_flags & MNT_NOSUID) i |= 2;
458     		if (put_user (s.f_bsize, &ss->f_bsize)		||
459     		    __put_user (0, &ss->f_frsize)		||
460     		    __put_user (s.f_blocks, &ss->f_blocks)	||
461     		    __put_user (s.f_bfree, &ss->f_bfree)	||
462     		    __put_user (s.f_bavail, &ss->f_bavail)	||
463     		    __put_user (s.f_files, &ss->f_files)	||
464     		    __put_user (s.f_ffree, &ss->f_ffree)	||
465     		    __put_user (s.f_ffree, &ss->f_favail)	||
466     		    __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) ||
467     		    __copy_to_user (ss->f_basetype,p,j)		||
468     		    __put_user (0, (char *)&ss->f_basetype[j])	||
469     		    __put_user (s.f_namelen, &ss->f_namemax)	||
470     		    __put_user (i, &ss->f_flag)			||		    
471     		    __clear_user (&ss->f_fstr, 32))
472     			return -EFAULT;
473     	}
474     	return error;
475     }
476     
477     asmlinkage int solaris_statvfs(u32 path, u32 buf)
478     {
479     	struct nameidata nd;
480     	int error;
481     
482     	error = user_path_walk((const char *)A(path),&nd);
483     	if (!error) {
484     		struct inode * inode = nd.dentry->d_inode;
485     		error = report_statvfs(nd.mnt, inode, buf);
486     		path_release(&nd);
487     	}
488     	return error;
489     }
490     
491     asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf)
492     {
493     	struct file * file;
494     	int error;
495     
496     	error = -EBADF;
497     	file = fget(fd);
498     	if (file) {
499     		error = report_statvfs(file->f_vfsmnt, file->f_dentry->d_inode, buf);
500     		fput(file);
501     	}
502     
503     	return error;
504     }
505     
506     asmlinkage int solaris_statvfs64(u32 path, u32 buf)
507     {
508     	struct nameidata nd;
509     	int error;
510     
511     	lock_kernel();
512     	error = user_path_walk((const char *)A(path), &nd);
513     	if (!error) {
514     		struct inode * inode = nd.dentry->d_inode;
515     		error = report_statvfs64(nd.mnt, inode, buf);
516     		path_release(&nd);
517     	}
518     	unlock_kernel();
519     	return error;
520     }
521     
522     asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf)
523     {
524     	struct file * file;
525     	int error;
526     
527     	error = -EBADF;
528     	file = fget(fd);
529     	if (file) {
530     		lock_kernel();
531     		error = report_statvfs64(file->f_vfsmnt, file->f_dentry->d_inode, buf);
532     		unlock_kernel();
533     		fput(file);
534     	}
535     	return error;
536     }
537     
538     extern asmlinkage long sparc32_open(const char * filename, int flags, int mode);
539     
540     asmlinkage int solaris_open(u32 fname, int flags, u32 mode)
541     {
542     	const char *filename = (const char *)(long)fname;
543     	int fl = flags & 0xf;
544     
545     	/* Translate flags first. */
546     	if (flags & 0x2000) fl |= O_LARGEFILE;
547     	if (flags & 0x8050) fl |= O_SYNC;
548     	if (flags & 0x80) fl |= O_NONBLOCK;
549     	if (flags & 0x100) fl |= O_CREAT;
550     	if (flags & 0x200) fl |= O_TRUNC;
551     	if (flags & 0x400) fl |= O_EXCL;
552     	if (flags & 0x800) fl |= O_NOCTTY;
553     	flags = fl;
554     
555     	return sparc32_open(filename, flags, mode);
556     }
557     
558     #define SOL_F_SETLK	6
559     #define SOL_F_SETLKW	7
560     #define SOL_F_FREESP    11
561     #define SOL_F_ISSTREAM  13
562     #define SOL_F_GETLK     14
563     #define SOL_F_PRIV      15
564     #define SOL_F_NPRIV     16
565     #define SOL_F_QUOTACTL  17
566     #define SOL_F_BLOCKS    18
567     #define SOL_F_BLKSIZE   19
568     #define SOL_F_GETOWN    23
569     #define SOL_F_SETOWN    24
570     
571     struct sol_flock {
572     	short	l_type;
573     	short	l_whence;
574     	u32	l_start;
575     	u32	l_len;
576     	s32	l_sysid;
577     	s32	l_pid;
578     	s32	l_pad[4];
579     };
580     
581     asmlinkage int solaris_fcntl(unsigned fd, unsigned cmd, u32 arg)
582     {
583     	int (*sys_fcntl)(unsigned,unsigned,unsigned long) = 
584     		(int (*)(unsigned,unsigned,unsigned long))SYS(fcntl);
585     	int ret, flags;
586     
587     	switch (cmd) {
588     	case F_DUPFD:
589     	case F_GETFD:
590     	case F_SETFD: return sys_fcntl(fd, cmd, (unsigned long)arg);
591     	case F_GETFL:
592     		flags = sys_fcntl(fd, cmd, 0);
593     		ret = flags & 0xf;
594     		if (flags & O_SYNC) ret |= 0x8050;
595     		if (flags & O_NONBLOCK) ret |= 0x80;
596     		return ret;
597     	case F_SETFL:
598     		flags = arg & 0xf;
599     		if (arg & 0x8050) flags |= O_SYNC;
600     		if (arg & 0x80) flags |= O_NONBLOCK;
601     		return sys_fcntl(fd, cmd, (long)flags);
602     	case SOL_F_GETLK:
603     	case SOL_F_SETLK:
604     	case SOL_F_SETLKW:
605     		{
606     			struct flock f;
607     			mm_segment_t old_fs = get_fs();
608     
609     			switch (cmd) {
610     			case SOL_F_GETLK: cmd = F_GETLK; break;
611     			case SOL_F_SETLK: cmd = F_SETLK; break;
612     			case SOL_F_SETLKW: cmd = F_SETLKW; break;
613     			}
614     
615     			if (get_user (f.l_type, &((struct sol_flock *)A(arg))->l_type) ||
616     			    __get_user (f.l_whence, &((struct sol_flock *)A(arg))->l_whence) ||
617     			    __get_user (f.l_start, &((struct sol_flock *)A(arg))->l_start) ||
618     			    __get_user (f.l_len, &((struct sol_flock *)A(arg))->l_len) ||
619     			    __get_user (f.l_pid, &((struct sol_flock *)A(arg))->l_sysid))
620     				return -EFAULT;
621     
622     			set_fs(KERNEL_DS);
623     			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
624     			set_fs(old_fs);
625     
626     			if (__put_user (f.l_type, &((struct sol_flock *)A(arg))->l_type) ||
627     			    __put_user (f.l_whence, &((struct sol_flock *)A(arg))->l_whence) ||
628     			    __put_user (f.l_start, &((struct sol_flock *)A(arg))->l_start) ||
629     			    __put_user (f.l_len, &((struct sol_flock *)A(arg))->l_len) ||
630     			    __put_user (f.l_pid, &((struct sol_flock *)A(arg))->l_pid) ||
631     			    __put_user (0, &((struct sol_flock *)A(arg))->l_sysid))
632     				return -EFAULT;
633     
634     			return ret;
635     		}
636     	case SOL_F_FREESP:
637     	        { 
638     		    int length;
639     		    int (*sys_newftruncate)(unsigned int, unsigned long)=
640     			    (int (*)(unsigned int, unsigned long))SYS(ftruncate);
641     
642     		    if (get_user(length, &((struct sol_flock*)A(arg))->l_start))
643     			    return -EFAULT;
644     
645     		    return sys_newftruncate(fd, length);
646     		}
647     	};
648     	return -EINVAL;
649     }
650     
651     asmlinkage int solaris_ulimit(int cmd, int val)
652     {
653     	switch (cmd) {
654     	case 1: /* UL_GETFSIZE - in 512B chunks */
655     		return current->rlim[RLIMIT_FSIZE].rlim_cur >> 9;
656     	case 2: /* UL_SETFSIZE */
657     		if ((unsigned long)val > (LONG_MAX>>9)) return -ERANGE;
658     		val <<= 9;
659     		lock_kernel();
660     		if (val > current->rlim[RLIMIT_FSIZE].rlim_max) {
661     			if (!capable(CAP_SYS_RESOURCE)) {
662     				unlock_kernel();
663     				return -EPERM;
664     			}
665     			current->rlim[RLIMIT_FSIZE].rlim_max = val;
666     		}
667     		current->rlim[RLIMIT_FSIZE].rlim_cur = val;
668     		unlock_kernel();
669     		return 0;
670     	case 3: /* UL_GMEMLIM */
671     		return current->rlim[RLIMIT_DATA].rlim_cur;
672     	case 4: /* UL_GDESLIM */
673     		return NR_OPEN;
674     	}
675     	return -EINVAL;
676     }
677     
678     /* At least at the time I'm writing this, Linux doesn't have ACLs, so we
679        just fake this */
680     asmlinkage int solaris_acl(u32 filename, int cmd, int nentries, u32 aclbufp)
681     {
682     	return -ENOSYS;
683     }
684     
685     asmlinkage int solaris_facl(unsigned int fd, int cmd, int nentries, u32 aclbufp)
686     {
687     	return -ENOSYS;
688     }
689     
690     asmlinkage int solaris_pread(unsigned int fd, char *buf, u32 count, u32 pos)
691     {
692     	ssize_t (*sys_pread)(unsigned int, char *, size_t, loff_t) =
693     		(ssize_t (*)(unsigned int, char *, size_t, loff_t))SYS(pread);
694     		
695     	return sys_pread(fd, buf, count, (loff_t)pos);
696     }
697     
698     asmlinkage int solaris_pwrite(unsigned int fd, char *buf, u32 count, u32 pos)
699     {
700     	ssize_t (*sys_pwrite)(unsigned int, char *, size_t, loff_t) =
701     		(ssize_t (*)(unsigned int, char *, size_t, loff_t))SYS(pwrite);
702     		
703     	return sys_pwrite(fd, buf, count, (loff_t)pos);
704     }
705     
706     /* POSIX.1 names */
707     #define _PC_LINK_MAX    1
708     #define _PC_MAX_CANON   2
709     #define _PC_MAX_INPUT   3
710     #define _PC_NAME_MAX    4
711     #define _PC_PATH_MAX    5
712     #define _PC_PIPE_BUF    6
713     #define _PC_NO_TRUNC    7
714     #define _PC_VDISABLE    8
715     #define _PC_CHOWN_RESTRICTED    9
716     /* POSIX.4 names */
717     #define _PC_ASYNC_IO    10
718     #define _PC_PRIO_IO     11
719     #define _PC_SYNC_IO     12
720     #define _PC_LAST        12
721     
722     /* This is not a real and complete implementation yet, just to keep
723      * the easy Solaris binaries happy.
724      */
725     asmlinkage int solaris_fpathconf(int fd, int name)
726     {
727     	int ret;
728     
729     	switch(name) {
730     	case _PC_LINK_MAX:
731     		ret = LINK_MAX;
732     		break;
733     	case _PC_MAX_CANON:
734     		ret = MAX_CANON;
735     		break;
736     	case _PC_MAX_INPUT:
737     		ret = MAX_INPUT;
738     		break;
739     	case _PC_NAME_MAX:
740     		ret = NAME_MAX;
741     		break;
742     	case _PC_PATH_MAX:
743     		ret = PATH_MAX;
744     		break;
745     	case _PC_PIPE_BUF:
746     		ret = PIPE_BUF;
747     		break;
748     	case _PC_CHOWN_RESTRICTED:
749     		ret = 1;
750     		break;
751     	case _PC_NO_TRUNC:
752     	case _PC_VDISABLE:
753     		ret = 0;
754     		break;
755     	default:
756     		ret = -EINVAL;
757     		break;
758     	}
759     	return ret;
760     }
761     
762     asmlinkage int solaris_pathconf(u32 path, int name)
763     {
764     	return solaris_fpathconf(0, name);
765     }
766     
767     /* solaris_llseek returns long long - quite difficult */
768     asmlinkage long solaris_llseek(struct pt_regs *regs, u32 off_hi, u32 off_lo, int whence)
769     {
770     	int (*sys_llseek)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int) =
771     		(int (*)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int))SYS(_llseek);
772     	int ret;
773     	mm_segment_t old_fs = get_fs();
774     	loff_t retval;
775     	
776     	set_fs(KERNEL_DS);
777     	ret = sys_llseek((unsigned int)regs->u_regs[UREG_I0], off_hi, off_lo, &retval, whence);
778     	set_fs(old_fs);
779     	if (ret < 0) return ret;
780     	regs->u_regs[UREG_I1] = (u32)retval;
781     	return (retval >> 32);
782     }
783     
784     /* Have to mask out all but lower 3 bits */
785     asmlinkage int solaris_access(u32 filename, long mode)
786     {
787     	int (*sys_access)(const char *, int) = 
788     		(int (*)(const char *, int))SYS(access);
789     		
790     	return sys_access((const char *)A(filename), mode & 7);
791     }
792