| File: | src/lib/libkvm/kvm_file2.c |
| Warning: | line 888, column 3 Address of stack memory associated with local variable 'specinfo' is still referred to by the stack variable 'vbuf' upon returning to the caller. This will be a dangling reference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: kvm_file2.c,v 1.57 2022/02/22 17:35:01 deraadt Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2009 Todd C. Miller <millert@openbsd.org> | |||
| 5 | * | |||
| 6 | * Permission to use, copy, modify, and distribute this software for any | |||
| 7 | * purpose with or without fee is hereby granted, provided that the above | |||
| 8 | * copyright notice and this permission notice appear in all copies. | |||
| 9 | * | |||
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 17 | */ | |||
| 18 | ||||
| 19 | /*- | |||
| 20 | * Copyright (c) 1989, 1992, 1993 | |||
| 21 | * The Regents of the University of California. All rights reserved. | |||
| 22 | * | |||
| 23 | * Redistribution and use in source and binary forms, with or without | |||
| 24 | * modification, are permitted provided that the following conditions | |||
| 25 | * are met: | |||
| 26 | * 1. Redistributions of source code must retain the above copyright | |||
| 27 | * notice, this list of conditions and the following disclaimer. | |||
| 28 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 29 | * notice, this list of conditions and the following disclaimer in the | |||
| 30 | * documentation and/or other materials provided with the distribution. | |||
| 31 | * 3. Neither the name of the University nor the names of its contributors | |||
| 32 | * may be used to endorse or promote products derived from this software | |||
| 33 | * without specific prior written permission. | |||
| 34 | * | |||
| 35 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 36 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 37 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 38 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 39 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 40 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 41 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 42 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 43 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 44 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 45 | * SUCH DAMAGE. | |||
| 46 | */ | |||
| 47 | ||||
| 48 | /* | |||
| 49 | * Extended file list interface for kvm. pstat, fstat and netstat are | |||
| 50 | * users of this code, so we've factored it out into a separate module. | |||
| 51 | * Thus, we keep this grunge out of the other kvm applications (i.e., | |||
| 52 | * most other applications are interested only in open/close/read/nlist). | |||
| 53 | */ | |||
| 54 | ||||
| 55 | #define __need_process | |||
| 56 | ||||
| 57 | #include <sys/types.h> | |||
| 58 | #include <sys/signal.h> | |||
| 59 | #include <sys/uio.h> | |||
| 60 | #include <sys/ucred.h> | |||
| 61 | #include <sys/proc.h> | |||
| 62 | #define _KERNEL | |||
| 63 | #include <sys/file.h> | |||
| 64 | #include <sys/mount.h> | |||
| 65 | #undef _KERNEL | |||
| 66 | #include <sys/vnode.h> | |||
| 67 | #include <sys/socket.h> | |||
| 68 | #include <sys/socketvar.h> | |||
| 69 | #include <sys/domain.h> | |||
| 70 | #include <sys/protosw.h> | |||
| 71 | #include <sys/event.h> | |||
| 72 | #include <sys/eventvar.h> | |||
| 73 | #include <sys/un.h> | |||
| 74 | #include <sys/unpcb.h> | |||
| 75 | #include <sys/filedesc.h> | |||
| 76 | #include <sys/mbuf.h> | |||
| 77 | #include <sys/pipe.h> | |||
| 78 | #include <sys/stat.h> | |||
| 79 | #include <sys/sysctl.h> | |||
| 80 | #include <sys/specdev.h> | |||
| 81 | ||||
| 82 | #define _KERNEL | |||
| 83 | #include <ufs/ufs/quota.h> | |||
| 84 | #include <ufs/ufs/inode.h> | |||
| 85 | #undef _KERNEL | |||
| 86 | ||||
| 87 | #include <nfs/nfsproto.h> | |||
| 88 | #include <nfs/rpcv2.h> | |||
| 89 | #include <nfs/nfs.h> | |||
| 90 | #include <nfs/nfsnode.h> | |||
| 91 | ||||
| 92 | #include <msdosfs/bpb.h> | |||
| 93 | #include <msdosfs/denode.h> | |||
| 94 | #include <msdosfs/msdosfsmount.h> | |||
| 95 | ||||
| 96 | #include <net/route.h> | |||
| 97 | #include <netinet/in.h> | |||
| 98 | #include <netinet/ip.h> | |||
| 99 | #include <netinet/in_pcb.h> | |||
| 100 | #include <netinet/tcp.h> | |||
| 101 | #include <netinet/tcp_timer.h> | |||
| 102 | #include <netinet/tcp_var.h> | |||
| 103 | ||||
| 104 | #ifdef INET6 | |||
| 105 | #include <netinet/ip6.h> | |||
| 106 | #include <netinet6/ip6_var.h> | |||
| 107 | #endif | |||
| 108 | ||||
| 109 | #include <fcntl.h> | |||
| 110 | #include <nlist.h> | |||
| 111 | #include <kvm.h> | |||
| 112 | #include <db.h> | |||
| 113 | #include <stddef.h> | |||
| 114 | #include <stdlib.h> | |||
| 115 | #include <string.h> | |||
| 116 | #include <unistd.h> | |||
| 117 | #include <limits.h> | |||
| 118 | #include <errno(*__errno()).h> | |||
| 119 | ||||
| 120 | #include "kvm_private.h" | |||
| 121 | #include "kvm_file.h" | |||
| 122 | ||||
| 123 | static struct kinfo_file *kvm_deadfile_byfile(kvm_t *, int, int, | |||
| 124 | size_t, int *); | |||
| 125 | static struct kinfo_file *kvm_deadfile_byid(kvm_t *, int, int, | |||
| 126 | size_t, int *); | |||
| 127 | static int fill_file(kvm_t *, struct kinfo_file *, struct file *, u_long, | |||
| 128 | struct vnode *, struct process *, int, pid_t); | |||
| 129 | static int filestat(kvm_t *, struct kinfo_file *, struct vnode *); | |||
| 130 | ||||
| 131 | LIST_HEAD(processlist, process)struct processlist { struct process *lh_first; }; | |||
| 132 | ||||
| 133 | struct kinfo_file * | |||
| 134 | kvm_getfiles(kvm_t *kd, int op, int arg, size_t esize, int *cnt) | |||
| 135 | { | |||
| 136 | int mib[6], rv; | |||
| 137 | void *filebase; | |||
| 138 | size_t size; | |||
| 139 | ||||
| 140 | if (ISALIVE(kd)((kd)->alive)) { | |||
| ||||
| 141 | mib[0] = CTL_KERN1; | |||
| 142 | mib[1] = KERN_FILE73; | |||
| 143 | mib[2] = op; | |||
| 144 | mib[3] = arg; | |||
| 145 | mib[4] = esize; | |||
| 146 | ||||
| 147 | do { | |||
| 148 | mib[5] = 0; | |||
| 149 | ||||
| 150 | /* find size and alloc buffer */ | |||
| 151 | rv = sysctl(mib, 6, NULL((void *)0), &size, NULL((void *)0), 0); | |||
| 152 | if (rv == -1) { | |||
| 153 | if (errno(*__errno()) != ESRCH3 && kd->vmfd != -1) | |||
| 154 | goto deadway; | |||
| 155 | _kvm_syserr(kd, kd->program, "kvm_getfiles"); | |||
| 156 | return (NULL((void *)0)); | |||
| 157 | } | |||
| 158 | ||||
| 159 | size += size / 8; /* add ~10% */ | |||
| 160 | ||||
| 161 | filebase = _kvm_realloc(kd, kd->filebase, size); | |||
| 162 | if (filebase == NULL((void *)0)) | |||
| 163 | return (NULL((void *)0)); | |||
| 164 | ||||
| 165 | kd->filebase = filebase; | |||
| 166 | ||||
| 167 | /* get actual data */ | |||
| 168 | mib[5] = size / esize; | |||
| 169 | rv = sysctl(mib, 6, kd->filebase, &size, NULL((void *)0), 0); | |||
| 170 | if (rv == -1 && errno(*__errno()) != ENOMEM12) { | |||
| 171 | _kvm_syserr(kd, kd->program, | |||
| 172 | "kvm_getfiles"); | |||
| 173 | return (NULL((void *)0)); | |||
| 174 | } | |||
| 175 | } while (rv == -1); | |||
| 176 | ||||
| 177 | *cnt = size / esize; | |||
| 178 | return (kd->filebase); | |||
| 179 | } else { | |||
| 180 | if (esize > sizeof(struct kinfo_file)) { | |||
| 181 | _kvm_syserr(kd, kd->program, | |||
| 182 | "kvm_getfiles: unknown fields requested: libkvm out of date?"); | |||
| 183 | return (NULL((void *)0)); | |||
| 184 | } | |||
| 185 | deadway: | |||
| 186 | switch (op) { | |||
| 187 | case KERN_FILE_BYFILE1: | |||
| 188 | return (kvm_deadfile_byfile(kd, op, arg, esize, cnt)); | |||
| 189 | break; | |||
| 190 | case KERN_FILE_BYPID2: | |||
| 191 | case KERN_FILE_BYUID3: | |||
| 192 | return (kvm_deadfile_byid(kd, op, arg, esize, cnt)); | |||
| 193 | break; | |||
| 194 | default: | |||
| 195 | return (NULL((void *)0)); | |||
| 196 | } | |||
| 197 | } | |||
| 198 | } | |||
| 199 | ||||
| 200 | static struct kinfo_file * | |||
| 201 | kvm_deadfile_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt) | |||
| 202 | { | |||
| 203 | struct nlist nl[3], *p; | |||
| 204 | size_t buflen; | |||
| 205 | int n = 0; | |||
| 206 | char *where; | |||
| 207 | struct kinfo_file kf; | |||
| 208 | struct file *fp, file; | |||
| 209 | struct filelist filehead; | |||
| 210 | int nfiles; | |||
| 211 | ||||
| 212 | nl[0].n_name = "_filehead"; | |||
| 213 | nl[1].n_name = "_numfiles"; | |||
| 214 | nl[2].n_name = 0; | |||
| 215 | ||||
| 216 | if (kvm_nlist(kd, nl) != 0) { | |||
| 217 | for (p = nl; p->n_type != 0; ++p) | |||
| 218 | ; | |||
| 219 | _kvm_err(kd, kd->program, | |||
| 220 | "%s: no such symbol", p->n_name); | |||
| 221 | return (NULL((void *)0)); | |||
| 222 | } | |||
| 223 | if (KREAD(kd, nl[0].n_value, &filehead)(kvm_read(kd, nl[0].n_value, (void *)(&filehead), sizeof( *&filehead)) != sizeof(*&filehead))) { | |||
| 224 | _kvm_err(kd, kd->program, "can't read filehead"); | |||
| 225 | return (NULL((void *)0)); | |||
| 226 | } | |||
| 227 | if (KREAD(kd, nl[1].n_value, &nfiles)(kvm_read(kd, nl[1].n_value, (void *)(&nfiles), sizeof(*& nfiles)) != sizeof(*&nfiles))) { | |||
| 228 | _kvm_err(kd, kd->program, "can't read nfiles"); | |||
| 229 | return (NULL((void *)0)); | |||
| 230 | } | |||
| 231 | where = _kvm_reallocarray(kd, kd->filebase, nfiles, esize); | |||
| 232 | if (where == NULL((void *)0)) | |||
| 233 | return (NULL((void *)0)); | |||
| 234 | ||||
| 235 | kd->filebase = (void *)where; | |||
| 236 | buflen = nfiles * esize; | |||
| 237 | ||||
| 238 | for (fp = LIST_FIRST(&filehead)((&filehead)->lh_first); | |||
| 239 | fp != NULL((void *)0) && esize <= buflen; | |||
| 240 | fp = LIST_NEXT(&file, f_list)((&file)->f_list.le_next)) { | |||
| 241 | if (KREAD(kd, (u_long)fp, &file)(kvm_read(kd, (u_long)fp, (void *)(&file), sizeof(*&file )) != sizeof(*&file))) { | |||
| 242 | _kvm_err(kd, kd->program, "can't read kfp"); | |||
| 243 | return (NULL((void *)0)); | |||
| 244 | } | |||
| 245 | if (file.f_count == 0) | |||
| 246 | continue; | |||
| 247 | if (arg != 0 && file.f_type != arg) | |||
| 248 | continue; | |||
| 249 | if (fill_file(kd, &kf, &file, (u_long)fp, NULL((void *)0), NULL((void *)0), 0, 0) | |||
| 250 | == -1) | |||
| 251 | return (NULL((void *)0)); | |||
| 252 | memcpy(where, &kf, esize); | |||
| 253 | where += esize; | |||
| 254 | buflen -= esize; | |||
| 255 | n++; | |||
| 256 | } | |||
| 257 | if (n != nfiles) { | |||
| 258 | _kvm_err(kd, kd->program, "inconsistent nfiles"); | |||
| 259 | return (NULL((void *)0)); | |||
| 260 | } | |||
| 261 | *cnt = n; | |||
| 262 | return (kd->filebase); | |||
| 263 | } | |||
| 264 | ||||
| 265 | static struct kinfo_file * | |||
| 266 | kvm_deadfile_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt) | |||
| 267 | { | |||
| 268 | size_t buflen; | |||
| 269 | struct nlist nl[4], *np; | |||
| 270 | int n = 0, matched = 0; | |||
| 271 | char *where; | |||
| 272 | struct kinfo_file kf; | |||
| 273 | struct file *fp, file; | |||
| 274 | struct filelist filehead; | |||
| 275 | struct filedesc0 filed0; | |||
| 276 | #define filedfiled0.fd_fd filed0.fd_fd | |||
| 277 | struct processlist allprocess; | |||
| 278 | struct process *pr, process; | |||
| 279 | struct ucred ucred; | |||
| 280 | char *filebuf = NULL((void *)0); | |||
| 281 | int i, nfiles; | |||
| 282 | ||||
| 283 | nl[0].n_name = "_filehead"; | |||
| 284 | nl[1].n_name = "_numfiles"; | |||
| 285 | nl[2].n_name = "_allprocess"; | |||
| 286 | nl[3].n_name = 0; | |||
| 287 | ||||
| 288 | if (kvm_nlist(kd, nl) != 0) { | |||
| 289 | for (np = nl; np->n_type != 0; ++np) | |||
| 290 | ; | |||
| 291 | _kvm_err(kd, kd->program, | |||
| 292 | "%s: no such symbol", np->n_name); | |||
| 293 | return (NULL((void *)0)); | |||
| 294 | } | |||
| 295 | if (KREAD(kd, nl[0].n_value, &filehead)(kvm_read(kd, nl[0].n_value, (void *)(&filehead), sizeof( *&filehead)) != sizeof(*&filehead))) { | |||
| 296 | _kvm_err(kd, kd->program, "can't read filehead"); | |||
| 297 | return (NULL((void *)0)); | |||
| 298 | } | |||
| 299 | if (KREAD(kd, nl[1].n_value, &nfiles)(kvm_read(kd, nl[1].n_value, (void *)(&nfiles), sizeof(*& nfiles)) != sizeof(*&nfiles))) { | |||
| 300 | _kvm_err(kd, kd->program, "can't read nfiles"); | |||
| 301 | return (NULL((void *)0)); | |||
| 302 | } | |||
| 303 | if (KREAD(kd, nl[2].n_value, &allprocess)(kvm_read(kd, nl[2].n_value, (void *)(&allprocess), sizeof (*&allprocess)) != sizeof(*&allprocess))) { | |||
| 304 | _kvm_err(kd, kd->program, "can't read allprocess"); | |||
| 305 | return (NULL((void *)0)); | |||
| 306 | } | |||
| 307 | /* this may be more room than we need but counting is expensive */ | |||
| 308 | where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize); | |||
| 309 | if (where == NULL((void *)0)) | |||
| 310 | return (NULL((void *)0)); | |||
| 311 | ||||
| 312 | kd->filebase = (void *)where; | |||
| 313 | buflen = (nfiles + 10) * esize; | |||
| 314 | ||||
| 315 | if (op != KERN_FILE_BYPID2 || arg <= 0) | |||
| 316 | matched = 1; | |||
| 317 | ||||
| 318 | for (pr = LIST_FIRST(&allprocess)((&allprocess)->lh_first); | |||
| 319 | pr != NULL((void *)0); | |||
| 320 | pr = LIST_NEXT(&process, ps_list)((&process)->ps_list.le_next)) { | |||
| 321 | if (KREAD(kd, (u_long)pr, &process)(kvm_read(kd, (u_long)pr, (void *)(&process), sizeof(*& process)) != sizeof(*&process))) { | |||
| 322 | _kvm_err(kd, kd->program, "can't read process at %lx", | |||
| 323 | (u_long)pr); | |||
| 324 | goto cleanup; | |||
| 325 | } | |||
| 326 | ||||
| 327 | /* skip system, exiting, embryonic and undead processes */ | |||
| 328 | if (process.ps_flags & (PS_SYSTEM0x00010000 | PS_EMBRYO0x00020000 | PS_EXITING0x00000008)) | |||
| 329 | continue; | |||
| 330 | ||||
| 331 | if (op == KERN_FILE_BYPID2) { | |||
| 332 | /* check if this is the pid we are looking for */ | |||
| 333 | if (arg > 0 && process.ps_pid != (pid_t)arg) | |||
| 334 | continue; | |||
| 335 | matched = 1; | |||
| 336 | } | |||
| 337 | ||||
| 338 | if (KREAD(kd, (u_long)process.ps_ucred, &ucred)(kvm_read(kd, (u_long)process.ps_ucred, (void *)(&ucred), sizeof(*&ucred)) != sizeof(*&ucred))) { | |||
| 339 | _kvm_err(kd, kd->program, "can't read ucred at %lx", | |||
| 340 | (u_long)process.ps_ucred); | |||
| 341 | goto cleanup; | |||
| 342 | } | |||
| 343 | process.ps_ucred = &ucred; | |||
| 344 | ||||
| 345 | if (op == KERN_FILE_BYUID3 && arg >= 0 && | |||
| 346 | process.ps_ucred->cr_uid != (uid_t)arg) { | |||
| 347 | /* not the uid we are looking for */ | |||
| 348 | continue; | |||
| 349 | } | |||
| 350 | ||||
| 351 | if (KREAD(kd, (u_long)process.ps_fd, &filed0)(kvm_read(kd, (u_long)process.ps_fd, (void *)(&filed0), sizeof (*&filed0)) != sizeof(*&filed0))) { | |||
| 352 | _kvm_err(kd, kd->program, "can't read filedesc at %lx", | |||
| 353 | (u_long)process.ps_fd); | |||
| 354 | goto cleanup; | |||
| 355 | } | |||
| 356 | if ((char *)process.ps_fd + offsetof(struct filedesc0,fd_dfiles)__builtin_offsetof(struct filedesc0, fd_dfiles) | |||
| 357 | == (char *)filedfiled0.fd_fd.fd_ofiles) { | |||
| 358 | filedfiled0.fd_fd.fd_ofiles = filed0.fd_dfiles; | |||
| 359 | filedfiled0.fd_fd.fd_ofileflags = filed0.fd_dfileflags; | |||
| 360 | } else { | |||
| 361 | size_t fsize; | |||
| 362 | char *tmp = reallocarray(filebuf, | |||
| 363 | filedfiled0.fd_fd.fd_nfiles, OFILESIZE(sizeof(struct file *) + sizeof(char))); | |||
| 364 | ||||
| 365 | fsize = filedfiled0.fd_fd.fd_nfiles * OFILESIZE(sizeof(struct file *) + sizeof(char)); | |||
| 366 | if (tmp == NULL((void *)0)) { | |||
| 367 | _kvm_syserr(kd, kd->program, "realloc ofiles"); | |||
| 368 | goto cleanup; | |||
| 369 | } | |||
| 370 | filebuf = tmp; | |||
| 371 | if (kvm_read(kd, (u_long)filedfiled0.fd_fd.fd_ofiles, filebuf, | |||
| 372 | fsize) != fsize) { | |||
| 373 | _kvm_err(kd, kd->program, | |||
| 374 | "can't read fd_ofiles"); | |||
| 375 | goto cleanup; | |||
| 376 | } | |||
| 377 | filedfiled0.fd_fd.fd_ofiles = (void *)filebuf; | |||
| 378 | filedfiled0.fd_fd.fd_ofileflags = filebuf + | |||
| 379 | (filedfiled0.fd_fd.fd_nfiles * sizeof(struct file *)); | |||
| 380 | } | |||
| 381 | process.ps_fd = &filedfiled0.fd_fd; | |||
| 382 | ||||
| 383 | if (process.ps_textvp) { | |||
| 384 | if (buflen < esize) | |||
| 385 | goto done; | |||
| 386 | if (fill_file(kd, &kf, NULL((void *)0), 0, process.ps_textvp, | |||
| 387 | &process, KERN_FILE_TEXT-1, process.ps_pid) == -1) | |||
| 388 | goto cleanup; | |||
| 389 | memcpy(where, &kf, esize); | |||
| 390 | where += esize; | |||
| 391 | buflen -= esize; | |||
| 392 | n++; | |||
| 393 | } | |||
| 394 | if (filedfiled0.fd_fd.fd_cdir) { | |||
| 395 | if (buflen < esize) | |||
| 396 | goto done; | |||
| 397 | if (fill_file(kd, &kf, NULL((void *)0), 0, filedfiled0.fd_fd.fd_cdir, | |||
| 398 | &process, KERN_FILE_CDIR-2, process.ps_pid) == -1) | |||
| 399 | goto cleanup; | |||
| 400 | memcpy(where, &kf, esize); | |||
| 401 | where += esize; | |||
| 402 | buflen -= esize; | |||
| 403 | n++; | |||
| 404 | } | |||
| 405 | if (filedfiled0.fd_fd.fd_rdir) { | |||
| 406 | if (buflen < esize) | |||
| 407 | goto done; | |||
| 408 | if (fill_file(kd, &kf, NULL((void *)0), 0, filedfiled0.fd_fd.fd_rdir, | |||
| 409 | &process, KERN_FILE_RDIR-3, process.ps_pid) == -1) | |||
| 410 | goto cleanup; | |||
| 411 | memcpy(where, &kf, esize); | |||
| 412 | where += esize; | |||
| 413 | buflen -= esize; | |||
| 414 | n++; | |||
| 415 | } | |||
| 416 | if (process.ps_tracevp) { | |||
| 417 | if (buflen < esize) | |||
| 418 | goto done; | |||
| 419 | if (fill_file(kd, &kf, NULL((void *)0), 0, process.ps_tracevp, | |||
| 420 | &process, KERN_FILE_TRACE-4, process.ps_pid) == -1) | |||
| 421 | goto cleanup; | |||
| 422 | memcpy(where, &kf, esize); | |||
| 423 | where += esize; | |||
| 424 | buflen -= esize; | |||
| 425 | n++; | |||
| 426 | } | |||
| 427 | ||||
| 428 | if (filedfiled0.fd_fd.fd_nfiles < 0 || | |||
| 429 | filedfiled0.fd_fd.fd_lastfile >= filedfiled0.fd_fd.fd_nfiles || | |||
| 430 | filedfiled0.fd_fd.fd_freefile > filedfiled0.fd_fd.fd_lastfile + 1) { | |||
| 431 | _kvm_err(kd, kd->program, | |||
| 432 | "filedesc corrupted at %lx for pid %d", | |||
| 433 | (u_long)process.ps_fd, process.ps_pid); | |||
| 434 | goto cleanup; | |||
| 435 | } | |||
| 436 | ||||
| 437 | for (i = 0; i < filedfiled0.fd_fd.fd_nfiles; i++) { | |||
| 438 | if (buflen < esize) | |||
| 439 | goto done; | |||
| 440 | if ((fp = filedfiled0.fd_fd.fd_ofiles[i]) == NULL((void *)0)) | |||
| 441 | continue; | |||
| 442 | if (KREAD(kd, (u_long)fp, &file)(kvm_read(kd, (u_long)fp, (void *)(&file), sizeof(*&file )) != sizeof(*&file))) { | |||
| 443 | _kvm_err(kd, kd->program, "can't read file"); | |||
| 444 | goto cleanup; | |||
| 445 | } | |||
| 446 | if (fill_file(kd, &kf, &file, (u_long)fp, NULL((void *)0), | |||
| 447 | &process, i, process.ps_pid) == -1) | |||
| 448 | goto cleanup; | |||
| 449 | memcpy(where, &kf, esize); | |||
| 450 | where += esize; | |||
| 451 | buflen -= esize; | |||
| 452 | n++; | |||
| 453 | } | |||
| 454 | } | |||
| 455 | if (!matched) { | |||
| 456 | errno(*__errno()) = ESRCH3; | |||
| 457 | goto cleanup; | |||
| 458 | } | |||
| 459 | done: | |||
| 460 | *cnt = n; | |||
| 461 | free(filebuf); | |||
| 462 | return (kd->filebase); | |||
| 463 | cleanup: | |||
| 464 | free(filebuf); | |||
| 465 | return (NULL((void *)0)); | |||
| 466 | } | |||
| 467 | ||||
| 468 | static int | |||
| 469 | fill_file(kvm_t *kd, struct kinfo_file *kf, struct file *fp, u_long fpaddr, | |||
| 470 | struct vnode *vp, struct process *pr, int fd, pid_t pid) | |||
| 471 | { | |||
| 472 | struct ucred f_cred; | |||
| 473 | ||||
| 474 | memset(kf, 0, sizeof(*kf)); | |||
| 475 | ||||
| 476 | kf->fd_fd = fd; /* might not really be an fd */ | |||
| 477 | ||||
| 478 | if (fp
| |||
| 479 | /* Fill in f_cred */ | |||
| 480 | if (KREAD(kd, (u_long)fp->f_cred, &f_cred)(kvm_read(kd, (u_long)fp->f_cred, (void *)(&f_cred), sizeof (*&f_cred)) != sizeof(*&f_cred))) { | |||
| 481 | _kvm_err(kd, kd->program, "can't read f_cred"); | |||
| 482 | return (-1); | |||
| 483 | } | |||
| 484 | ||||
| 485 | kf->f_fileaddr = PTRTOINT64(fpaddr)((u_int64_t)(u_long)(fpaddr)); | |||
| 486 | kf->f_flag = fp->f_flag; | |||
| 487 | kf->f_iflags = fp->f_iflags; | |||
| 488 | kf->f_type = fp->f_type; | |||
| 489 | kf->f_count = fp->f_count; | |||
| 490 | kf->f_ucred = PTRTOINT64(fp->f_cred)((u_int64_t)(u_long)(fp->f_cred)); | |||
| 491 | kf->f_uid = f_cred.cr_uid; | |||
| 492 | kf->f_gid = f_cred.cr_gid; | |||
| 493 | kf->f_ops = PTRTOINT64(fp->f_ops)((u_int64_t)(u_long)(fp->f_ops)); | |||
| 494 | kf->f_offset = fp->f_offset; | |||
| 495 | kf->f_data = PTRTOINT64(fp->f_data)((u_int64_t)(u_long)(fp->f_data)); | |||
| 496 | kf->f_usecount = 0; | |||
| 497 | ||||
| 498 | kf->f_rxfer = fp->f_rxfer; | |||
| 499 | kf->f_rwfer = fp->f_wxfer; | |||
| 500 | kf->f_seek = fp->f_seek; | |||
| 501 | kf->f_rbytes = fp->f_rbytes; | |||
| 502 | kf->f_wbytes = fp->f_wbytes; | |||
| 503 | } else if (vp != NULL((void *)0)) { | |||
| 504 | /* fake it */ | |||
| 505 | kf->f_type = DTYPE_VNODE1; | |||
| 506 | kf->f_flag = FREAD0x0001; | |||
| 507 | if (fd == KERN_FILE_TRACE-4) | |||
| 508 | kf->f_flag |= FWRITE0x0002; | |||
| 509 | kf->f_data = PTRTOINT64(vp)((u_int64_t)(u_long)(vp)); | |||
| 510 | } | |||
| 511 | ||||
| 512 | /* information about the object associated with this file */ | |||
| 513 | switch (kf->f_type) { | |||
| 514 | case DTYPE_VNODE1: { | |||
| 515 | struct vnode vbuf; | |||
| 516 | ||||
| 517 | if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)(kvm_read(kd, (u_long)(fp ? fp->f_data : vp), (void *)(& vbuf), sizeof(*&vbuf)) != sizeof(*&vbuf))) { | |||
| 518 | _kvm_err(kd, kd->program, "can't read vnode"); | |||
| 519 | return (-1); | |||
| 520 | } | |||
| 521 | vp = &vbuf; | |||
| 522 | ||||
| 523 | kf->v_un = PTRTOINT64(vp->v_un.vu_socket)((u_int64_t)(u_long)(vp->v_un.vu_socket)); | |||
| 524 | kf->v_type = vp->v_type; | |||
| 525 | kf->v_tag = vp->v_tag; | |||
| 526 | kf->v_flag = vp->v_flag; | |||
| 527 | kf->v_data = PTRTOINT64(vp->v_data)((u_int64_t)(u_long)(vp->v_data)); | |||
| 528 | kf->v_mount = PTRTOINT64(vp->v_mount)((u_int64_t)(u_long)(vp->v_mount)); | |||
| 529 | ||||
| 530 | if (vp->v_mount != NULL((void *)0)) { | |||
| 531 | struct mount mount; | |||
| 532 | ||||
| 533 | if (KREAD(kd, (u_long)vp->v_mount, &mount)(kvm_read(kd, (u_long)vp->v_mount, (void *)(&mount), sizeof (*&mount)) != sizeof(*&mount))) { | |||
| 534 | _kvm_err(kd, kd->program, "can't read v_mount"); | |||
| 535 | return (-1); | |||
| 536 | } | |||
| 537 | ||||
| 538 | strlcpy(kf->f_mntonname, mount.mnt_stat.f_mntonname, | |||
| 539 | sizeof(kf->f_mntonname)); | |||
| 540 | } | |||
| 541 | ||||
| 542 | /* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */ | |||
| 543 | filestat(kd, kf, vp); | |||
| 544 | break; | |||
| 545 | } | |||
| 546 | ||||
| 547 | case DTYPE_SOCKET2: { | |||
| 548 | struct socket sock; | |||
| 549 | struct sosplice ssp; | |||
| 550 | struct protosw protosw; | |||
| 551 | struct domain domain; | |||
| 552 | ||||
| 553 | if (KREAD(kd, (u_long)fp->f_data, &sock)(kvm_read(kd, (u_long)fp->f_data, (void *)(&sock), sizeof (*&sock)) != sizeof(*&sock))) { | |||
| 554 | _kvm_err(kd, kd->program, "can't read socket"); | |||
| 555 | return (-1); | |||
| 556 | } | |||
| 557 | ||||
| 558 | kf->so_type = sock.so_type; | |||
| 559 | kf->so_state = sock.so_state; | |||
| 560 | kf->so_pcb = PTRTOINT64(sock.so_pcb)((u_int64_t)(u_long)(sock.so_pcb)); | |||
| 561 | if (KREAD(kd, (u_long)sock.so_proto, &protosw)(kvm_read(kd, (u_long)sock.so_proto, (void *)(&protosw), sizeof (*&protosw)) != sizeof(*&protosw))) { | |||
| 562 | _kvm_err(kd, kd->program, "can't read protosw"); | |||
| 563 | return (-1); | |||
| 564 | } | |||
| 565 | kf->so_protocol = protosw.pr_protocol; | |||
| 566 | if (KREAD(kd, (u_long)protosw.pr_domain, &domain)(kvm_read(kd, (u_long)protosw.pr_domain, (void *)(&domain ), sizeof(*&domain)) != sizeof(*&domain))) { | |||
| 567 | _kvm_err(kd, kd->program, "can't read domain"); | |||
| 568 | return (-1); | |||
| 569 | } | |||
| 570 | kf->so_family = domain.dom_family; | |||
| 571 | kf->so_rcv_cc = sock.so_rcv.sb_cc; | |||
| 572 | kf->so_snd_cc = sock.so_snd.sb_cc; | |||
| 573 | if (sock.so_sp) { | |||
| 574 | if (KREAD(kd, (u_long)sock.so_sp, &ssp)(kvm_read(kd, (u_long)sock.so_sp, (void *)(&ssp), sizeof( *&ssp)) != sizeof(*&ssp))) { | |||
| 575 | _kvm_err(kd, kd->program, "can't read splice"); | |||
| 576 | return (-1); | |||
| 577 | } | |||
| 578 | if (ssp.ssp_socket) { | |||
| 579 | kf->so_splice = PTRTOINT64(ssp.ssp_socket)((u_int64_t)(u_long)(ssp.ssp_socket)); | |||
| 580 | kf->so_splicelen = ssp.ssp_len; | |||
| 581 | } else if (ssp.ssp_soback) { | |||
| 582 | kf->so_splicelen = -1; | |||
| 583 | } | |||
| 584 | } | |||
| 585 | if (!sock.so_pcb) | |||
| 586 | break; | |||
| 587 | switch (kf->so_family) { | |||
| 588 | case AF_INET2: { | |||
| 589 | struct inpcb inpcb; | |||
| 590 | ||||
| 591 | if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)(kvm_read(kd, (u_long)sock.so_pcb, (void *)(&inpcb), sizeof (*&inpcb)) != sizeof(*&inpcb))) { | |||
| 592 | _kvm_err(kd, kd->program, "can't read inpcb"); | |||
| 593 | return (-1); | |||
| 594 | } | |||
| 595 | kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb)((u_int64_t)(u_long)(inpcb.inp_ppcb)); | |||
| 596 | kf->inp_lport = inpcb.inp_lport; | |||
| 597 | kf->inp_laddru[0] = inpcb.inp_laddrinp_laddru.iau_a4u.inaddr.s_addr; | |||
| 598 | kf->inp_fport = inpcb.inp_fport; | |||
| 599 | kf->inp_faddru[0] = inpcb.inp_faddrinp_faddru.iau_a4u.inaddr.s_addr; | |||
| 600 | kf->inp_rtableid = inpcb.inp_rtableid; | |||
| 601 | if (sock.so_type == SOCK_RAW3) | |||
| 602 | kf->inp_proto = inpcb.inp_ipinp_hu.hu_ip.ip_p; | |||
| 603 | if (protosw.pr_protocol == IPPROTO_TCP6) { | |||
| 604 | struct tcpcb tcpcb; | |||
| 605 | if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)(kvm_read(kd, (u_long)inpcb.inp_ppcb, (void *)(&tcpcb), sizeof (*&tcpcb)) != sizeof(*&tcpcb))) { | |||
| 606 | _kvm_err(kd, kd->program, | |||
| 607 | "can't read tcpcb"); | |||
| 608 | return (-1); | |||
| 609 | } | |||
| 610 | kf->t_rcv_wnd = tcpcb.rcv_wnd; | |||
| 611 | kf->t_snd_wnd = tcpcb.snd_wnd; | |||
| 612 | kf->t_snd_cwnd = tcpcb.snd_cwnd; | |||
| 613 | kf->t_state = tcpcb.t_state; | |||
| 614 | } | |||
| 615 | break; | |||
| 616 | } | |||
| 617 | case AF_INET624: { | |||
| 618 | struct inpcb inpcb; | |||
| 619 | #define s6_addr32__u6_addr.__u6_addr32 __u6_addr.__u6_addr32 | |||
| 620 | ||||
| 621 | if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)(kvm_read(kd, (u_long)sock.so_pcb, (void *)(&inpcb), sizeof (*&inpcb)) != sizeof(*&inpcb))) { | |||
| 622 | _kvm_err(kd, kd->program, "can't read inpcb"); | |||
| 623 | return (-1); | |||
| 624 | } | |||
| 625 | kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb)((u_int64_t)(u_long)(inpcb.inp_ppcb)); | |||
| 626 | kf->inp_lport = inpcb.inp_lport; | |||
| 627 | kf->inp_laddru[0] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[0]; | |||
| 628 | kf->inp_laddru[1] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[1]; | |||
| 629 | kf->inp_laddru[2] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[2]; | |||
| 630 | kf->inp_laddru[3] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[3]; | |||
| 631 | kf->inp_fport = inpcb.inp_fport; | |||
| 632 | kf->inp_faddru[0] = inpcb.inp_laddr6inp_laddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[0]; | |||
| 633 | kf->inp_faddru[1] = inpcb.inp_faddr6inp_faddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[1]; | |||
| 634 | kf->inp_faddru[2] = inpcb.inp_faddr6inp_faddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[2]; | |||
| 635 | kf->inp_faddru[3] = inpcb.inp_faddr6inp_faddru.iau_addr6.s6_addr32__u6_addr.__u6_addr32[3]; | |||
| 636 | kf->inp_rtableid = inpcb.inp_rtableid; | |||
| 637 | if (sock.so_type == SOCK_RAW3) | |||
| 638 | kf->inp_proto = inpcb.inp_ipv6inp_hu.hu_ipv6.ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt; | |||
| 639 | if (protosw.pr_protocol == IPPROTO_TCP6) { | |||
| 640 | struct tcpcb tcpcb; | |||
| 641 | if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)(kvm_read(kd, (u_long)inpcb.inp_ppcb, (void *)(&tcpcb), sizeof (*&tcpcb)) != sizeof(*&tcpcb))) { | |||
| 642 | _kvm_err(kd, kd->program, | |||
| 643 | "can't read tcpcb"); | |||
| 644 | return (-1); | |||
| 645 | } | |||
| 646 | kf->t_rcv_wnd = tcpcb.rcv_wnd; | |||
| 647 | kf->t_snd_wnd = tcpcb.snd_wnd; | |||
| 648 | kf->t_snd_cwnd = tcpcb.snd_cwnd; | |||
| 649 | kf->t_state = tcpcb.t_state; | |||
| 650 | } | |||
| 651 | break; | |||
| 652 | } | |||
| 653 | case AF_UNIX1: { | |||
| 654 | struct unpcb unpcb; | |||
| 655 | ||||
| 656 | if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)(kvm_read(kd, (u_long)sock.so_pcb, (void *)(&unpcb), sizeof (*&unpcb)) != sizeof(*&unpcb))) { | |||
| 657 | _kvm_err(kd, kd->program, "can't read unpcb"); | |||
| 658 | return (-1); | |||
| 659 | } | |||
| 660 | kf->f_msgcount = unpcb.unp_msgcount; | |||
| 661 | kf->unp_conn = PTRTOINT64(unpcb.unp_conn)((u_int64_t)(u_long)(unpcb.unp_conn)); | |||
| 662 | kf->unp_refs = PTRTOINT64(((u_int64_t)(u_long)(((&unpcb.unp_refs)->slh_first))) | |||
| 663 | SLIST_FIRST(&unpcb.unp_refs))((u_int64_t)(u_long)(((&unpcb.unp_refs)->slh_first))); | |||
| 664 | kf->unp_nextref = PTRTOINT64(((u_int64_t)(u_long)(((&unpcb)->unp_nextref.sle_next)) ) | |||
| 665 | SLIST_NEXT(&unpcb, unp_nextref))((u_int64_t)(u_long)(((&unpcb)->unp_nextref.sle_next)) ); | |||
| 666 | kf->v_un = PTRTOINT64(unpcb.unp_vnode)((u_int64_t)(u_long)(unpcb.unp_vnode)); | |||
| 667 | if (unpcb.unp_addr != NULL((void *)0)) { | |||
| 668 | struct mbuf mb; | |||
| 669 | struct sockaddr_un un; | |||
| 670 | ||||
| 671 | if (KREAD(kd, (u_long)unpcb.unp_addr, &mb)(kvm_read(kd, (u_long)unpcb.unp_addr, (void *)(&mb), sizeof (*&mb)) != sizeof(*&mb))) { | |||
| 672 | _kvm_err(kd, kd->program, | |||
| 673 | "can't read sockaddr_un mbuf"); | |||
| 674 | return (-1); | |||
| 675 | } | |||
| 676 | if (KREAD(kd, (u_long)mb.m_data, &un)(kvm_read(kd, (u_long)mb.m_hdr.mh_data, (void *)(&un), sizeof (*&un)) != sizeof(*&un))) { | |||
| 677 | _kvm_err(kd, kd->program, | |||
| 678 | "can't read sockaddr_un"); | |||
| 679 | return (-1); | |||
| 680 | } | |||
| 681 | ||||
| 682 | kf->unp_addr = PTRTOINT64(unpcb.unp_addr)((u_int64_t)(u_long)(unpcb.unp_addr)); | |||
| 683 | memcpy(kf->unp_path, un.sun_path, un.sun_len | |||
| 684 | - offsetof(struct sockaddr_un,sun_path)__builtin_offsetof(struct sockaddr_un, sun_path)); | |||
| 685 | } | |||
| 686 | ||||
| 687 | break; | |||
| 688 | } | |||
| 689 | } | |||
| 690 | break; | |||
| 691 | } | |||
| 692 | ||||
| 693 | case DTYPE_PIPE3: { | |||
| 694 | struct pipe pipe; | |||
| 695 | ||||
| 696 | if (KREAD(kd, (u_long)fp->f_data, &pipe)(kvm_read(kd, (u_long)fp->f_data, (void *)(&pipe), sizeof (*&pipe)) != sizeof(*&pipe))) { | |||
| 697 | _kvm_err(kd, kd->program, "can't read pipe"); | |||
| 698 | return (-1); | |||
| 699 | } | |||
| 700 | kf->pipe_peer = PTRTOINT64(pipe.pipe_peer)((u_int64_t)(u_long)(pipe.pipe_peer)); | |||
| 701 | kf->pipe_state = pipe.pipe_state; | |||
| 702 | break; | |||
| 703 | } | |||
| 704 | ||||
| 705 | case DTYPE_KQUEUE4: { | |||
| 706 | struct kqueue kqi; | |||
| 707 | ||||
| 708 | if (KREAD(kd, (u_long)fp->f_data, &kqi)(kvm_read(kd, (u_long)fp->f_data, (void *)(&kqi), sizeof (*&kqi)) != sizeof(*&kqi))) { | |||
| 709 | _kvm_err(kd, kd->program, "can't read kqi"); | |||
| 710 | return (-1); | |||
| 711 | } | |||
| 712 | kf->kq_count = kqi.kq_count; | |||
| 713 | kf->kq_state = kqi.kq_state; | |||
| 714 | break; | |||
| 715 | } | |||
| 716 | } | |||
| 717 | ||||
| 718 | /* per-process information for KERN_FILE_BY[PU]ID */ | |||
| 719 | if (pr != NULL((void *)0)) { | |||
| 720 | kf->p_pid = pid; | |||
| 721 | kf->p_uid = pr->ps_ucred->cr_uid; | |||
| 722 | kf->p_gid = pr->ps_ucred->cr_gid; | |||
| 723 | kf->p_tid = -1; | |||
| 724 | strlcpy(kf->p_comm, pr->ps_comm, sizeof(kf->p_comm)); | |||
| 725 | if (pr->ps_fd != NULL((void *)0)) | |||
| 726 | kf->fd_ofileflags = pr->ps_fd->fd_ofileflags[fd]; | |||
| 727 | } | |||
| 728 | ||||
| 729 | return (0); | |||
| 730 | } | |||
| 731 | ||||
| 732 | mode_t | |||
| 733 | _kvm_getftype(enum vtype v_type) | |||
| 734 | { | |||
| 735 | mode_t ftype = 0; | |||
| 736 | ||||
| 737 | switch (v_type) { | |||
| 738 | case VREG: | |||
| 739 | ftype = S_IFREG0100000; | |||
| 740 | break; | |||
| 741 | case VDIR: | |||
| 742 | ftype = S_IFDIR0040000; | |||
| 743 | break; | |||
| 744 | case VBLK: | |||
| 745 | ftype = S_IFBLK0060000; | |||
| 746 | break; | |||
| 747 | case VCHR: | |||
| 748 | ftype = S_IFCHR0020000; | |||
| 749 | break; | |||
| 750 | case VLNK: | |||
| 751 | ftype = S_IFLNK0120000; | |||
| 752 | break; | |||
| 753 | case VSOCK: | |||
| 754 | ftype = S_IFSOCK0140000; | |||
| 755 | break; | |||
| 756 | case VFIFO: | |||
| 757 | ftype = S_IFIFO0010000; | |||
| 758 | break; | |||
| 759 | case VNON: | |||
| 760 | case VBAD: | |||
| 761 | break; | |||
| 762 | } | |||
| 763 | ||||
| 764 | return (ftype); | |||
| 765 | } | |||
| 766 | ||||
| 767 | static int | |||
| 768 | ufs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
| 769 | { | |||
| 770 | struct inode inode; | |||
| 771 | struct ufs1_dinode di1; | |||
| 772 | ||||
| 773 | if (KREAD(kd, (u_long)VTOI(vp), &inode)(kvm_read(kd, (u_long)((struct inode *)(vp)->v_data), (void *)(&inode), sizeof(*&inode)) != sizeof(*&inode))) { | |||
| 774 | _kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp)((struct inode *)(vp)->v_data)); | |||
| 775 | return (-1); | |||
| 776 | } | |||
| 777 | ||||
| 778 | if (KREAD(kd, (u_long)inode.i_din1, &di1)(kvm_read(kd, (u_long)inode.dinode_u.ffs1_din, (void *)(& di1), sizeof(*&di1)) != sizeof(*&di1))) { | |||
| 779 | _kvm_err(kd, kd->program, "can't read dinode at %p", | |||
| 780 | inode.i_din1dinode_u.ffs1_din); | |||
| 781 | return (-1); | |||
| 782 | } | |||
| 783 | ||||
| 784 | inode.i_din1dinode_u.ffs1_din = &di1; | |||
| 785 | ||||
| 786 | kf->va_fsid = inode.i_dev & 0xffff; | |||
| 787 | kf->va_fileid = (long)inode.i_number; | |||
| 788 | kf->va_mode = inode.i_ffs1_modedinode_u.ffs1_din->di_mode; | |||
| 789 | kf->va_size = inode.i_ffs1_sizedinode_u.ffs1_din->di_size; | |||
| 790 | kf->va_rdev = inode.i_ffs1_rdevdinode_u.ffs1_din->di_db[0]; | |||
| 791 | kf->va_nlink = inode.i_ffs1_nlinkdinode_u.ffs1_din->di_nlink; | |||
| 792 | ||||
| 793 | return (0); | |||
| 794 | } | |||
| 795 | ||||
| 796 | static int | |||
| 797 | ext2fs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
| 798 | { | |||
| 799 | struct inode inode; | |||
| 800 | struct ext2fs_dinode e2di; | |||
| 801 | ||||
| 802 | if (KREAD(kd, (u_long)VTOI(vp), &inode)(kvm_read(kd, (u_long)((struct inode *)(vp)->v_data), (void *)(&inode), sizeof(*&inode)) != sizeof(*&inode))) { | |||
| 803 | _kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp)((struct inode *)(vp)->v_data)); | |||
| 804 | return (-1); | |||
| 805 | } | |||
| 806 | ||||
| 807 | if (KREAD(kd, (u_long)inode.i_e2din, &e2di)(kvm_read(kd, (u_long)inode.dinode_u.e2fs_din, (void *)(& e2di), sizeof(*&e2di)) != sizeof(*&e2di))) { | |||
| 808 | _kvm_err(kd, kd->program, "can't read dinode at %p", | |||
| 809 | inode.i_e2dindinode_u.e2fs_din); | |||
| 810 | return (-1); | |||
| 811 | } | |||
| 812 | ||||
| 813 | inode.i_e2dindinode_u.e2fs_din = &e2di; | |||
| 814 | ||||
| 815 | kf->va_fsid = inode.i_dev & 0xffff; | |||
| 816 | kf->va_fileid = (long)inode.i_number; | |||
| 817 | kf->va_mode = inode.i_e2fs_modedinode_u.e2fs_din->e2di_mode; | |||
| 818 | kf->va_size = inode.i_e2fs_sizedinode_u.e2fs_din->e2di_size; | |||
| 819 | kf->va_rdev = 0; /* XXX */ | |||
| 820 | kf->va_nlink = inode.i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink; | |||
| 821 | ||||
| 822 | return (0); | |||
| 823 | } | |||
| 824 | ||||
| 825 | static int | |||
| 826 | msdos_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
| 827 | { | |||
| 828 | struct denode de; | |||
| 829 | struct msdosfsmount mp; | |||
| 830 | ||||
| 831 | if (KREAD(kd, (u_long)VTODE(vp), &de)(kvm_read(kd, (u_long)((struct denode *)(vp)->v_data), (void *)(&de), sizeof(*&de)) != sizeof(*&de))) { | |||
| 832 | _kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp)((struct denode *)(vp)->v_data)); | |||
| 833 | return (-1); | |||
| 834 | } | |||
| 835 | if (KREAD(kd, (u_long)de.de_pmp, &mp)(kvm_read(kd, (u_long)de.de_pmp, (void *)(&mp), sizeof(*& mp)) != sizeof(*&mp))) { | |||
| 836 | _kvm_err(kd, kd->program, "can't read mount struct at %p", | |||
| 837 | de.de_pmp); | |||
| 838 | return (-1); | |||
| 839 | } | |||
| 840 | ||||
| 841 | kf->va_fsid = de.de_dev & 0xffff; | |||
| 842 | kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */ | |||
| 843 | kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type); | |||
| 844 | kf->va_size = de.de_FileSize; | |||
| 845 | kf->va_rdev = 0; /* msdosfs doesn't support device files */ | |||
| 846 | kf->va_nlink = 1; | |||
| 847 | ||||
| 848 | return (0); | |||
| 849 | } | |||
| 850 | ||||
| 851 | static int | |||
| 852 | nfs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
| 853 | { | |||
| 854 | struct nfsnode nfsnode; | |||
| 855 | ||||
| 856 | if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)(kvm_read(kd, (u_long)((struct nfsnode *)(vp)->v_data), (void *)(&nfsnode), sizeof(*&nfsnode)) != sizeof(*&nfsnode ))) { | |||
| 857 | _kvm_err(kd, kd->program, "can't read nfsnode at %p", | |||
| 858 | VTONFS(vp)((struct nfsnode *)(vp)->v_data)); | |||
| 859 | return (-1); | |||
| 860 | } | |||
| 861 | kf->va_fsid = nfsnode.n_vattr.va_fsid; | |||
| 862 | kf->va_fileid = nfsnode.n_vattr.va_fileid; | |||
| 863 | kf->va_size = nfsnode.n_size; | |||
| 864 | kf->va_rdev = nfsnode.n_vattr.va_rdev; | |||
| 865 | kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type); | |||
| 866 | kf->va_nlink = nfsnode.n_vattr.va_nlink; | |||
| 867 | ||||
| 868 | return (0); | |||
| 869 | } | |||
| 870 | ||||
| 871 | static int | |||
| 872 | spec_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
| 873 | { | |||
| 874 | struct specinfo specinfo; | |||
| 875 | struct vnode parent; | |||
| 876 | ||||
| 877 | if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)(kvm_read(kd, (u_long)vp->v_un.vu_specinfo, (void *)(& specinfo), sizeof(*&specinfo)) != sizeof(*&specinfo))) { | |||
| 878 | _kvm_err(kd, kd->program, "can't read specinfo at %p", | |||
| 879 | vp->v_specinfov_un.vu_specinfo); | |||
| 880 | return (-1); | |||
| 881 | } | |||
| 882 | ||||
| 883 | vp->v_specinfov_un.vu_specinfo = &specinfo; | |||
| 884 | ||||
| 885 | if (KREAD(kd, (u_long)vp->v_specparent, &parent)(kvm_read(kd, (u_long)vp->v_un.vu_specinfo->si_ci.ci_parent , (void *)(&parent), sizeof(*&parent)) != sizeof(*& parent))) { | |||
| 886 | _kvm_err(kd, kd->program, "can't read parent vnode at %p", | |||
| 887 | vp->v_specparentv_un.vu_specinfo->si_ci.ci_parent); | |||
| 888 | return (-1); | |||
| ||||
| 889 | } | |||
| 890 | ||||
| 891 | if (ufs_filestat(kd, kf, vp)) | |||
| 892 | return (-1); | |||
| 893 | ||||
| 894 | return (0); | |||
| 895 | } | |||
| 896 | ||||
| 897 | static int | |||
| 898 | filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp) | |||
| 899 | { | |||
| 900 | int ret = 0; | |||
| 901 | ||||
| 902 | if (vp->v_type != VNON && vp->v_type != VBAD) { | |||
| 903 | switch (vp->v_tag) { | |||
| 904 | case VT_UFS: | |||
| 905 | case VT_MFS: | |||
| 906 | ret = ufs_filestat(kd, kf, vp); | |||
| 907 | break; | |||
| 908 | case VT_NFS: | |||
| 909 | ret = nfs_filestat(kd, kf, vp); | |||
| 910 | break; | |||
| 911 | case VT_EXT2FS: | |||
| 912 | ret = ext2fs_filestat(kd, kf, vp); | |||
| 913 | break; | |||
| 914 | case VT_ISOFS: | |||
| 915 | ret = _kvm_stat_cd9660(kd, kf, vp); | |||
| 916 | break; | |||
| 917 | case VT_MSDOSFS: | |||
| 918 | ret = msdos_filestat(kd, kf, vp); | |||
| 919 | break; | |||
| 920 | case VT_UDF: | |||
| 921 | ret = _kvm_stat_udf(kd, kf, vp); | |||
| 922 | break; | |||
| 923 | case VT_NTFS: | |||
| 924 | ret = _kvm_stat_ntfs(kd, kf, vp); | |||
| 925 | break; | |||
| 926 | case VT_NON: | |||
| 927 | if (vp->v_flag & VCLONE0x8000) | |||
| 928 | ret = spec_filestat(kd, kf, vp); | |||
| 929 | break; | |||
| 930 | default: | |||
| 931 | ret = -1; | |||
| 932 | break; | |||
| 933 | } | |||
| 934 | } | |||
| 935 | return (ret); | |||
| 936 | } |