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