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
main(int argc,const char ** argv)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
check_file(const char * filename,mode_t * mode)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
fix_file(const char * filename,mode_t mode)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
usage(const char * name)152 usage(const char *name)
153 {
154 (void) fprintf(stderr, "Usage: %s file...\n", name);
155 exit(EXIT_FAILURE);
156 }
157