1 /* $NetBSD: procfs_map.c,v 1.14 2001/11/06 07:20:37 simonb Exp $ */ 2 3 /* 4 * Copyright (c) 1993 Jan-Simon Pendry 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)procfs_status.c 8.3 (Berkeley) 2/17/94 40 * 41 * $FreeBSD: procfs_map.c,v 1.18 1998/12/04 22:54:51 archie Exp $ 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/proc.h> 47 #include <sys/vnode.h> 48 #include <sys/malloc.h> 49 #include <sys/namei.h> 50 #include <miscfs/procfs/procfs.h> 51 52 #include <sys/lock.h> 53 54 #include <uvm/uvm.h> 55 56 #define MEBUFFERSIZE 256 57 58 extern int getcwd_common __P((struct vnode *, struct vnode *, 59 char **, char *, int, int, struct proc *)); 60 61 static int procfs_vnode_to_path(struct vnode *vp, char *path, int len, 62 struct proc *curp, struct proc *p); 63 64 /* 65 * The map entries can *almost* be read with programs like cat. However, 66 * large maps need special programs to read. It is not easy to implement 67 * a program that can sense the required size of the buffer, and then 68 * subsequently do a read with the appropriate size. This operation cannot 69 * be atomic. The best that we can do is to allow the program to do a read 70 * with an arbitrarily large buffer, and return as much as we can. We can 71 * return an error code if the buffer is too small (EFBIG), then the program 72 * can try a bigger buffer. 73 */ 74 int 75 procfs_domap(struct proc *curp, struct proc *p, struct pfsnode *pfs, 76 struct uio *uio, int linuxmode) 77 { 78 int len; 79 int error; 80 struct vm_map *map = &p->p_vmspace->vm_map; 81 struct vm_map_entry *entry; 82 char mebuffer[MEBUFFERSIZE]; 83 char *path; 84 struct vnode *vp; 85 struct vattr va; 86 dev_t dev; 87 long fileid; 88 89 if (uio->uio_rw != UIO_READ) 90 return (EOPNOTSUPP); 91 92 if (uio->uio_offset != 0) 93 return (0); 94 95 error = 0; 96 if (map != &curproc->p_vmspace->vm_map) 97 vm_map_lock_read(map); 98 for (entry = map->header.next; 99 ((uio->uio_resid > 0) && (entry != &map->header)); 100 entry = entry->next) { 101 102 if (UVM_ET_ISSUBMAP(entry)) 103 continue; 104 105 if (linuxmode != 0) { 106 path = (char *)malloc(MAXPATHLEN * 4, M_TEMP, M_WAITOK); 107 if (path == NULL) { 108 error = ENOMEM; 109 break; 110 } 111 *path = 0; 112 113 dev = (dev_t)0; 114 fileid = 0; 115 if (UVM_ET_ISOBJ(entry) && 116 UVM_OBJ_IS_VNODE(entry->object.uvm_obj)) { 117 vp = (struct vnode *)entry->object.uvm_obj; 118 error = VOP_GETATTR(vp, &va, curp->p_ucred, 119 curp); 120 if (error == 0 && vp != pfs->pfs_vnode) { 121 fileid = va.va_fileid; 122 dev = va.va_fsid; 123 error = procfs_vnode_to_path(vp, path, 124 MAXPATHLEN * 4, curp, p); 125 } 126 } 127 snprintf(mebuffer, sizeof(mebuffer), 128 "%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %ld %s\n", 129 (int)sizeof(void *) * 2,(unsigned long)entry->start, 130 (int)sizeof(void *) * 2,(unsigned long)entry->end, 131 (entry->protection & VM_PROT_READ) ? 'r' : '-', 132 (entry->protection & VM_PROT_WRITE) ? 'w' : '-', 133 (entry->protection & VM_PROT_EXECUTE) ? 'x' : '-', 134 (entry->etype & UVM_ET_COPYONWRITE) ? 'p' : 's', 135 (int)sizeof(void *) * 2, 136 (unsigned long)entry->offset, 137 major(dev), minor(dev), fileid, path); 138 free(path, M_TEMP); 139 } else { 140 snprintf(mebuffer, sizeof(mebuffer), 141 "0x%lx 0x%lx %c%c%c %c%c%c %s %s %d %d %d\n", 142 entry->start, entry->end, 143 (entry->protection & VM_PROT_READ) ? 'r' : '-', 144 (entry->protection & VM_PROT_WRITE) ? 'w' : '-', 145 (entry->protection & VM_PROT_EXECUTE) ? 'x' : '-', 146 (entry->max_protection & VM_PROT_READ) ? 'r' : '-', 147 (entry->max_protection & VM_PROT_WRITE) ? 'w' : '-', 148 (entry->max_protection & VM_PROT_EXECUTE) ? 149 'x' : '-', 150 (entry->etype & UVM_ET_COPYONWRITE) ? 151 "COW" : "NCOW", 152 (entry->etype & UVM_ET_NEEDSCOPY) ? "NC" : "NNC", 153 entry->inheritance, entry->wired_count, 154 entry->advice); 155 } 156 157 len = strlen(mebuffer); 158 if (len > uio->uio_resid) { 159 error = EFBIG; 160 break; 161 } 162 error = uiomove(mebuffer, len, uio); 163 if (error) 164 break; 165 } 166 if (map != &curproc->p_vmspace->vm_map) 167 vm_map_unlock_read(map); 168 return error; 169 } 170 171 int 172 procfs_validmap(struct proc *p, struct mount *mp) 173 { 174 return ((p->p_flag & P_SYSTEM) == 0); 175 } 176 177 /* 178 * Try to find a pathname for a vnode. Since there is no mapping 179 * vnode -> parent directory, this needs the NAMECACHE_ENTER_REVERSE 180 * option to work (to make cache_revlookup succeed). 181 */ 182 static int procfs_vnode_to_path(struct vnode *vp, char *path, int len, 183 struct proc *curp, struct proc *p) 184 { 185 int error, lenused, elen; 186 char *bp, *bend; 187 struct vnode *dvp; 188 189 bp = bend = &path[len]; 190 *(--bp) = '\0'; 191 192 error = vget(vp, LK_EXCLUSIVE | LK_RETRY); 193 if (error != 0) 194 return error; 195 error = cache_revlookup(vp, &dvp, &bp, path); 196 vput(vp); 197 if (error != 0) 198 return (error == -1 ? ENOENT : error); 199 200 error = vget(dvp, 0); 201 if (error != 0) 202 return error; 203 *(--bp) = '/'; 204 /* XXX GETCWD_CHECK_ACCESS == 0x0001 */ 205 error = getcwd_common(dvp, NULL, &bp, path, len / 2, 1, curp); 206 207 /* 208 * Strip off emulation path for emulated processes looking at 209 * the maps file of a process of the same emulation. (Won't 210 * work if /emul/xxx is a symlink..) 211 */ 212 if (curp->p_emul == p->p_emul && curp->p_emul->e_path != NULL) { 213 elen = strlen(curp->p_emul->e_path); 214 if (!strncmp(bp, curp->p_emul->e_path, elen)) 215 bp = &bp[elen]; 216 } 217 218 lenused = bend - bp; 219 220 memcpy(path, bp, lenused); 221 path[lenused] = 0; 222 223 return 0; 224 } 225