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