1 /* $NetBSD: vfs_syscalls_50.c,v 1.8 2011/03/24 17:05:44 bouyer Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_50.c,v 1.8 2011/03/24 17:05:44 bouyer Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/namei.h> 44 #include <sys/filedesc.h> 45 #include <sys/kernel.h> 46 #include <sys/file.h> 47 #include <sys/stat.h> 48 #include <sys/socketvar.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/proc.h> 52 #include <sys/uio.h> 53 #include <sys/dirent.h> 54 #include <sys/malloc.h> 55 #include <sys/kauth.h> 56 #include <sys/time.h> 57 #include <sys/vfs_syscalls.h> 58 #ifndef LFS 59 #define LFS 60 #endif 61 #include <sys/syscallargs.h> 62 63 #include <ufs/lfs/lfs_extern.h> 64 65 #include <compat/common/compat_util.h> 66 #include <compat/sys/time.h> 67 #include <compat/sys/stat.h> 68 #include <compat/sys/dirent.h> 69 #include <compat/sys/mount.h> 70 71 static void cvtstat(struct stat30 *, const struct stat *); 72 73 /* 74 * Convert from a new to an old stat structure. 75 */ 76 static void 77 cvtstat(struct stat30 *ost, const struct stat *st) 78 { 79 80 ost->st_dev = st->st_dev; 81 ost->st_ino = st->st_ino; 82 ost->st_mode = st->st_mode; 83 ost->st_nlink = st->st_nlink; 84 ost->st_uid = st->st_uid; 85 ost->st_gid = st->st_gid; 86 ost->st_rdev = st->st_rdev; 87 timespec_to_timespec50(&st->st_atimespec, &ost->st_atimespec); 88 timespec_to_timespec50(&st->st_mtimespec, &ost->st_mtimespec); 89 timespec_to_timespec50(&st->st_ctimespec, &ost->st_ctimespec); 90 timespec_to_timespec50(&st->st_birthtimespec, &ost->st_birthtimespec); 91 ost->st_size = st->st_size; 92 ost->st_blocks = st->st_blocks; 93 ost->st_blksize = st->st_blksize; 94 ost->st_flags = st->st_flags; 95 ost->st_gen = st->st_gen; 96 memset(ost->st_spare, 0, sizeof(ost->st_spare)); 97 } 98 99 /* 100 * Get file status; this version follows links. 101 */ 102 /* ARGSUSED */ 103 int 104 compat_50_sys___stat30(struct lwp *l, const struct compat_50_sys___stat30_args *uap, register_t *retval) 105 { 106 /* { 107 syscallarg(const char *) path; 108 syscallarg(struct stat30 *) ub; 109 } */ 110 struct stat sb; 111 struct stat30 osb; 112 int error; 113 114 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); 115 if (error) 116 return error; 117 cvtstat(&osb, &sb); 118 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 119 return error; 120 } 121 122 123 /* 124 * Get file status; this version does not follow links. 125 */ 126 /* ARGSUSED */ 127 int 128 compat_50_sys___lstat30(struct lwp *l, const struct compat_50_sys___lstat30_args *uap, register_t *retval) 129 { 130 /* { 131 syscallarg(const char *) path; 132 syscallarg(struct stat30 *) ub; 133 } */ 134 struct stat sb; 135 struct stat30 osb; 136 int error; 137 138 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); 139 if (error) 140 return error; 141 cvtstat(&osb, &sb); 142 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 143 return error; 144 } 145 146 /* 147 * Return status information about a file descriptor. 148 */ 149 /* ARGSUSED */ 150 int 151 compat_50_sys___fstat30(struct lwp *l, const struct compat_50_sys___fstat30_args *uap, register_t *retval) 152 { 153 /* { 154 syscallarg(int) fd; 155 syscallarg(struct stat30 *) sb; 156 } */ 157 struct stat sb; 158 struct stat30 osb; 159 int error; 160 161 error = do_sys_fstat(SCARG(uap, fd), &sb); 162 if (error) 163 return error; 164 cvtstat(&osb, &sb); 165 error = copyout(&osb, SCARG(uap, sb), sizeof (osb)); 166 return error; 167 } 168 169 /* ARGSUSED */ 170 int 171 compat_50_sys___fhstat40(struct lwp *l, const struct compat_50_sys___fhstat40_args *uap, register_t *retval) 172 { 173 /* { 174 syscallarg(const void *) fhp; 175 syscallarg(size_t) fh_size; 176 syscallarg(struct stat30 *) sb; 177 } */ 178 struct stat sb; 179 struct stat30 osb; 180 int error; 181 182 error = do_fhstat(l, SCARG(uap, fhp), SCARG(uap, fh_size), &sb); 183 if (error) 184 return error; 185 cvtstat(&osb, &sb); 186 error = copyout(&osb, SCARG(uap, sb), sizeof (osb)); 187 return error; 188 } 189 190 static int 191 compat_50_do_sys_utimes(struct lwp *l, struct vnode *vp, const char *path, 192 int flag, const struct timeval50 *tptr) 193 { 194 struct timeval tv[2], *tvp; 195 struct timeval50 tv50[2]; 196 if (tptr) { 197 int error = copyin(tptr, tv50, sizeof(tv50)); 198 if (error) 199 return error; 200 timeval50_to_timeval(&tv50[0], &tv[0]); 201 timeval50_to_timeval(&tv50[1], &tv[1]); 202 tvp = tv; 203 } else 204 tvp = NULL; 205 return do_sys_utimes(l, vp, path, flag, tvp, UIO_SYSSPACE); 206 } 207 208 /* 209 * Set the access and modification times given a path name; this 210 * version follows links. 211 */ 212 /* ARGSUSED */ 213 int 214 compat_50_sys_utimes(struct lwp *l, const struct compat_50_sys_utimes_args *uap, 215 register_t *retval) 216 { 217 /* { 218 syscallarg(const char *) path; 219 syscallarg(const struct timeval50 *) tptr; 220 } */ 221 222 return compat_50_do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW, 223 SCARG(uap, tptr)); 224 } 225 226 /* 227 * Set the access and modification times given a file descriptor. 228 */ 229 /* ARGSUSED */ 230 int 231 compat_50_sys_futimes(struct lwp *l, 232 const struct compat_50_sys_futimes_args *uap, register_t *retval) 233 { 234 /* { 235 syscallarg(int) fd; 236 syscallarg(const struct timeval50 *) tptr; 237 } */ 238 int error; 239 struct file *fp; 240 241 /* fd_getvnode() will use the descriptor for us */ 242 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 243 return error; 244 error = compat_50_do_sys_utimes(l, fp->f_data, NULL, 0, 245 SCARG(uap, tptr)); 246 fd_putfile(SCARG(uap, fd)); 247 return error; 248 } 249 250 /* 251 * Set the access and modification times given a path name; this 252 * version does not follow links. 253 */ 254 int 255 compat_50_sys_lutimes(struct lwp *l, 256 const struct compat_50_sys_lutimes_args *uap, register_t *retval) 257 { 258 /* { 259 syscallarg(const char *) path; 260 syscallarg(const struct timeval50 *) tptr; 261 } */ 262 263 return compat_50_do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW, 264 SCARG(uap, tptr)); 265 } 266 267 int 268 compat_50_sys_lfs_segwait(struct lwp *l, 269 const struct compat_50_sys_lfs_segwait_args *uap, register_t *retval) 270 { 271 /* { 272 syscallarg(fsid_t *) fsidp; 273 syscallarg(struct timeval50 *) tv; 274 } */ 275 #ifdef notyet 276 struct timeval atv; 277 struct timeval50 atv50; 278 fsid_t fsid; 279 int error; 280 281 /* XXX need we be su to segwait? */ 282 if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, 283 NULL)) != 0) 284 return (error); 285 if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0) 286 return (error); 287 288 if (SCARG(uap, tv)) { 289 error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); 290 if (error) 291 return (error); 292 timeval50_to_timeval(&atv50, &atv); 293 if (itimerfix(&atv)) 294 return (EINVAL); 295 } else /* NULL or invalid */ 296 atv.tv_sec = atv.tv_usec = 0; 297 return lfs_segwait(&fsid, &atv); 298 #else 299 return ENOSYS; 300 #endif 301 } 302 303 int 304 compat_50_sys_mknod(struct lwp *l, 305 const struct compat_50_sys_mknod_args *uap, register_t *retval) 306 { 307 /* { 308 syscallarg(const char *) path; 309 syscallarg(mode_t) mode; 310 syscallarg(uint32_t) dev; 311 } */ 312 return do_sys_mknod(l, SCARG(uap, path), SCARG(uap, mode), 313 SCARG(uap, dev), retval, UIO_USERSPACE); 314 } 315 316 #include <ufs/ufs/quota1.h> 317 #include <quota/quotaprop.h> 318 319 /* ARGSUSED */ 320 int 321 compat_50_sys_quotactl(struct lwp *l, const struct compat_50_sys_quotactl_args *uap, register_t *retval) 322 { 323 /* { 324 syscallarg(const char *) path; 325 syscallarg(int) cmd; 326 syscallarg(int) uid; 327 syscallarg(void *) arg; 328 } */ 329 struct mount *mp; 330 int error; 331 uint8_t error8; 332 struct vnode *vp; 333 int q1cmd = SCARG(uap, cmd); 334 prop_dictionary_t dict, data, cmd; 335 prop_array_t cmds, datas; 336 char *bufpath; 337 struct dqblk dqblk; 338 struct ufs_quota_entry qe[QUOTA_NLIMITS]; 339 uint64_t *values[QUOTA_NLIMITS]; 340 341 values[QUOTA_LIMIT_BLOCK] = &qe[QUOTA_LIMIT_BLOCK].ufsqe_hardlimit; 342 values[QUOTA_LIMIT_FILE] = &qe[QUOTA_LIMIT_FILE].ufsqe_hardlimit; 343 344 error = namei_simple_user(SCARG(uap, path), 345 NSM_FOLLOW_TRYEMULROOT, &vp); 346 if (error != 0) 347 return (error); 348 error = ENOMEM; 349 mp = vp->v_mount; 350 if ((dict = quota_prop_create()) == NULL) 351 goto out; 352 if ((cmds = prop_array_create()) == NULL) 353 goto out_dict; 354 if ((datas = prop_array_create()) == NULL) 355 goto out_cmds; 356 357 switch((q1cmd & ~SUBCMDMASK) >> SUBCMDSHIFT) { 358 case Q_QUOTAON: 359 data = prop_dictionary_create(); 360 if (data == NULL) 361 goto out_datas; 362 bufpath = malloc(PATH_MAX * sizeof(char), M_TEMP, M_WAITOK); 363 if (bufpath == NULL) 364 goto out_data; 365 error = copyinstr(SCARG(uap, arg), bufpath, PATH_MAX, NULL); 366 if (error != 0) { 367 free(bufpath, M_TEMP); 368 goto out_data; 369 } 370 if (!prop_dictionary_set_cstring(data, "quotafile", bufpath)) 371 error = ENOMEM; 372 free(bufpath, M_TEMP); 373 if (error) 374 goto out_data; 375 error = ENOMEM; 376 if (!prop_array_add_and_rel(datas, data)) 377 goto out_datas; 378 if (!quota_prop_add_command(cmds, "quotaon", 379 ufs_quota_class_names[qtype2ufsclass(q1cmd & SUBCMDMASK)], 380 datas)) 381 goto out_cmds; 382 goto do_quotaonoff; 383 384 case Q_QUOTAOFF: 385 error = ENOMEM; 386 if (!quota_prop_add_command(cmds, "quotaoff", 387 ufs_quota_class_names[qtype2ufsclass(q1cmd & SUBCMDMASK)], 388 datas)) 389 goto out_cmds; 390 do_quotaonoff: 391 if (!prop_dictionary_set_and_rel(dict, "commands", cmds)) 392 goto out_dict; 393 error = VFS_QUOTACTL(mp, dict); 394 if (error) 395 goto out_dict; 396 if ((error = quota_get_cmds(dict, &cmds)) != 0) 397 goto out_dict; 398 cmd = prop_array_get(cmds, 0); 399 if (cmd == NULL) { 400 error = EINVAL; 401 goto out_dict; 402 } 403 if (!prop_dictionary_get_int8(cmd, "return", &error8)) { 404 error = EINVAL; 405 goto out_dict; 406 } 407 error = error8; 408 goto out_dict; 409 410 case Q_GETQUOTA: 411 error = ENOMEM; 412 data = prop_dictionary_create(); 413 if (data == NULL) 414 goto out_datas; 415 if (!prop_dictionary_set_uint32(data, "id", SCARG(uap, uid))) 416 goto out_data; 417 if (!prop_array_add_and_rel(datas, data)) 418 goto out_datas; 419 if (!quota_prop_add_command(cmds, "get", 420 ufs_quota_class_names[qtype2ufsclass(q1cmd & SUBCMDMASK)], 421 datas)) 422 goto out_cmds; 423 if (!prop_dictionary_set_and_rel(dict, "commands", cmds)) 424 goto out_dict; 425 error = VFS_QUOTACTL(mp, dict); 426 if (error) 427 goto out_dict; 428 if ((error = quota_get_cmds(dict, &cmds)) != 0) 429 goto out_dict; 430 cmd = prop_array_get(cmds, 0); 431 if (cmd == NULL) { 432 error = EINVAL; 433 goto out_dict; 434 } 435 if (!prop_dictionary_get_int8(cmd, "return", &error8)) { 436 error = EINVAL; 437 goto out_dict; 438 } 439 error = error8; 440 if (error) 441 goto out_dict; 442 datas = prop_dictionary_get(cmd, "data"); 443 error = EINVAL; 444 if (datas == NULL) 445 goto out_dict; 446 data = prop_array_get(datas, 0); 447 if (data == NULL) 448 goto out_dict; 449 error = proptoquota64(data, values, 450 ufs_quota_entry_names, UFS_QUOTA_NENTRIES, 451 ufs_quota_limit_names, QUOTA_NLIMITS); 452 if (error) 453 goto out_dict; 454 ufsqe2dqblk(qe, &dqblk); 455 error = copyout(&dqblk, SCARG(uap, arg), sizeof(dqblk)); 456 goto out_dict; 457 458 case Q_SETQUOTA: 459 error = copyin(SCARG(uap, arg), &dqblk, sizeof(dqblk)); 460 if (error) 461 goto out_datas; 462 dqblk2ufsqe(&dqblk, qe); 463 464 error = ENOMEM; 465 data = quota64toprop(SCARG(uap, uid), 0, values, 466 ufs_quota_entry_names, UFS_QUOTA_NENTRIES, 467 ufs_quota_limit_names, QUOTA_NLIMITS); 468 if (data == NULL) 469 goto out_data; 470 if (!prop_array_add_and_rel(datas, data)) 471 goto out_datas; 472 if (!quota_prop_add_command(cmds, "set", 473 ufs_quota_class_names[qtype2ufsclass(q1cmd & SUBCMDMASK)], 474 datas)) 475 goto out_cmds; 476 if (!prop_dictionary_set_and_rel(dict, "commands", cmds)) 477 goto out_dict; 478 error = VFS_QUOTACTL(mp, dict); 479 if (error) 480 goto out_dict; 481 if ((error = quota_get_cmds(dict, &cmds)) != 0) 482 goto out_dict; 483 cmd = prop_array_get(cmds, 0); 484 if (cmd == NULL) { 485 error = EINVAL; 486 goto out_dict; 487 } 488 if (!prop_dictionary_get_int8(cmd, "return", &error8)) { 489 error = EINVAL; 490 goto out_dict; 491 } 492 error = error8; 493 goto out_dict; 494 495 case Q_SYNC: 496 /* 497 * not supported but used only to see if quota is supported, 498 * emulate with a "get version" 499 */ 500 error = ENOMEM; 501 if (!quota_prop_add_command(cmds, "get version", 502 ufs_quota_class_names[qtype2ufsclass(q1cmd & SUBCMDMASK)], 503 datas)) 504 goto out_cmds; 505 if (!prop_dictionary_set_and_rel(dict, "commands", cmds)) 506 goto out_dict; 507 error = VFS_QUOTACTL(mp, dict); 508 if (error) 509 goto out_dict; 510 if ((error = quota_get_cmds(dict, &cmds)) != 0) 511 goto out_dict; 512 cmd = prop_array_get(cmds, 0); 513 if (cmd == NULL) { 514 error = EINVAL; 515 goto out_dict; 516 } 517 if (!prop_dictionary_get_int8(cmd, "return", &error8)) { 518 error = EINVAL; 519 goto out_dict; 520 } 521 error = error8; 522 goto out_dict; 523 524 case Q_SETUSE: 525 default: 526 error = EOPNOTSUPP; 527 goto out_datas; 528 } 529 out_data: 530 prop_object_release(data); 531 out_datas: 532 prop_object_release(datas); 533 out_cmds: 534 prop_object_release(cmds); 535 out_dict: 536 prop_object_release(dict); 537 out: 538 vrele(vp); 539 return error; 540 } 541