1 /* $NetBSD: dtfs_vfsops.c,v 1.3 2012/11/04 23:37:02 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/resource.h> 30 31 #include <stdio.h> 32 #include <assert.h> 33 #include <err.h> 34 #include <errno.h> 35 #include <puffs.h> 36 #include <string.h> 37 #include <stdlib.h> 38 #include <unistd.h> 39 #include <util.h> 40 41 #include "dtfs.h" 42 43 static int 44 rtstr(struct puffs_usermount *pu, const char *str, enum vtype vt) 45 { 46 struct puffs_node *pn = puffs_getroot(pu); 47 struct vattr *va = &pn->pn_va; 48 struct dtfs_file *df = DTFS_PTOF(pn); 49 char ltarg[256+1]; 50 51 if (sscanf(str, "%*s %256s", ltarg) != 1) 52 return 1; 53 54 dtfs_baseattrs(va, vt, 2); 55 df->df_linktarget = estrdup(ltarg); 56 57 va->va_nlink = 1; 58 va->va_size = strlen(df->df_linktarget); 59 60 puffs_setrootinfo(pu, vt, 0, 0); 61 62 return 0; 63 } 64 65 static int 66 rtdev(struct puffs_usermount *pu, const char *str, enum vtype vt) 67 { 68 struct puffs_node *pn = puffs_getroot(pu); 69 struct vattr *va = &pn->pn_va; 70 int major, minor; 71 72 if (sscanf(str, "%*s %d %d", &major, &minor) != 2) 73 return 1; 74 75 dtfs_baseattrs(va, vt, 2); 76 va->va_nlink = 1; 77 va->va_rdev = makedev(major, minor); 78 79 if (vt == VBLK) 80 va->va_mode |= S_IFBLK; 81 else 82 va->va_mode |= S_IFCHR; 83 84 puffs_setrootinfo(pu, vt, 0, va->va_rdev); 85 86 return 0; 87 } 88 89 static int 90 rtnorm(struct puffs_usermount *pu, const char *str, enum vtype vt) 91 { 92 struct puffs_node *pn = puffs_getroot(pu); 93 struct vattr *va = &pn->pn_va; 94 95 dtfs_baseattrs(va, vt, 2); 96 if (vt == VDIR) 97 va->va_nlink = 2; 98 else 99 va->va_nlink = 1; 100 101 puffs_setrootinfo(pu, vt, 0, 0); 102 103 return 0; 104 } 105 106 struct rtype { 107 char *tstr; 108 enum vtype vt; 109 int (*pfunc)(struct puffs_usermount *, const char *, enum vtype); 110 } rtypes[] = { 111 { "reg", VREG, rtnorm }, 112 { "dir", VDIR, rtnorm }, 113 { "blk", VBLK, rtdev }, 114 { "chr", VCHR, rtdev }, 115 { "lnk", VLNK, rtstr }, 116 { "sock", VSOCK, rtnorm }, 117 { "fifo", VFIFO, rtnorm } 118 }; 119 #define NTYPES (sizeof(rtypes) / sizeof(rtypes[0])) 120 121 int 122 dtfs_domount(struct puffs_usermount *pu, const char *typestr) 123 { 124 struct dtfs_mount *dtm; 125 struct dtfs_file *dff; 126 struct puffs_node *pn; 127 int i; 128 129 /* create mount-local thingie */ 130 dtm = puffs_getspecific(pu); 131 dtm->dtm_nextfileid = 3; 132 dtm->dtm_nfiles = 1; 133 dtm->dtm_fsizes = 0; 134 LIST_INIT(&dtm->dtm_pollent); 135 136 /* 137 * create root directory, do it "by hand" to avoid special-casing 138 * dtfs_genfile() 139 */ 140 dff = dtfs_newdir(); 141 dff->df_dotdot = NULL; 142 pn = puffs_pn_new(pu, dff); 143 if (!pn) 144 errx(1, "puffs_newpnode"); 145 puffs_setroot(pu, pn); 146 147 if (!typestr) { 148 rtnorm(pu, NULL, VDIR); 149 } else { 150 for (i = 0; i < NTYPES; i++) { 151 if (strncmp(rtypes[i].tstr, typestr, 152 strlen(rtypes[i].tstr)) == 0) { 153 if (rtypes[i].pfunc(pu, typestr, 154 rtypes[i].vt) != 0) { 155 fprintf(stderr, "failed to parse " 156 "\"%s\"\n", typestr); 157 return 1; 158 } 159 break; 160 } 161 } 162 if (i == NTYPES) { 163 fprintf(stderr, "no maching type for %s\n", typestr); 164 return 1; 165 } 166 } 167 168 return 0; 169 } 170 171 /* 172 * statvfs() should fill in the following members of struct statvfs: 173 * 174 * unsigned long f_bsize; file system block size 175 * unsigned long f_frsize; fundamental file system block size 176 * unsigned long f_iosize; optimal file system block size 177 * fsblkcnt_t f_blocks; number of blocks in file system, 178 * (in units of f_frsize) 179 * 180 * fsblkcnt_t f_bfree; free blocks avail in file system 181 * fsblkcnt_t f_bavail; free blocks avail to non-root 182 * fsblkcnt_t f_bresvd; blocks reserved for root 183 * 184 * fsfilcnt_t f_files; total file nodes in file system 185 * fsfilcnt_t f_ffree; free file nodes in file system 186 * fsfilcnt_t f_favail; free file nodes avail to non-root 187 * fsfilcnt_t f_fresvd; file nodes reserved for root 188 * 189 * 190 * The rest are filled in by the kernel. 191 */ 192 #define ROUND(a,b) (((a) + ((b)-1)) & ~((b)-1)) 193 #define NFILES 1024*1024 194 int 195 dtfs_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp) 196 { 197 struct rlimit rlim; 198 struct dtfs_mount *dtm; 199 off_t btot, bfree; 200 int pgsize; 201 202 dtm = puffs_getspecific(pu); 203 pgsize = getpagesize(); 204 memset(sbp, 0, sizeof(struct statvfs)); 205 206 /* 207 * Use datasize rlimit as an _approximation_ for free size. 208 * This, of course, is not accurate due to overhead and not 209 * accounting for metadata. 210 */ 211 if (getrlimit(RLIMIT_DATA, &rlim) == 0) 212 btot = rlim.rlim_cur; 213 else 214 btot = 16*1024*1024; 215 bfree = btot - dtm->dtm_fsizes; 216 217 sbp->f_blocks = ROUND(btot, pgsize) / pgsize; 218 sbp->f_files = NFILES; 219 220 sbp->f_bsize = sbp->f_frsize = sbp->f_iosize = pgsize; 221 sbp->f_bfree = sbp->f_bavail = ROUND(bfree, pgsize) / pgsize; 222 sbp->f_ffree = sbp->f_favail = NFILES - dtm->dtm_nfiles; 223 224 sbp->f_bresvd = sbp->f_fresvd = 0; 225 226 return 0; 227 } 228 #undef ROUND 229 230 static void * 231 addrcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg) 232 { 233 234 if (pn == arg) 235 return pn; 236 237 return NULL; 238 } 239 240 int 241 dtfs_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, 242 struct puffs_newinfo *pni) 243 { 244 struct dtfs_fid *dfid; 245 struct puffs_node *pn; 246 247 assert(fidsize == sizeof(struct dtfs_fid)); 248 dfid = fid; 249 250 pn = puffs_pn_nodewalk(pu, addrcmp, dfid->dfid_addr); 251 if (pn == NULL) 252 return ESTALE; 253 254 if (pn->pn_va.va_fileid != dfid->dfid_fileid 255 || pn->pn_va.va_gen != dfid->dfid_gen) 256 return ESTALE; 257 258 puffs_newinfo_setcookie(pni, pn); 259 puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 260 puffs_newinfo_setsize(pni, pn->pn_va.va_size); 261 puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); 262 263 return 0; 264 } 265 266 int 267 dtfs_fs_nodetofh(struct puffs_usermount *pu, void *cookie, 268 void *fid, size_t *fidsize) 269 { 270 struct puffs_node *pn = cookie; 271 struct dtfs_fid *dfid; 272 extern int dynamicfh; 273 274 if (dynamicfh == 0) { 275 assert(*fidsize >= sizeof(struct dtfs_fid)); 276 } else { 277 if (*fidsize < sizeof(struct dtfs_fid)) { 278 *fidsize = sizeof(struct dtfs_fid); 279 return E2BIG; 280 } 281 *fidsize = sizeof(struct dtfs_fid); 282 } 283 284 dfid = fid; 285 286 dfid->dfid_addr = pn; 287 dfid->dfid_fileid = pn->pn_va.va_fileid; 288 dfid->dfid_gen = pn->pn_va.va_gen; 289 290 return 0; 291 } 292 293 int 294 dtfs_fs_unmount(struct puffs_usermount *pu, int flags) 295 { 296 297 return 0; 298 } 299