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