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