xref: /illumos-gate/usr/src/tools/ctf/ctfstrip/ctfstrip.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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