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.6 2004/06/04 17:30:26 hmp 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 setenv("LD_RESIDENT_REGISTER_NOW", "yes", 1); 155 else 156 setenv("LD_RESIDENT_UNREGISTER_NOW", "yes", 1); 157 158 rval = 0; 159 for ( ; argc > 0; argc--, argv++) { 160 int fd; 161 union { 162 struct exec aout; 163 Elf_Ehdr elf; 164 } hdr; 165 int n; 166 int status; 167 int file_ok; 168 int is_shlib; 169 170 if (force) 171 goto force_target; 172 173 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 174 warn("%s", *argv); 175 rval |= 1; 176 continue; 177 } 178 if ((n = read(fd, &hdr, sizeof hdr)) == -1) { 179 warn("%s: can't read program header", *argv); 180 (void)close(fd); 181 rval |= 1; 182 continue; 183 } 184 185 file_ok = 1; 186 is_shlib = 0; 187 if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) { 188 /* a.out file */ 189 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 190 #if 1 /* Compatibility */ 191 || hdr.aout.a_entry < __LDPGSZ 192 #endif 193 ) { 194 warnx("%s: not a dynamic executable", *argv); 195 file_ok = 0; 196 } 197 } else if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) { 198 Elf_Ehdr ehdr; 199 Elf_Phdr phdr; 200 int dynamic = 0, i; 201 202 if (lseek(fd, 0, SEEK_SET) == -1 || 203 read(fd, &ehdr, sizeof ehdr) != sizeof ehdr || 204 lseek(fd, ehdr.e_phoff, SEEK_SET) == -1 205 ) { 206 warnx("%s: can't read program header", *argv); 207 file_ok = 0; 208 } else { 209 for (i = 0; i < ehdr.e_phnum; i++) { 210 if (read(fd, &phdr, ehdr.e_phentsize) 211 != sizeof phdr) { 212 warnx("%s: can't read program header", 213 *argv); 214 file_ok = 0; 215 break; 216 } 217 if (phdr.p_type == PT_DYNAMIC) 218 dynamic = 1; 219 } 220 } 221 if (!dynamic) { 222 warnx("%s: not a dynamic executable", *argv); 223 file_ok = 0; 224 } else if (hdr.elf.e_type == ET_DYN) { 225 if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 226 is_shlib = 1; 227 } else { 228 warnx("%s: not a FreeBSD ELF shared " 229 "object", *argv); 230 file_ok = 0; 231 } 232 } 233 } else { 234 warnx("%s: not a dynamic executable", *argv); 235 file_ok = 0; 236 } 237 (void)close(fd); 238 if (!file_ok) { 239 rval |= 1; 240 continue; 241 } 242 243 if (is_shlib) { 244 rval |= 1; 245 warnx("%s: resident not supported on shared libraries.", *argv); 246 continue; 247 } 248 249 force_target: 250 fflush(stdout); 251 252 switch (fork()) { 253 case -1: 254 err(1, "fork"); 255 break; 256 default: 257 if (wait(&status) <= 0) { 258 warn("wait"); 259 rval |= 1; 260 } else if (WIFSIGNALED(status)) { 261 fprintf(stderr, "%s: signal %d\n", 262 *argv, WTERMSIG(status)); 263 rval |= 1; 264 } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 265 switch(WEXITSTATUS(status)) { 266 case ENOENT: 267 fprintf(stderr, "%s: entry not found\n", 268 *argv); 269 break; 270 case EEXIST: 271 fprintf(stderr, "%s: binary already resident\n", 272 *argv); 273 break; 274 default: 275 fprintf(stderr, "%s: exit status %s\n", 276 *argv, strerror(WEXITSTATUS(status))); 277 } 278 rval |= 1; 279 } else { 280 } 281 break; 282 case 0: 283 execl(*argv, *argv, (char *)NULL); 284 warn("%s", *argv); 285 _exit(1); 286 } 287 } 288 289 return rval; 290 } 291