1 /*
2  * linux/arch/parisc/kernel/sys_hpux.c
3  *
4  * implements HPUX syscalls.
5  */
6 
7 #include <linux/mm.h>
8 #include <linux/sched.h>
9 #include <linux/file.h>
10 #include <linux/smp_lock.h>
11 #include <linux/slab.h>
12 #include <asm/errno.h>
13 #include <asm/uaccess.h>
14 
hpux_execve(struct pt_regs * regs)15 int hpux_execve(struct pt_regs *regs)
16 {
17 	int error;
18 	char *filename;
19 
20 	filename = getname((char *) regs->gr[26]);
21 	error = PTR_ERR(filename);
22 	if (IS_ERR(filename))
23 		goto out;
24 
25 	error = do_execve(filename, (char **) regs->gr[25],
26 		(char **)regs->gr[24], regs);
27 
28 	if (error == 0)
29 		current->ptrace &= ~PT_DTRACE;
30 	putname(filename);
31 
32 out:
33 	return error;
34 }
35 
36 struct hpux_dirent {
37 	long	d_off_pad; /* we only have a 32-bit off_t */
38 	long	d_off;
39 	ino_t	d_ino;
40 	short	d_reclen;
41 	short	d_namlen;
42 	char	d_name[1];
43 };
44 
45 struct getdents_callback {
46 	struct hpux_dirent *current_dir;
47 	struct hpux_dirent *previous;
48 	int count;
49 	int error;
50 };
51 
52 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
53 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
54 
filldir(void * __buf,const char * name,int namlen,loff_t offset,ino_t ino,unsigned int d_type)55 static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
56 		ino_t ino, unsigned int d_type)
57 {
58 	struct hpux_dirent * dirent;
59 	struct getdents_callback * buf = (struct getdents_callback *) __buf;
60 	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
61 
62 	buf->error = -EINVAL;	/* only used if we fail.. */
63 	if (reclen > buf->count)
64 		return -EINVAL;
65 	dirent = buf->previous;
66 	if (dirent)
67 		put_user(offset, &dirent->d_off);
68 	dirent = buf->current_dir;
69 	buf->previous = dirent;
70 	put_user(ino, &dirent->d_ino);
71 	put_user(reclen, &dirent->d_reclen);
72 	put_user(namlen, &dirent->d_namlen);
73 	copy_to_user(dirent->d_name, name, namlen);
74 	put_user(0, dirent->d_name + namlen);
75 	((char *) dirent) += reclen;
76 	buf->current_dir = dirent;
77 	buf->count -= reclen;
78 	return 0;
79 }
80 
81 #undef NAME_OFFSET
82 #undef ROUND_UP
83 
hpux_getdents(unsigned int fd,struct hpux_dirent * dirent,unsigned int count)84 int hpux_getdents(unsigned int fd, struct hpux_dirent *dirent, unsigned int count)
85 {
86 	struct file * file;
87 	struct hpux_dirent * lastdirent;
88 	struct getdents_callback buf;
89 	int error;
90 
91 	error = -EBADF;
92 	file = fget(fd);
93 	if (!file)
94 		goto out;
95 
96 	buf.current_dir = dirent;
97 	buf.previous = NULL;
98 	buf.count = count;
99 	buf.error = 0;
100 
101 	error = vfs_readdir(file, filldir, &buf);
102 	if (error < 0)
103 		goto out_putf;
104 	error = buf.error;
105 	lastdirent = buf.previous;
106 	if (lastdirent) {
107 		put_user(file->f_pos, &lastdirent->d_off);
108 		error = count - buf.count;
109 	}
110 
111 out_putf:
112 	fput(file);
113 out:
114 	return error;
115 }
116 
hpux_mount(const char * fs,const char * path,int mflag,const char * fstype,const char * dataptr,int datalen)117 int hpux_mount(const char *fs, const char *path, int mflag,
118 		const char *fstype, const char *dataptr, int datalen)
119 {
120 	return -ENOSYS;
121 }
122 
cp_hpux_stat(struct inode * inode,struct hpux_stat64 * statbuf)123 static int cp_hpux_stat(struct inode * inode, struct hpux_stat64 * statbuf)
124 {
125 	struct hpux_stat64 tmp;
126 	unsigned int blocks, indirect;
127 
128 	memset(&tmp, 0, sizeof(tmp));
129 	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
130 	tmp.st_ino = inode->i_ino;
131 	tmp.st_mode = inode->i_mode;
132 	tmp.st_nlink = inode->i_nlink;
133 	tmp.st_uid = inode->i_uid;
134 	tmp.st_gid = inode->i_gid;
135 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
136 	tmp.st_size = inode->i_size;
137 	tmp.st_atime = inode->i_atime;
138 	tmp.st_mtime = inode->i_mtime;
139 	tmp.st_ctime = inode->i_ctime;
140 
141 #define D_B   7
142 #define I_B   (BLOCK_SIZE / sizeof(unsigned short))
143 
144 	if (!inode->i_blksize) {
145 		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
146 		if (blocks > D_B) {
147 			indirect = (blocks - D_B + I_B - 1) / I_B;
148 			blocks += indirect;
149 			if (indirect > 1) {
150 				indirect = (indirect - 1 + I_B - 1) / I_B;
151 				blocks += indirect;
152 				if (indirect > 1)
153 					blocks++;
154 			}
155 		}
156 		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
157 		tmp.st_blksize = BLOCK_SIZE;
158 	} else {
159 		tmp.st_blocks = inode->i_blocks;
160 		tmp.st_blksize = inode->i_blksize;
161 	}
162 	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
163 }
164 
165 /*
166  * Revalidate the inode. This is required for proper NFS attribute caching.
167  * Blatently copied wholesale from fs/stat.c
168  */
169 static __inline__ int
do_revalidate(struct dentry * dentry)170 do_revalidate(struct dentry *dentry)
171 {
172 	struct inode * inode = dentry->d_inode;
173 	if (inode->i_op && inode->i_op->revalidate)
174 		return inode->i_op->revalidate(dentry);
175 	return 0;
176 }
177 
hpux_stat64(const char * path,struct hpux_stat64 * buf)178 long hpux_stat64(const char *path, struct hpux_stat64 *buf)
179 {
180 	struct nameidata nd;
181 	int error;
182 
183 	lock_kernel();
184 	error = user_path_walk(path, &nd);
185 	if (!error) {
186 		error = do_revalidate(nd.dentry);
187 		if (!error)
188 			error = cp_hpux_stat(nd.dentry->d_inode, buf);
189 		path_release(&nd);
190 	}
191 	unlock_kernel();
192 	return error;
193 }
194 
hpux_fstat64(unsigned int fd,struct hpux_stat64 * statbuf)195 long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf)
196 {
197 	struct file * f;
198 	int err = -EBADF;
199 
200 	lock_kernel();
201 	f = fget(fd);
202 	if (f) {
203 		struct dentry * dentry = f->f_dentry;
204 
205 		err = do_revalidate(dentry);
206 		if (!err)
207 			err = cp_hpux_stat(dentry->d_inode, statbuf);
208 		fput(f);
209 	}
210 	unlock_kernel();
211 	return err;
212 }
213 
hpux_lstat64(char * filename,struct hpux_stat64 * statbuf)214 long hpux_lstat64(char *filename, struct hpux_stat64 *statbuf)
215 {
216 	struct nameidata nd;
217 	int error;
218 
219 	lock_kernel();
220 	error = user_path_walk_link(filename, &nd);
221 	if (!error) {
222 		error = do_revalidate(nd.dentry);
223 		if (!error)
224 			error = cp_hpux_stat(nd.dentry->d_inode, statbuf);
225 		path_release(&nd);
226 	}
227 	unlock_kernel();
228 	return error;
229 }
230