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
  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
  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
 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
 153 usage(const char *name)
 154 {
 155         (void) fprintf(stderr, "Usage: %s file...\n", name);
 156         exit(EXIT_FAILURE);
 157 }