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 <dlfcn.h> 35 #include <err.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <string.h> 41 #include <errno.h> 42 43 static void 44 usage(void) 45 { 46 fprintf(stderr, "usage: resident [-l] [-f] [-x id] [-d] [-R] program ...\n"); 47 exit(1); 48 } 49 50 static int 51 list_residents(void) 52 { 53 const char *mib = "vm.resident"; 54 struct xresident *buf; 55 size_t res_count, res_total, i; 56 int error; 57 58 /* get the number of resident binaries */ 59 error = sysctlbyname(mib, NULL, &res_count, NULL, 0); 60 if (error != 0) { 61 perror("sysctl: vm.resident"); 62 goto done; 63 } 64 65 if (res_count == 0) { 66 printf("no resident binaries to list\n"); 67 goto done; 68 } 69 70 /* allocate memory for the list of binaries */ 71 res_total = sizeof(*buf) * res_count; 72 if ((buf = malloc(res_total)) != NULL) { 73 /* retrieve entries via sysctl */ 74 error = sysctlbyname(mib, buf, &res_total, NULL, 0); 75 if (error != 0) { 76 perror("sysctl: vm.resident"); 77 goto done; 78 } 79 } else { 80 perror("malloc"); 81 goto done; 82 } 83 84 /* print the list of retrieved resident binary */ 85 printf("%-4s\t%-15s\t%-12s\t%-30s\n","Id", "Size", "Address", "Executable"); 86 for (i = 0; i < res_count; ++i) { 87 printf("%-4d\t%-15jd\t0x%-12x\t%-30s\n", 88 buf[i].res_id, 89 (intmax_t)buf[i].res_stat.st_size, 90 (int)buf[i].res_entry_addr, 91 buf[i].res_file); 92 } 93 94 /* free back the memory */ 95 free(buf); 96 97 done: 98 return error; 99 } 100 101 int 102 main(int argc, char *argv[]) 103 { 104 int rval; 105 int c; 106 int doreg = 1; 107 int force = 0; 108 109 while ((c = getopt(argc, argv, "Rdflx:")) != -1) { 110 switch (c) { 111 case 'f': 112 force = 1; 113 break; 114 case 'l': 115 rval = list_residents(); 116 if (rval < 0) 117 exit(EXIT_FAILURE); 118 else 119 exit(EXIT_SUCCESS); 120 case 'd': 121 doreg = 0; 122 break; 123 case 'x': 124 case 'R': 125 if (c == 'R') 126 c = exec_sys_unregister(-2); 127 else 128 c = exec_sys_unregister(strtol(optarg, NULL, 0)); 129 if (c < 0) 130 printf("unregister: %s\n", strerror(errno)); 131 else 132 printf("unregister: success\n"); 133 exit(0); 134 default: 135 usage(); 136 /*NOTREACHED*/ 137 } 138 } 139 argc -= optind; 140 argv += optind; 141 142 if (argc <= 0) { 143 usage(); 144 /*NOTREACHED*/ 145 } 146 147 /* ld-elf.so magic */ 148 if (doreg) { 149 if (setenv("LD_RESIDENT_REGISTER_NOW", "yes", 1) == -1) 150 err(1, "setenv failed"); 151 } else { 152 if (setenv("LD_RESIDENT_UNREGISTER_NOW", "yes", 1) == -1) 153 err(1, "setenv failed"); 154 } 155 156 rval = 0; 157 for ( ; argc > 0; argc--, argv++) { 158 int fd; 159 union { 160 Elf_Ehdr elf; 161 } hdr; 162 int n; 163 int status; 164 int file_ok; 165 int is_shlib; 166 167 if (force) 168 goto force_target; 169 170 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 171 warn("%s", *argv); 172 rval |= 1; 173 continue; 174 } 175 if ((n = read(fd, &hdr, sizeof hdr)) == -1) { 176 warn("%s: can't read program header", *argv); 177 close(fd); 178 rval |= 1; 179 continue; 180 } 181 182 file_ok = 1; 183 is_shlib = 0; 184 if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) { 185 Elf_Ehdr ehdr; 186 Elf_Phdr phdr; 187 int dynamic = 0, i; 188 189 if (lseek(fd, 0, SEEK_SET) == -1 || 190 read(fd, &ehdr, sizeof ehdr) != sizeof ehdr || 191 lseek(fd, ehdr.e_phoff, SEEK_SET) == -1 192 ) { 193 warnx("%s: can't read program header", *argv); 194 file_ok = 0; 195 } else { 196 for (i = 0; i < ehdr.e_phnum; i++) { 197 if (read(fd, &phdr, ehdr.e_phentsize) 198 != sizeof phdr) { 199 warnx("%s: can't read program header", 200 *argv); 201 file_ok = 0; 202 break; 203 } 204 if (phdr.p_type == PT_DYNAMIC) 205 dynamic = 1; 206 } 207 } 208 if (!dynamic) { 209 warnx("%s: not a dynamic executable", *argv); 210 file_ok = 0; 211 } else if (hdr.elf.e_type == ET_DYN) { 212 if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 213 is_shlib = 1; 214 } else { 215 warnx("%s: not a FreeBSD ELF shared " 216 "object", *argv); 217 file_ok = 0; 218 } 219 } 220 } else { 221 warnx("%s: not a dynamic executable", *argv); 222 file_ok = 0; 223 } 224 close(fd); 225 if (!file_ok) { 226 rval |= 1; 227 continue; 228 } 229 230 if (is_shlib) { 231 rval |= 1; 232 warnx("%s: resident not supported on shared libraries.", *argv); 233 continue; 234 } 235 236 force_target: 237 fflush(stdout); 238 239 switch (fork()) { 240 case -1: 241 err(1, "fork"); 242 break; 243 default: 244 if (wait(&status) <= 0) { 245 warn("wait"); 246 rval |= 1; 247 } else if (WIFSIGNALED(status)) { 248 fprintf(stderr, "%s: signal %d\n", 249 *argv, WTERMSIG(status)); 250 rval |= 1; 251 } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 252 switch(WEXITSTATUS(status)) { 253 case ENOENT: 254 fprintf(stderr, "%s: entry not found\n", 255 *argv); 256 break; 257 case EEXIST: 258 fprintf(stderr, "%s: binary already resident\n", 259 *argv); 260 break; 261 default: 262 fprintf(stderr, "%s: exit status %s\n", 263 *argv, strerror(WEXITSTATUS(status))); 264 } 265 rval |= 1; 266 } else { 267 } 268 break; 269 case 0: 270 execl(*argv, *argv, NULL); 271 warn("%s", *argv); 272 _exit(1); 273 } 274 } 275 276 return rval; 277 } 278