1 /* $NetBSD: vfs_syscalls_50.c,v 1.18 2014/09/05 09:21:54 matt 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.18 2014/09/05 09:21:54 matt 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/kauth.h> 55 #include <sys/time.h> 56 #include <sys/vfs_syscalls.h> 57 #ifndef LFS 58 #define LFS 59 #endif 60 #include <sys/syscallargs.h> 61 62 #include <ufs/lfs/lfs_extern.h> 63 64 #include <sys/quota.h> 65 #include <sys/quotactl.h> 66 #include <ufs/ufs/quota1.h> 67 68 #include <compat/common/compat_util.h> 69 #include <compat/sys/time.h> 70 #include <compat/sys/stat.h> 71 #include <compat/sys/dirent.h> 72 #include <compat/sys/mount.h> 73 74 static void cvtstat(struct stat30 *, const struct stat *); 75 76 /* 77 * Convert from a new to an old stat structure. 78 */ 79 static void 80 cvtstat(struct stat30 *ost, const struct stat *st) 81 { 82 83 ost->st_dev = st->st_dev; 84 ost->st_ino = st->st_ino; 85 ost->st_mode = st->st_mode; 86 ost->st_nlink = st->st_nlink; 87 ost->st_uid = st->st_uid; 88 ost->st_gid = st->st_gid; 89 ost->st_rdev = st->st_rdev; 90 timespec_to_timespec50(&st->st_atimespec, &ost->st_atimespec); 91 timespec_to_timespec50(&st->st_mtimespec, &ost->st_mtimespec); 92 timespec_to_timespec50(&st->st_ctimespec, &ost->st_ctimespec); 93 timespec_to_timespec50(&st->st_birthtimespec, &ost->st_birthtimespec); 94 ost->st_size = st->st_size; 95 ost->st_blocks = st->st_blocks; 96 ost->st_blksize = st->st_blksize; 97 ost->st_flags = st->st_flags; 98 ost->st_gen = st->st_gen; 99 memset(ost->st_spare, 0, sizeof(ost->st_spare)); 100 } 101 102 /* 103 * Get file status; this version follows links. 104 */ 105 /* ARGSUSED */ 106 int 107 compat_50_sys___stat30(struct lwp *l, const struct compat_50_sys___stat30_args *uap, register_t *retval) 108 { 109 /* { 110 syscallarg(const char *) path; 111 syscallarg(struct stat30 *) ub; 112 } */ 113 struct stat sb; 114 struct stat30 osb; 115 int error; 116 117 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); 118 if (error) 119 return error; 120 cvtstat(&osb, &sb); 121 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 122 return error; 123 } 124 125 126 /* 127 * Get file status; this version does not follow links. 128 */ 129 /* ARGSUSED */ 130 int 131 compat_50_sys___lstat30(struct lwp *l, const struct compat_50_sys___lstat30_args *uap, register_t *retval) 132 { 133 /* { 134 syscallarg(const char *) path; 135 syscallarg(struct stat30 *) ub; 136 } */ 137 struct stat sb; 138 struct stat30 osb; 139 int error; 140 141 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); 142 if (error) 143 return error; 144 cvtstat(&osb, &sb); 145 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 146 return error; 147 } 148 149 /* 150 * Return status information about a file descriptor. 151 */ 152 /* ARGSUSED */ 153 int 154 compat_50_sys___fstat30(struct lwp *l, const struct compat_50_sys___fstat30_args *uap, register_t *retval) 155 { 156 /* { 157 syscallarg(int) fd; 158 syscallarg(struct stat30 *) sb; 159 } */ 160 struct stat sb; 161 struct stat30 osb; 162 int error; 163 164 error = do_sys_fstat(SCARG(uap, fd), &sb); 165 if (error) 166 return error; 167 cvtstat(&osb, &sb); 168 error = copyout(&osb, SCARG(uap, sb), sizeof (osb)); 169 return error; 170 } 171 172 /* ARGSUSED */ 173 int 174 compat_50_sys___fhstat40(struct lwp *l, const struct compat_50_sys___fhstat40_args *uap, register_t *retval) 175 { 176 /* { 177 syscallarg(const void *) fhp; 178 syscallarg(size_t) fh_size; 179 syscallarg(struct stat30 *) sb; 180 } */ 181 struct stat sb; 182 struct stat30 osb; 183 int error; 184 185 error = do_fhstat(l, SCARG(uap, fhp), SCARG(uap, fh_size), &sb); 186 if (error) 187 return error; 188 cvtstat(&osb, &sb); 189 error = copyout(&osb, SCARG(uap, sb), sizeof (osb)); 190 return error; 191 } 192 193 static int 194 compat_50_do_sys_utimes(struct lwp *l, struct vnode *vp, const char *path, 195 int flag, const struct timeval50 *tptr) 196 { 197 struct timeval tv[2], *tvp; 198 struct timeval50 tv50[2]; 199 if (tptr) { 200 int error = copyin(tptr, tv50, sizeof(tv50)); 201 if (error) 202 return error; 203 timeval50_to_timeval(&tv50[0], &tv[0]); 204 timeval50_to_timeval(&tv50[1], &tv[1]); 205 tvp = tv; 206 } else 207 tvp = NULL; 208 return do_sys_utimes(l, vp, path, flag, tvp, UIO_SYSSPACE); 209 } 210 211 /* 212 * Set the access and modification times given a path name; this 213 * version follows links. 214 */ 215 /* ARGSUSED */ 216 int 217 compat_50_sys_utimes(struct lwp *l, const struct compat_50_sys_utimes_args *uap, 218 register_t *retval) 219 { 220 /* { 221 syscallarg(const char *) path; 222 syscallarg(const struct timeval50 *) tptr; 223 } */ 224 225 return compat_50_do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW, 226 SCARG(uap, tptr)); 227 } 228 229 /* 230 * Set the access and modification times given a file descriptor. 231 */ 232 /* ARGSUSED */ 233 int 234 compat_50_sys_futimes(struct lwp *l, 235 const struct compat_50_sys_futimes_args *uap, register_t *retval) 236 { 237 /* { 238 syscallarg(int) fd; 239 syscallarg(const struct timeval50 *) tptr; 240 } */ 241 int error; 242 struct file *fp; 243 244 /* fd_getvnode() will use the descriptor for us */ 245 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 246 return error; 247 error = compat_50_do_sys_utimes(l, fp->f_vnode, NULL, 0, 248 SCARG(uap, tptr)); 249 fd_putfile(SCARG(uap, fd)); 250 return error; 251 } 252 253 /* 254 * Set the access and modification times given a path name; this 255 * version does not follow links. 256 */ 257 int 258 compat_50_sys_lutimes(struct lwp *l, 259 const struct compat_50_sys_lutimes_args *uap, register_t *retval) 260 { 261 /* { 262 syscallarg(const char *) path; 263 syscallarg(const struct timeval50 *) tptr; 264 } */ 265 266 return compat_50_do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW, 267 SCARG(uap, tptr)); 268 } 269 270 int 271 compat_50_sys_lfs_segwait(struct lwp *l, 272 const struct compat_50_sys_lfs_segwait_args *uap, register_t *retval) 273 { 274 /* { 275 syscallarg(fsid_t *) fsidp; 276 syscallarg(struct timeval50 *) tv; 277 } */ 278 #ifdef notyet 279 struct timeval atv; 280 struct timeval50 atv50; 281 fsid_t fsid; 282 int error; 283 284 /* XXX need we be su to segwait? */ 285 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_LFS, 286 KAUTH_REQ_SYSTEM_LFS_SEGWAIT, NULL, NULL, NULL); 287 if (error) 288 return (error); 289 if ((error = copyin(SCARG(uap, fsidp), &fsid, sizeof(fsid_t))) != 0) 290 return (error); 291 292 if (SCARG(uap, tv)) { 293 error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); 294 if (error) 295 return (error); 296 timeval50_to_timeval(&atv50, &atv); 297 if (itimerfix(&atv)) 298 return (EINVAL); 299 } else /* NULL or invalid */ 300 atv.tv_sec = atv.tv_usec = 0; 301 return lfs_segwait(&fsid, &atv); 302 #else 303 return ENOSYS; 304 #endif 305 } 306 307 int 308 compat_50_sys_mknod(struct lwp *l, 309 const struct compat_50_sys_mknod_args *uap, register_t *retval) 310 { 311 /* { 312 syscallarg(const char *) path; 313 syscallarg(mode_t) mode; 314 syscallarg(uint32_t) dev; 315 } */ 316 return do_sys_mknod(l, SCARG(uap, path), SCARG(uap, mode), 317 SCARG(uap, dev), retval, UIO_USERSPACE); 318 } 319 320 /* ARGSUSED */ 321 int 322 compat_50_sys_quotactl(struct lwp *l, const struct compat_50_sys_quotactl_args *uap, register_t *retval) 323 { 324 /* { 325 syscallarg(const char *) path; 326 syscallarg(int) cmd; 327 syscallarg(int) uid; 328 syscallarg(void *) arg; 329 } */ 330 struct vnode *vp; 331 struct mount *mp; 332 int q1cmd; 333 int idtype; 334 char *qfile; 335 struct dqblk dqblk; 336 struct quotakey key; 337 struct quotaval blocks, files; 338 struct quotastat qstat; 339 int error; 340 341 error = namei_simple_user(SCARG(uap, path), 342 NSM_FOLLOW_TRYEMULROOT, &vp); 343 if (error != 0) 344 return (error); 345 346 mp = vp->v_mount; 347 q1cmd = SCARG(uap, cmd); 348 idtype = quota_idtype_from_ufs(q1cmd & SUBCMDMASK); 349 350 switch ((q1cmd & ~SUBCMDMASK) >> SUBCMDSHIFT) { 351 case Q_QUOTAON: 352 qfile = PNBUF_GET(); 353 error = copyinstr(SCARG(uap, arg), qfile, PATH_MAX, NULL); 354 if (error != 0) { 355 PNBUF_PUT(qfile); 356 break; 357 } 358 359 error = vfs_quotactl_quotaon(mp, idtype, qfile); 360 361 PNBUF_PUT(qfile); 362 break; 363 364 case Q_QUOTAOFF: 365 error = vfs_quotactl_quotaoff(mp, idtype); 366 break; 367 368 case Q_GETQUOTA: 369 key.qk_idtype = idtype; 370 key.qk_id = SCARG(uap, uid); 371 372 key.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 373 error = vfs_quotactl_get(mp, &key, &blocks); 374 if (error) { 375 break; 376 } 377 378 key.qk_objtype = QUOTA_OBJTYPE_FILES; 379 error = vfs_quotactl_get(mp, &key, &files); 380 if (error) { 381 break; 382 } 383 384 quotavals_to_dqblk(&blocks, &files, &dqblk); 385 error = copyout(&dqblk, SCARG(uap, arg), sizeof(dqblk)); 386 break; 387 388 case Q_SETQUOTA: 389 error = copyin(SCARG(uap, arg), &dqblk, sizeof(dqblk)); 390 if (error) { 391 break; 392 } 393 dqblk_to_quotavals(&dqblk, &blocks, &files); 394 395 key.qk_idtype = idtype; 396 key.qk_id = SCARG(uap, uid); 397 398 key.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 399 error = vfs_quotactl_put(mp, &key, &blocks); 400 if (error) { 401 break; 402 } 403 404 key.qk_objtype = QUOTA_OBJTYPE_FILES; 405 error = vfs_quotactl_put(mp, &key, &files); 406 break; 407 408 case Q_SYNC: 409 /* 410 * not supported but used only to see if quota is supported, 411 * emulate with stat 412 * 413 * XXX should probably be supported 414 */ 415 (void)idtype; /* not used */ 416 417 error = vfs_quotactl_stat(mp, &qstat); 418 break; 419 420 case Q_SETUSE: 421 default: 422 error = EOPNOTSUPP; 423 break; 424 } 425 426 vrele(vp); 427 return error; 428 } 429