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