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