1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2011 Jason King. All rights reserved. 14 */ 15 16 #include <stdlib.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <sys/wait.h> 23 #include <fcntl.h> 24 #include <err.h> 25 #include <spawn.h> 26 27 #define MCS "/usr/bin/mcs" 28 29 #define ELFLEN 4 30 static const char elf_signature[] = "\177ELF"; 31 static posix_spawnattr_t attr; 32 static const char *cmd[] = { MCS, "-d", "-n", ".SUNW_ctf", NULL, NULL }; 33 34 extern char **environ; 35 36 static boolean_t check_file(const char *, mode_t *); 37 static boolean_t fix_file(const char *, mode_t); 38 static void usage(const char *); 39 40 int 41 main(int argc, const char **argv) 42 { 43 const char **p; 44 int rc = 0; 45 mode_t mode; 46 47 if (argc < 2) 48 usage(argv[0]); 49 50 rc = posix_spawnattr_init(&attr); 51 if (rc != 0) { 52 errx(EXIT_FAILURE, "Spawn attribute initialization failed: %s", 53 strerror(rc)); 54 } 55 56 for (p = argv + 1; *p != NULL; p++) { 57 if (!check_file(*p, &mode)) 58 continue; 59 if (!fix_file(*p, mode)) 60 rc = 1; 61 } 62 63 return (rc); 64 } 65 66 static boolean_t 67 check_file(const char *filename, mode_t *mode) 68 { 69 char elfbuf[4]; 70 struct stat sb; 71 int fd; 72 73 fd = open(filename, O_RDONLY); 74 if (fd == -1) { 75 warn("Unable to open %s", filename); 76 return (B_FALSE); 77 } 78 79 if (fstat(fd, &sb) == -1) { 80 warn("stat(2) failed on %s", filename); 81 (void) close(fd); 82 return (B_FALSE); 83 } 84 85 if (!S_ISREG(sb.st_mode)) { 86 warnx("%s is not a regular file", filename); 87 (void) close(fd); 88 return (B_FALSE); 89 } 90 91 if (sb.st_size < ELFLEN) { 92 warnx("%s is not an ELF file", filename); 93 (void) close(fd); 94 return (B_FALSE); 95 } 96 97 if (read(fd, elfbuf, ELFLEN) != ELFLEN) { 98 warn("Error reading %s", filename); 99 (void) close(fd); 100 return (B_FALSE); 101 } 102 103 if (strncmp(elfbuf, elf_signature, ELFLEN) != 0) { 104 warnx("%s is not an ELF file", filename); 105 (void) close(fd); 106 return (B_FALSE); 107 } 108 109 *mode = sb.st_mode & S_IAMB; 110 (void) close(fd); 111 return (B_TRUE); 112 } 113 114 static boolean_t 115 fix_file(const char *filename, mode_t mode) 116 { 117 pid_t pid; 118 int i, rc; 119 int stat = 0; 120 121 if ((mode & S_IWUSR) == 0) { 122 if (chmod(filename, mode | S_IWUSR) == -1) { 123 warn("failed to make %s writable", filename); 124 return (B_FALSE); 125 } 126 } 127 128 cmd[4] = filename; 129 if ((rc = posix_spawn(&pid, MCS, NULL, &attr, 130 (char *const *)cmd, environ)) != 0) { 131 warnx("could not exec mcs: %s", strerror(rc)); 132 return (B_FALSE); 133 } 134 135 waitpid(pid, &stat, 0); 136 if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0) { 137 warnx("Removing CTF information from %s failed", filename); 138 return (B_FALSE); 139 } 140 141 if ((mode & S_IWUSR) == 0) { 142 if (chmod(filename, mode) == -1) { 143 warn("could not reset permissions of %s", filename); 144 return (B_FALSE); 145 } 146 } 147 148 return (B_TRUE); 149 } 150 151 static void 152 usage(const char *name) 153 { 154 (void) fprintf(stderr, "Usage: %s file...\n", name); 155 exit(EXIT_FAILURE); 156 } 157