xref: /openbmc/qemu/bsd-user/freebsd/os-stat.h (revision 5f88dd43)
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 int freebsd11_fstat(int fd, struct freebsd11_stat *stat);
28 __sym_compat(fstat, freebsd11_fstat, FBSD_1.0);
29 int freebsd11_fstatat(int fd, const char *path, struct freebsd11_stat *stat,
30         int flag);
31 __sym_compat(fstatat, freebsd11_fstatat, FBSD_1.1);
32 
33 int freebsd11_fhstat(const fhandle_t *fhandle, struct freebsd11_stat *stat);
34 __sym_compat(fhstat, freebsd11_fhstat, FBSD_1.0);
35 int freebsd11_getfsstat(struct freebsd11_statfs *buf, long bufsize, int mode);
36 __sym_compat(getfsstat, freebsd11_getfsstat, FBSD_1.0);
37 int freebsd11_fhstatfs(const fhandle_t *fhandle, struct freebsd11_statfs * buf);
38 __sym_compat(fhstatfs, freebsd11_fhstatfs, FBSD_1.0);
39 int freebsd11_statfs(const char *path, struct freebsd11_statfs *buf);
40 __sym_compat(statfs, freebsd11_statfs, FBSD_1.0);
41 int freebsd11_fstatfs(int fd, struct freebsd11_statfs *buf);
42 __sym_compat(fstatfs, freebsd11_fstatfs, FBSD_1.0);
43 
44 ssize_t freebsd11_getdirentries(int fd, char *buf, size_t nbytes, off_t *basep);
45 __sym_compat(getdirentries, freebsd11_getdirentries, FBSD_1.0);
46 ssize_t freebsd11_getdents(int fd, char *buf, size_t nbytes);
47 __sym_compat(getdents, freebsd11_getdents, FBSD_1.0);
48 
49 /* undocumented nstat system calls */
50 int freebsd11_nstat(const char *path, struct freebsd11_stat *sb);
51 __sym_compat(nstat, freebsd11_nstat, FBSD_1.0);
52 int freebsd11_nlstat(const char *path, struct freebsd11_stat *sb);
53 __sym_compat(nlstat, freebsd11_nlstat, FBSD_1.0);
54 int freebsd11_nfstat(int fd, struct freebsd11_stat *sb);
55 __sym_compat(nfstat, freebsd11_nfstat, FBSD_1.0);
56 
57 /* stat(2) */
58 static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2)
59 {
60     abi_long ret;
61     void *p;
62     struct freebsd11_stat st;
63 
64     LOCK_PATH(p, arg1);
65     ret = get_errno(freebsd11_stat(path(p), &st));
66     UNLOCK_PATH(p, arg1);
67     if (!is_error(ret)) {
68         ret = h2t_freebsd11_stat(arg2, &st);
69     }
70     return ret;
71 }
72 
73 /* lstat(2) */
74 static inline abi_long do_freebsd11_lstat(abi_long arg1, abi_long arg2)
75 {
76     abi_long ret;
77     void *p;
78     struct freebsd11_stat st;
79 
80     LOCK_PATH(p, arg1);
81     ret = get_errno(freebsd11_lstat(path(p), &st));
82     UNLOCK_PATH(p, arg1);
83     if (!is_error(ret)) {
84         ret = h2t_freebsd11_stat(arg2, &st);
85     }
86     return ret;
87 }
88 
89 /* fstat(2) */
90 static inline abi_long do_freebsd11_fstat(abi_long arg1, abi_long arg2)
91 {
92     abi_long ret;
93     struct freebsd11_stat st;
94 
95     ret = get_errno(freebsd11_fstat(arg1, &st));
96     if (!is_error(ret))  {
97         ret = h2t_freebsd11_stat(arg2, &st);
98     }
99     return ret;
100 }
101 
102 /* fstat(2) */
103 static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
104 {
105     abi_long ret;
106     struct stat st;
107 
108     ret = get_errno(fstat(arg1, &st));
109     if (!is_error(ret))  {
110         ret = h2t_freebsd_stat(arg2, &st);
111     }
112     return ret;
113 }
114 
115 /* fstatat(2) */
116 static inline abi_long do_freebsd11_fstatat(abi_long arg1, abi_long arg2,
117         abi_long arg3, abi_long arg4)
118 {
119     abi_long ret;
120     void *p;
121     struct freebsd11_stat st;
122 
123     LOCK_PATH(p, arg2);
124     ret = get_errno(freebsd11_fstatat(arg1, p, &st, arg4));
125     UNLOCK_PATH(p, arg2);
126     if (!is_error(ret) && arg3) {
127         ret = h2t_freebsd11_stat(arg3, &st);
128     }
129     return ret;
130 }
131 
132 /* fstatat(2) */
133 static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
134         abi_long arg3, abi_long arg4)
135 {
136     abi_long ret;
137     void *p;
138     struct stat st;
139 
140     LOCK_PATH(p, arg2);
141     ret = get_errno(fstatat(arg1, p, &st, arg4));
142     UNLOCK_PATH(p, arg2);
143     if (!is_error(ret) && arg3) {
144         ret = h2t_freebsd_stat(arg3, &st);
145     }
146     return ret;
147 }
148 
149 /* undocummented nstat(char *path, struct nstat *ub) syscall */
150 static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
151 {
152     abi_long ret;
153     void *p;
154     struct freebsd11_stat st;
155 
156     LOCK_PATH(p, arg1);
157     ret = get_errno(freebsd11_nstat(path(p), &st));
158     UNLOCK_PATH(p, arg1);
159     if (!is_error(ret)) {
160         ret = h2t_freebsd11_nstat(arg2, &st);
161     }
162     return ret;
163 }
164 
165 /* undocummented nfstat(int fd, struct nstat *sb) syscall */
166 static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
167 {
168     abi_long ret;
169     struct freebsd11_stat st;
170 
171     ret = get_errno(freebsd11_nfstat(arg1, &st));
172     if (!is_error(ret))  {
173         ret = h2t_freebsd11_nstat(arg2, &st);
174     }
175     return ret;
176 }
177 
178 /* undocummented nlstat(char *path, struct nstat *ub) syscall */
179 static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2)
180 {
181     abi_long ret;
182     void *p;
183     struct freebsd11_stat st;
184 
185     LOCK_PATH(p, arg1);
186     ret = get_errno(freebsd11_nlstat(path(p), &st));
187     UNLOCK_PATH(p, arg1);
188     if (!is_error(ret)) {
189         ret = h2t_freebsd11_nstat(arg2, &st);
190     }
191     return ret;
192 }
193 
194 /* getfh(2) */
195 static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
196 {
197     abi_long ret;
198     void *p;
199     fhandle_t host_fh;
200 
201     LOCK_PATH(p, arg1);
202     ret = get_errno(getfh(path(p), &host_fh));
203     UNLOCK_PATH(p, arg1);
204     if (is_error(ret)) {
205         return ret;
206     }
207     return h2t_freebsd_fhandle(arg2, &host_fh);
208 }
209 
210 /* lgetfh(2) */
211 static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
212 {
213     abi_long ret;
214     void *p;
215     fhandle_t host_fh;
216 
217     LOCK_PATH(p, arg1);
218     ret = get_errno(lgetfh(path(p), &host_fh));
219     UNLOCK_PATH(p, arg1);
220     if (is_error(ret)) {
221         return ret;
222     }
223     return h2t_freebsd_fhandle(arg2, &host_fh);
224 }
225 
226 /* fhopen(2) */
227 static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
228 {
229     abi_long ret;
230     fhandle_t host_fh;
231 
232     ret = t2h_freebsd_fhandle(&host_fh, arg1);
233     if (is_error(ret)) {
234         return ret;
235     }
236 
237     return get_errno(fhopen(&host_fh, arg2));
238 }
239 
240 /* fhstat(2) */
241 static inline abi_long do_freebsd11_fhstat(abi_long arg1, abi_long arg2)
242 {
243     abi_long ret;
244     fhandle_t host_fh;
245     struct freebsd11_stat host_sb;
246 
247     ret = t2h_freebsd_fhandle(&host_fh, arg1);
248     if (is_error(ret)) {
249         return ret;
250     }
251     ret = get_errno(freebsd11_fhstat(&host_fh, &host_sb));
252     if (is_error(ret)) {
253         return ret;
254     }
255     return h2t_freebsd11_stat(arg2, &host_sb);
256 }
257 
258 /* fhstat(2) */
259 static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
260 {
261     abi_long ret;
262     fhandle_t host_fh;
263     struct stat host_sb;
264 
265     ret = t2h_freebsd_fhandle(&host_fh, arg1);
266     if (is_error(ret)) {
267         return ret;
268     }
269     ret = get_errno(fhstat(&host_fh, &host_sb));
270     if (is_error(ret)) {
271         return ret;
272     }
273     return h2t_freebsd_stat(arg2, &host_sb);
274 }
275 
276 /* fhstatfs(2) */
277 static inline abi_long do_freebsd11_fhstatfs(abi_ulong target_fhp_addr,
278         abi_ulong target_stfs_addr)
279 {
280     abi_long ret;
281     fhandle_t host_fh;
282     struct freebsd11_statfs host_stfs;
283 
284     ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
285     if (is_error(ret)) {
286         return ret;
287     }
288     ret = get_errno(freebsd11_fhstatfs(&host_fh, &host_stfs));
289     if (is_error(ret)) {
290         return ret;
291     }
292     return h2t_freebsd11_statfs(target_stfs_addr, &host_stfs);
293 }
294 
295 /* fhstatfs(2) */
296 static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
297         abi_ulong target_stfs_addr)
298 {
299     abi_long ret;
300     fhandle_t host_fh;
301     struct statfs host_stfs;
302 
303     ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
304     if (is_error(ret)) {
305         return ret;
306     }
307     ret = get_errno(fhstatfs(&host_fh, &host_stfs));
308     if (is_error(ret)) {
309         return ret;
310     }
311     return h2t_freebsd_statfs(target_stfs_addr, &host_stfs);
312 }
313 
314 /* statfs(2) */
315 static inline abi_long do_freebsd11_statfs(abi_long arg1, abi_long arg2)
316 {
317     abi_long ret;
318     void *p;
319     struct freebsd11_statfs host_stfs;
320 
321     LOCK_PATH(p, arg1);
322     ret = get_errno(freebsd11_statfs(path(p), &host_stfs));
323     UNLOCK_PATH(p, arg1);
324     if (is_error(ret)) {
325         return ret;
326     }
327 
328     return h2t_freebsd11_statfs(arg2, &host_stfs);
329 }
330 
331 /* statfs(2) */
332 static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
333 {
334     abi_long ret;
335     void *p;
336     struct statfs host_stfs;
337 
338     LOCK_PATH(p, arg1);
339     ret = get_errno(statfs(path(p), &host_stfs));
340     UNLOCK_PATH(p, arg1);
341     if (is_error(ret)) {
342         return ret;
343     }
344 
345     return h2t_freebsd_statfs(arg2, &host_stfs);
346 }
347 
348 /* fstatfs(2) */
349 static inline abi_long do_freebsd11_fstatfs(abi_long fd, abi_ulong target_addr)
350 {
351     abi_long ret;
352     struct freebsd11_statfs host_stfs;
353 
354     ret = get_errno(freebsd11_fstatfs(fd, &host_stfs));
355     if (is_error(ret)) {
356         return ret;
357     }
358 
359     return h2t_freebsd11_statfs(target_addr, &host_stfs);
360 }
361 
362 /* fstatfs(2) */
363 static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
364 {
365     abi_long ret;
366     struct statfs host_stfs;
367 
368     ret = get_errno(fstatfs(fd, &host_stfs));
369     if (is_error(ret)) {
370         return ret;
371     }
372 
373     return h2t_freebsd_statfs(target_addr, &host_stfs);
374 }
375 
376 /* getfsstat(2) */
377 static inline abi_long do_freebsd11_getfsstat(abi_ulong target_addr,
378         abi_long bufsize, abi_long flags)
379 {
380     abi_long ret;
381     struct freebsd11_statfs *host_stfs;
382     int count;
383     long host_bufsize;
384 
385     count = bufsize / sizeof(struct target_freebsd11_statfs);
386 
387     /* if user buffer is NULL then return number of mounted FS's */
388     if (target_addr == 0 || count == 0) {
389         return get_errno(freebsd11_getfsstat(NULL, 0, flags));
390     }
391 
392     /* XXX check count to be reasonable */
393     host_bufsize = sizeof(struct freebsd11_statfs) * count;
394     host_stfs = alloca(host_bufsize);
395     if (!host_stfs) {
396         return -TARGET_EINVAL;
397     }
398 
399     ret = count = get_errno(freebsd11_getfsstat(host_stfs, host_bufsize, flags));
400     if (is_error(ret)) {
401         return ret;
402     }
403 
404     while (count--) {
405         if (h2t_freebsd11_statfs((target_addr +
406                         (count * sizeof(struct target_freebsd11_statfs))),
407                     &host_stfs[count])) {
408             return -TARGET_EFAULT;
409         }
410     }
411     return ret;
412 }
413 
414 /* getfsstat(2) */
415 static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
416         abi_long bufsize, abi_long flags)
417 {
418     abi_long ret;
419     struct statfs *host_stfs;
420     int count;
421     long host_bufsize;
422 
423     count = bufsize / sizeof(struct target_statfs);
424 
425     /* if user buffer is NULL then return number of mounted FS's */
426     if (target_addr == 0 || count == 0) {
427         return get_errno(freebsd11_getfsstat(NULL, 0, flags));
428     }
429 
430     /* XXX check count to be reasonable */
431     host_bufsize = sizeof(struct statfs) * count;
432     host_stfs = alloca(host_bufsize);
433     if (!host_stfs) {
434         return -TARGET_EINVAL;
435     }
436 
437     ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags));
438     if (is_error(ret)) {
439         return ret;
440     }
441 
442     while (count--) {
443         if (h2t_freebsd_statfs((target_addr +
444                         (count * sizeof(struct target_statfs))),
445                     &host_stfs[count])) {
446             return -TARGET_EFAULT;
447         }
448     }
449     return ret;
450 }
451 
452 /* getdents(2) */
453 static inline abi_long do_freebsd11_getdents(abi_long arg1,
454         abi_ulong arg2, abi_long nbytes)
455 {
456     abi_long ret;
457     struct freebsd11_dirent *dirp;
458 
459     dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
460     if (dirp == NULL) {
461         return -TARGET_EFAULT;
462     }
463     ret = get_errno(freebsd11_getdents(arg1, (char *)dirp, nbytes));
464     if (!is_error(ret)) {
465         struct freebsd11_dirent *de;
466         int len = ret;
467         int reclen;
468 
469         de = dirp;
470         while (len > 0) {
471             reclen = de->d_reclen;
472             if (reclen > len) {
473                 return -TARGET_EFAULT;
474             }
475             de->d_reclen = tswap16(reclen);
476             de->d_fileno = tswap32(de->d_fileno);
477             len -= reclen;
478         }
479     }
480     return ret;
481 }
482 
483 /* getdirecentries(2) */
484 static inline abi_long do_freebsd11_getdirentries(abi_long arg1,
485         abi_ulong arg2, abi_long nbytes, abi_ulong arg4)
486 {
487     abi_long ret;
488     struct freebsd11_dirent *dirp;
489     long basep;
490 
491     dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
492     if (dirp == NULL) {
493         return -TARGET_EFAULT;
494     }
495     ret = get_errno(freebsd11_getdirentries(arg1, (char *)dirp, nbytes, &basep));
496     if (!is_error(ret)) {
497         struct freebsd11_dirent *de;
498         int len = ret;
499         int reclen;
500 
501         de = dirp;
502         while (len > 0) {
503             reclen = de->d_reclen;
504             if (reclen > len) {
505                 return -TARGET_EFAULT;
506             }
507             de->d_reclen = tswap16(reclen);
508             de->d_fileno = tswap32(de->d_fileno);
509             len -= reclen;
510             de = (struct freebsd11_dirent *)((void *)de + reclen);
511         }
512     }
513     unlock_user(dirp, arg2, ret);
514     if (arg4) {
515         if (put_user(basep, arg4, abi_ulong)) {
516             return -TARGET_EFAULT;
517         }
518     }
519     return ret;
520 }
521 
522 /* getdirecentries(2) */
523 static inline abi_long do_freebsd_getdirentries(abi_long arg1,
524         abi_ulong arg2, abi_long nbytes, abi_ulong arg4)
525 {
526     abi_long ret;
527     struct dirent *dirp;
528     long basep;
529 
530     dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
531     if (dirp == NULL) {
532         return -TARGET_EFAULT;
533     }
534     ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep));
535     if (!is_error(ret)) {
536         struct dirent *de;
537         int len = ret;
538         int reclen;
539 
540         de = dirp;
541         while (len > 0) {
542             reclen = de->d_reclen;
543             if (reclen > len) {
544                 return -TARGET_EFAULT;
545             }
546             de->d_fileno = tswap64(de->d_fileno);
547             de->d_off = tswap64(de->d_off);
548             de->d_reclen = tswap16(de->d_reclen);
549             de->d_namlen = tswap16(de->d_namlen);
550             len -= reclen;
551             de = (struct dirent *)((void *)de + reclen);
552         }
553     }
554     unlock_user(dirp, arg2, ret);
555     if (arg4) {
556         if (put_user(basep, arg4, abi_ulong)) {
557             return -TARGET_EFAULT;
558         }
559     }
560     return ret;
561 }
562 
563 /* fcntl(2) */
564 static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
565         abi_ulong arg3)
566 {
567     abi_long ret;
568     int host_cmd;
569     struct flock fl;
570     struct target_freebsd_flock *target_fl;
571 
572     host_cmd = target_to_host_fcntl_cmd(arg2);
573     if (host_cmd < 0) {
574         return host_cmd;
575     }
576     switch (arg2) {
577     case TARGET_F_GETLK:
578         if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
579             return -TARGET_EFAULT;
580         }
581         __get_user(fl.l_type, &target_fl->l_type);
582         __get_user(fl.l_whence, &target_fl->l_whence);
583         __get_user(fl.l_start, &target_fl->l_start);
584         __get_user(fl.l_len, &target_fl->l_len);
585         __get_user(fl.l_pid, &target_fl->l_pid);
586         __get_user(fl.l_sysid, &target_fl->l_sysid);
587         unlock_user_struct(target_fl, arg3, 0);
588         ret = get_errno(safe_fcntl(arg1, host_cmd, &fl));
589         if (!is_error(ret)) {
590             if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) {
591                 return -TARGET_EFAULT;
592             }
593             __put_user(fl.l_type, &target_fl->l_type);
594             __put_user(fl.l_whence, &target_fl->l_whence);
595             __put_user(fl.l_start, &target_fl->l_start);
596             __put_user(fl.l_len, &target_fl->l_len);
597             __put_user(fl.l_pid, &target_fl->l_pid);
598             __put_user(fl.l_sysid, &target_fl->l_sysid);
599             unlock_user_struct(target_fl, arg3, 1);
600         }
601         break;
602 
603     case TARGET_F_SETLK:
604     case TARGET_F_SETLKW:
605         if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
606             return -TARGET_EFAULT;
607         }
608         __get_user(fl.l_type, &target_fl->l_type);
609         __get_user(fl.l_whence, &target_fl->l_whence);
610         __get_user(fl.l_start, &target_fl->l_start);
611         __get_user(fl.l_len, &target_fl->l_len);
612         __get_user(fl.l_pid, &target_fl->l_pid);
613         __get_user(fl.l_sysid, &target_fl->l_sysid);
614         unlock_user_struct(target_fl, arg3, 0);
615         ret = get_errno(safe_fcntl(arg1, host_cmd, &fl));
616         break;
617 
618     case TARGET_F_DUPFD:
619     case TARGET_F_DUP2FD:
620     case TARGET_F_GETOWN:
621     case TARGET_F_SETOWN:
622     case TARGET_F_GETFD:
623     case TARGET_F_SETFD:
624     case TARGET_F_GETFL:
625     case TARGET_F_SETFL:
626     case TARGET_F_READAHEAD:
627     case TARGET_F_RDAHEAD:
628     case TARGET_F_ADD_SEALS:
629     case TARGET_F_GET_SEALS:
630     default:
631         ret = get_errno(safe_fcntl(arg1, host_cmd, arg3));
632         break;
633     }
634     return ret;
635 }
636 
637 #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300080
638 extern int __realpathat(int fd, const char *path, char *buf, size_t size,
639         int flags);
640 /* https://svnweb.freebsd.org/base?view=revision&revision=358172 */
641 /* no man page */
642 static inline abi_long do_freebsd_realpathat(abi_long arg1, abi_long arg2,
643         abi_long arg3, abi_long arg4, abi_long arg5)
644 {
645     abi_long ret;
646     void *p, *b;
647 
648     LOCK_PATH(p, arg2);
649     b = lock_user(VERIFY_WRITE, arg3, arg4, 0);
650     if (b == NULL) {
651         UNLOCK_PATH(p, arg2);
652         return -TARGET_EFAULT;
653     }
654 
655     ret = get_errno(__realpathat(arg1, p, b, arg4, arg5));
656     UNLOCK_PATH(p, arg2);
657     unlock_user(b, arg3, ret);
658 
659     return ret;
660 }
661 #endif
662 
663 #endif /* BSD_USER_FREEBSD_OS_STAT_H */
664