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