1 /* 2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/wait.h> 29 #include <sys/stat.h> 30 #include <sys/resident.h> 31 #include <sys/sysctl.h> 32 33 #include <machine/elf.h> 34 #include <a.out.h> 35 #include <dlfcn.h> 36 #include <err.h> 37 #include <fcntl.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <string.h> 42 #include <errno.h> 43 44 static void 45 usage(void) 46 { 47 fprintf(stderr, "usage: resident [-l] [-f] [-x id] [-d] [-R] program ...\n"); 48 exit(1); 49 } 50 51 static int 52 list_residents(void) 53 { 54 const char *mib = "vm.resident"; 55 struct xresident *buf; 56 size_t res_count, res_total, i; 57 int error; 58 59 /* get the number of resident binaries */ 60 error = sysctlbyname(mib, NULL, &res_count, NULL, 0); 61 if (error != 0) { 62 perror("sysctl: vm.resident"); 63 goto done; 64 } 65 66 if (res_count == 0) { 67 printf("no resident binaries to list\n"); 68 goto done; 69 } 70 71 /* allocate memory for the list of binaries */ 72 res_total = sizeof(*buf) * res_count; 73 if ((buf = malloc(res_total)) != NULL) { 74 /* retrieve entries via sysctl */ 75 error = sysctlbyname(mib, buf, &res_total, NULL, 0); 76 if (error != 0) { 77 perror("sysctl: vm.resident"); 78 goto done; 79 } 80 } else { 81 perror("malloc"); 82 goto done; 83 } 84 85 /* print the list of retrieved resident binary */ 86 printf("%-4s\t%-15s\t%-12s\t%-30s\n","Id", "Size", "Address", "Executable"); 87 for (i = 0; i < res_count; ++i) { 88 printf("%-4d\t%-15jd\t0x%-12x\t%-30s\n", 89 buf[i].res_id, 90 (intmax_t)buf[i].res_stat.st_size, 91 (int)buf[i].res_entry_addr, 92 buf[i].res_file); 93 } 94 95 /* free back the memory */ 96 free(buf); 97 98 done: 99 return error; 100 } 101 102 int 103 main(int argc, char *argv[]) 104 { 105 int rval; 106 int c; 107 int doreg = 1; 108 int force = 0; 109 110 while ((c = getopt(argc, argv, "Rdflx:")) != -1) { 111 switch (c) { 112 case 'f': 113 force = 1; 114 break; 115 case 'l': 116 rval = list_residents(); 117 if (rval < 0) 118 exit(EXIT_FAILURE); 119 else 120 exit(EXIT_SUCCESS); 121 case 'd': 122 doreg = 0; 123 break; 124 case 'x': 125 case 'R': 126 if (c == 'R') 127 c = exec_sys_unregister(-2); 128 else 129 c = exec_sys_unregister(strtol(optarg, NULL, 0)); 130 if (c < 0) 131 printf("unregister: %s\n", strerror(errno)); 132 else 133 printf("unregister: success\n"); 134 exit(0); 135 default: 136 usage(); 137 /*NOTREACHED*/ 138 } 139 } 140 argc -= optind; 141 argv += optind; 142 143 if (argc <= 0) { 144 usage(); 145 /*NOTREACHED*/ 146 } 147 148 /* ld-elf.so magic */ 149 if (doreg) { 150 if (setenv("LD_RESIDENT_REGISTER_NOW", "yes", 1) == -1) 151 err(1, "setenv failed"); 152 } else { 153 if (setenv("LD_RESIDENT_UNREGISTER_NOW", "yes", 1) == -1) 154 err(1, "setenv failed"); 155 } 156 157 rval = 0; 158 for ( ; argc > 0; argc--, argv++) { 159 int fd; 160 union { 161 struct exec aout; 162 Elf_Ehdr elf; 163 } hdr; 164 int n; 165 int status; 166 int file_ok; 167 int is_shlib; 168 169 if (force) 170 goto force_target; 171 172 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 173 warn("%s", *argv); 174 rval |= 1; 175 continue; 176 } 177 if ((n = read(fd, &hdr, sizeof hdr)) == -1) { 178 warn("%s: can't read program header", *argv); 179 close(fd); 180 rval |= 1; 181 continue; 182 } 183 184 file_ok = 1; 185 is_shlib = 0; 186 if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) { 187 /* a.out file */ 188 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 189 #if 1 /* Compatibility */ 190 || hdr.aout.a_entry < __LDPGSZ 191 #endif 192 ) { 193 warnx("%s: not a dynamic executable", *argv); 194 file_ok = 0; 195 } 196 } else if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) { 197 Elf_Ehdr ehdr; 198 Elf_Phdr phdr; 199 int dynamic = 0, i; 200 201 if (lseek(fd, 0, SEEK_SET) == -1 || 202 read(fd, &ehdr, sizeof ehdr) != sizeof ehdr || 203 lseek(fd, ehdr.e_phoff, SEEK_SET) == -1 204 ) { 205 warnx("%s: can't read program header", *argv); 206 file_ok = 0; 207 } else { 208 for (i = 0; i < ehdr.e_phnum; i++) { 209 if (read(fd, &phdr, ehdr.e_phentsize) 210 != sizeof phdr) { 211 warnx("%s: can't read program header", 212 *argv); 213 file_ok = 0; 214 break; 215 } 216 if (phdr.p_type == PT_DYNAMIC) 217 dynamic = 1; 218 } 219 } 220 if (!dynamic) { 221 warnx("%s: not a dynamic executable", *argv); 222 file_ok = 0; 223 } else if (hdr.elf.e_type == ET_DYN) { 224 if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 225 is_shlib = 1; 226 } else { 227 warnx("%s: not a FreeBSD ELF shared " 228 "object", *argv); 229 file_ok = 0; 230 } 231 } 232 } else { 233 warnx("%s: not a dynamic executable", *argv); 234 file_ok = 0; 235 } 236 close(fd); 237 if (!file_ok) { 238 rval |= 1; 239 continue; 240 } 241 242 if (is_shlib) { 243 rval |= 1; 244 warnx("%s: resident not supported on shared libraries.", *argv); 245 continue; 246 } 247 248 force_target: 249 fflush(stdout); 250 251 switch (fork()) { 252 case -1: 253 err(1, "fork"); 254 break; 255 default: 256 if (wait(&status) <= 0) { 257 warn("wait"); 258 rval |= 1; 259 } else if (WIFSIGNALED(status)) { 260 fprintf(stderr, "%s: signal %d\n", 261 *argv, WTERMSIG(status)); 262 rval |= 1; 263 } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 264 switch(WEXITSTATUS(status)) { 265 case ENOENT: 266 fprintf(stderr, "%s: entry not found\n", 267 *argv); 268 break; 269 case EEXIST: 270 fprintf(stderr, "%s: binary already resident\n", 271 *argv); 272 break; 273 default: 274 fprintf(stderr, "%s: exit status %s\n", 275 *argv, strerror(WEXITSTATUS(status))); 276 } 277 rval |= 1; 278 } else { 279 } 280 break; 281 case 0: 282 execl(*argv, *argv, NULL); 283 warn("%s", *argv); 284 _exit(1); 285 } 286 } 287 288 return rval; 289 } 290