xref: /openbmc/qemu/bsd-user/freebsd/os-stat.h (revision b4432977)
1 /*
2  *  stat related system call shims and definitions
3  *
4  *  Copyright (c) 2013 Stacey D. Son
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef BSD_USER_FREEBSD_OS_STAT_H
21 #define BSD_USER_FREEBSD_OS_STAT_H
22 
23 int freebsd11_stat(const char *path, struct freebsd11_stat *stat);
24 __sym_compat(stat, freebsd11_stat, FBSD_1.0);
25 int freebsd11_lstat(const char *path, struct freebsd11_stat *stat);
26 __sym_compat(lstat, freebsd11_lstat, FBSD_1.0);
27 
28 /* stat(2) */
29 static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2)
30 {
31     abi_long ret;
32     void *p;
33     struct freebsd11_stat st;
34 
35     LOCK_PATH(p, arg1);
36     ret = get_errno(freebsd11_stat(path(p), &st));
37     UNLOCK_PATH(p, arg1);
38     if (!is_error(ret)) {
39         ret = h2t_freebsd11_stat(arg2, &st);
40     }
41     return ret;
42 }
43 
44 /* lstat(2) */
45 static inline abi_long do_freebsd11_lstat(abi_long arg1, abi_long arg2)
46 {
47     abi_long ret;
48     void *p;
49     struct freebsd11_stat st;
50 
51     LOCK_PATH(p, arg1);
52     ret = get_errno(freebsd11_lstat(path(p), &st));
53     UNLOCK_PATH(p, arg1);
54     if (!is_error(ret)) {
55         ret = h2t_freebsd11_stat(arg2, &st);
56     }
57     return ret;
58 }
59 
60 /* fstat(2) */
61 static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
62 {
63     abi_long ret;
64     struct stat st;
65 
66     ret = get_errno(fstat(arg1, &st));
67     if (!is_error(ret))  {
68         ret = h2t_freebsd_stat(arg2, &st);
69     }
70     return ret;
71 }
72 
73 /* fstatat(2) */
74 static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
75         abi_long arg3, abi_long arg4)
76 {
77     abi_long ret;
78     void *p;
79     struct stat st;
80 
81     LOCK_PATH(p, arg2);
82     ret = get_errno(fstatat(arg1, p, &st, arg4));
83     UNLOCK_PATH(p, arg2);
84     if (!is_error(ret) && arg3) {
85         ret = h2t_freebsd_stat(arg3, &st);
86     }
87     return ret;
88 }
89 
90 /* undocummented nstat(char *path, struct nstat *ub) syscall */
91 static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
92 {
93     abi_long ret;
94     void *p;
95     struct freebsd11_stat st;
96 
97     LOCK_PATH(p, arg1);
98     ret = get_errno(freebsd11_nstat(path(p), &st));
99     UNLOCK_PATH(p, arg1);
100     if (!is_error(ret)) {
101         ret = h2t_freebsd11_nstat(arg2, &st);
102     }
103     return ret;
104 }
105 
106 /* undocummented nfstat(int fd, struct nstat *sb) syscall */
107 static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
108 {
109     abi_long ret;
110     struct freebsd11_stat st;
111 
112     ret = get_errno(freebsd11_nfstat(arg1, &st));
113     if (!is_error(ret))  {
114         ret = h2t_freebsd11_nstat(arg2, &st);
115     }
116     return ret;
117 }
118 
119 /* undocummented nlstat(char *path, struct nstat *ub) syscall */
120 static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2)
121 {
122     abi_long ret;
123     void *p;
124     struct freebsd11_stat st;
125 
126     LOCK_PATH(p, arg1);
127     ret = get_errno(freebsd11_nlstat(path(p), &st));
128     UNLOCK_PATH(p, arg1);
129     if (!is_error(ret)) {
130         ret = h2t_freebsd11_nstat(arg2, &st);
131     }
132     return ret;
133 }
134 
135 /* getfh(2) */
136 static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
137 {
138     abi_long ret;
139     void *p;
140     fhandle_t host_fh;
141 
142     LOCK_PATH(p, arg1);
143     ret = get_errno(getfh(path(p), &host_fh));
144     UNLOCK_PATH(p, arg1);
145     if (is_error(ret)) {
146         return ret;
147     }
148     return h2t_freebsd_fhandle(arg2, &host_fh);
149 }
150 
151 /* lgetfh(2) */
152 static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
153 {
154     abi_long ret;
155     void *p;
156     fhandle_t host_fh;
157 
158     LOCK_PATH(p, arg1);
159     ret = get_errno(lgetfh(path(p), &host_fh));
160     UNLOCK_PATH(p, arg1);
161     if (is_error(ret)) {
162         return ret;
163     }
164     return h2t_freebsd_fhandle(arg2, &host_fh);
165 }
166 
167 /* fhopen(2) */
168 static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
169 {
170     abi_long ret;
171     fhandle_t host_fh;
172 
173     ret = t2h_freebsd_fhandle(&host_fh, arg1);
174     if (is_error(ret)) {
175         return ret;
176     }
177 
178     return get_errno(fhopen(&host_fh, arg2));
179 }
180 
181 /* fhstat(2) */
182 static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
183 {
184     abi_long ret;
185     fhandle_t host_fh;
186     struct stat host_sb;
187 
188     ret = t2h_freebsd_fhandle(&host_fh, arg1);
189     if (is_error(ret)) {
190         return ret;
191     }
192     ret = get_errno(fhstat(&host_fh, &host_sb));
193     if (is_error(ret)) {
194         return ret;
195     }
196     return h2t_freebsd_stat(arg2, &host_sb);
197 }
198 
199 /* fhstatfs(2) */
200 static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
201         abi_ulong target_stfs_addr)
202 {
203     abi_long ret;
204     fhandle_t host_fh;
205     struct statfs host_stfs;
206 
207     ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
208     if (is_error(ret)) {
209         return ret;
210     }
211     ret = get_errno(fhstatfs(&host_fh, &host_stfs));
212     if (is_error(ret)) {
213         return ret;
214     }
215     return h2t_freebsd_statfs(target_stfs_addr, &host_stfs);
216 }
217 
218 /* statfs(2) */
219 static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
220 {
221     abi_long ret;
222     void *p;
223     struct statfs host_stfs;
224 
225     LOCK_PATH(p, arg1);
226     ret = get_errno(statfs(path(p), &host_stfs));
227     UNLOCK_PATH(p, arg1);
228     if (is_error(ret)) {
229         return ret;
230     }
231 
232     return h2t_freebsd_statfs(arg2, &host_stfs);
233 }
234 
235 /* fstatfs(2) */
236 static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
237 {
238     abi_long ret;
239     struct statfs host_stfs;
240 
241     ret = get_errno(fstatfs(fd, &host_stfs));
242     if (is_error(ret)) {
243         return ret;
244     }
245 
246     return h2t_freebsd_statfs(target_addr, &host_stfs);
247 }
248 
249 /* getfsstat(2) */
250 static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
251         abi_long bufsize, abi_long flags)
252 {
253     abi_long ret;
254     struct statfs *host_stfs;
255     int count;
256     long host_bufsize;
257 
258     count = bufsize / sizeof(struct target_statfs);
259 
260     /* if user buffer is NULL then return number of mounted FS's */
261     if (target_addr == 0 || count == 0) {
262         return get_errno(freebsd11_getfsstat(NULL, 0, flags));
263     }
264 
265     /* XXX check count to be reasonable */
266     host_bufsize = sizeof(struct statfs) * count;
267     host_stfs = alloca(host_bufsize);
268     if (!host_stfs) {
269         return -TARGET_EINVAL;
270     }
271 
272     ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags));
273     if (is_error(ret)) {
274         return ret;
275     }
276 
277     while (count--) {
278         if (h2t_freebsd_statfs((target_addr +
279                         (count * sizeof(struct target_statfs))),
280                     &host_stfs[count])) {
281             return -TARGET_EFAULT;
282         }
283     }
284     return ret;
285 }
286 
287 /* getdents(2) */
288 static inline abi_long do_freebsd11_getdents(abi_long arg1,
289         abi_ulong arg2, abi_long nbytes)
290 {
291     abi_long ret;
292     struct freebsd11_dirent *dirp;
293 
294     dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
295     if (dirp == NULL) {
296         return -TARGET_EFAULT;
297     }
298     ret = get_errno(freebsd11_getdents(arg1, (char *)dirp, nbytes));
299     if (!is_error(ret)) {
300         struct freebsd11_dirent *de;
301         int len = ret;
302         int reclen;
303 
304         de = dirp;
305         while (len > 0) {
306             reclen = de->d_reclen;
307             if (reclen > len) {
308                 return -TARGET_EFAULT;
309             }
310             de->d_reclen = tswap16(reclen);
311             de->d_fileno = tswap32(de->d_fileno);
312             len -= reclen;
313         }
314     }
315     return ret;
316 }
317 
318 /* getdirecentries(2) */
319 static inline abi_long do_freebsd_getdirentries(abi_long arg1,
320         abi_ulong arg2, abi_long nbytes, abi_ulong arg4)
321 {
322     abi_long ret;
323     struct dirent *dirp;
324     long basep;
325 
326     dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
327     if (dirp == NULL) {
328         return -TARGET_EFAULT;
329     }
330     ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep));
331     if (!is_error(ret)) {
332         struct dirent *de;
333         int len = ret;
334         int reclen;
335 
336         de = dirp;
337         while (len > 0) {
338             reclen = de->d_reclen;
339             if (reclen > len) {
340                 return -TARGET_EFAULT;
341             }
342             de->d_fileno = tswap64(de->d_fileno);
343             de->d_off = tswap64(de->d_off);
344             de->d_reclen = tswap16(de->d_reclen);
345             de->d_namlen = tswap16(de->d_namlen);
346             len -= reclen;
347             de = (struct dirent *)((void *)de + reclen);
348         }
349     }
350     unlock_user(dirp, arg2, ret);
351     if (arg4) {
352         if (put_user(basep, arg4, abi_ulong)) {
353             return -TARGET_EFAULT;
354         }
355     }
356     return ret;
357 }
358 
359 /* fcntl(2) */
360 static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
361         abi_ulong arg3)
362 {
363     abi_long ret;
364     int host_cmd;
365     struct flock fl;
366     struct target_freebsd_flock *target_fl;
367 
368     host_cmd = target_to_host_fcntl_cmd(arg2);
369     if (host_cmd < 0) {
370         return host_cmd;
371     }
372     switch (arg2) {
373     case TARGET_F_GETLK:
374         if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
375             return -TARGET_EFAULT;
376         }
377         __get_user(fl.l_type, &target_fl->l_type);
378         __get_user(fl.l_whence, &target_fl->l_whence);
379         __get_user(fl.l_start, &target_fl->l_start);
380         __get_user(fl.l_len, &target_fl->l_len);
381         __get_user(fl.l_pid, &target_fl->l_pid);
382         __get_user(fl.l_sysid, &target_fl->l_sysid);
383         unlock_user_struct(target_fl, arg3, 0);
384         ret = get_errno(safe_fcntl(arg1, host_cmd, &fl));
385         if (!is_error(ret)) {
386             if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) {
387                 return -TARGET_EFAULT;
388             }
389             __put_user(fl.l_type, &target_fl->l_type);
390             __put_user(fl.l_whence, &target_fl->l_whence);
391             __put_user(fl.l_start, &target_fl->l_start);
392             __put_user(fl.l_len, &target_fl->l_len);
393             __put_user(fl.l_pid, &target_fl->l_pid);
394             __put_user(fl.l_sysid, &target_fl->l_sysid);
395             unlock_user_struct(target_fl, arg3, 1);
396         }
397         break;
398 
399     case TARGET_F_SETLK:
400     case TARGET_F_SETLKW:
401         if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
402             return -TARGET_EFAULT;
403         }
404         __get_user(fl.l_type, &target_fl->l_type);
405         __get_user(fl.l_whence, &target_fl->l_whence);
406         __get_user(fl.l_start, &target_fl->l_start);
407         __get_user(fl.l_len, &target_fl->l_len);
408         __get_user(fl.l_pid, &target_fl->l_pid);
409         __get_user(fl.l_sysid, &target_fl->l_sysid);
410         unlock_user_struct(target_fl, arg3, 0);
411         ret = get_errno(safe_fcntl(arg1, host_cmd, &fl));
412         break;
413 
414     case TARGET_F_DUPFD:
415     case TARGET_F_DUP2FD:
416     case TARGET_F_GETOWN:
417     case TARGET_F_SETOWN:
418     case TARGET_F_GETFD:
419     case TARGET_F_SETFD:
420     case TARGET_F_GETFL:
421     case TARGET_F_SETFL:
422     case TARGET_F_READAHEAD:
423     case TARGET_F_RDAHEAD:
424     case TARGET_F_ADD_SEALS:
425     case TARGET_F_GET_SEALS:
426     default:
427         ret = get_errno(safe_fcntl(arg1, host_cmd, arg3));
428         break;
429     }
430     return ret;
431 }
432 
433 #endif /* BSD_USER_FREEBSD_OS_STAT_H */
434