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