Print this page
9899 cw(1onbld) should shadow more compilation
*** 260,269 ****
--- 260,270 ----
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+ #include <dirent.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
*** 309,319 ****
struct aelist *i_ae;
uint32_t i_flags;
int i_oldargc;
char **i_oldargv;
pid_t i_pid;
! char i_discard[MAXPATHLEN];
char *i_stderr;
} cw_ictx_t;
/*
* Status values to indicate which Studio compiler and associated
--- 310,320 ----
struct aelist *i_ae;
uint32_t i_flags;
int i_oldargc;
char **i_oldargv;
pid_t i_pid;
! char *i_tmpdir;
char *i_stderr;
} cw_ictx_t;
/*
* Status values to indicate which Studio compiler and associated
*** 554,563 ****
--- 555,601 ----
newae(h, *table);
table++;
}
}
+ /*
+ * The compiler wants the output file to end in appropriate extension. If
+ * we're generating a name from whole cloth (path == NULL), we assume that
+ * extension to be .o, otherwise we match the extension of the caller.
+ */
+ static char *
+ discard_file_name(cw_ictx_t *ctx, const char *path)
+ {
+ char *ret, *ext;
+ char tmpl[] = "cwXXXXXX";
+
+ if (path == NULL) {
+ ext = ".o";
+ } else {
+ ext = strrchr(path, '.');
+ }
+
+ /*
+ * We need absolute control over where the temporary file goes, since
+ * we rely on it for cleanup so tempnam(3C) and tmpnam(3C) are
+ * inappropriate (they use TMPDIR, preferentially).
+ *
+ * mkstemp(3C) doesn't actually help us, since the temporary file
+ * isn't used by us, only its name.
+ */
+ if (mktemp(tmpl) == NULL)
+ nomem();
+
+ (void) asprintf(&ret, "%s/%s%s", ctx->i_tmpdir, tmpl,
+ (ext != NULL) ? ext : "");
+
+ if (ret == NULL)
+ nomem();
+
+ return (ret);
+ }
+
static void
do_gcc(cw_ictx_t *ctx)
{
int c;
int nolibc = 0;
*** 631,644 ****
* Otherwise, filenames and partial arguments
* are passed through for gcc to chew on. However,
* output is always discarded for the secondary
* compiler.
*/
! if ((ctx->i_flags & CW_F_SHADOW) && in_output)
! newae(ctx->i_ae, ctx->i_discard);
! else
newae(ctx->i_ae, arg);
in_output = 0;
continue;
}
if (ctx->i_flags & CW_F_CXX) {
--- 669,683 ----
* Otherwise, filenames and partial arguments
* are passed through for gcc to chew on. However,
* output is always discarded for the secondary
* compiler.
*/
! if ((ctx->i_flags & CW_F_SHADOW) && in_output) {
! newae(ctx->i_ae, discard_file_name(ctx, arg));
! } else {
newae(ctx->i_ae, arg);
+ }
in_output = 0;
continue;
}
if (ctx->i_flags & CW_F_CXX) {
*** 750,760 ****
if (arglen == 1) {
in_output = 1;
newae(ctx->i_ae, arg);
} else if (ctx->i_flags & CW_F_SHADOW) {
newae(ctx->i_ae, "-o");
! newae(ctx->i_ae, ctx->i_discard);
} else {
newae(ctx->i_ae, arg);
}
break;
case 'D':
--- 789,799 ----
if (arglen == 1) {
in_output = 1;
newae(ctx->i_ae, arg);
} else if (ctx->i_flags & CW_F_SHADOW) {
newae(ctx->i_ae, "-o");
! newae(ctx->i_ae, discard_file_name(ctx, arg));
} else {
newae(ctx->i_ae, arg);
}
break;
case 'D':
*** 1188,1199 ****
}
}
free(nameflag);
! if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) &&
! op != CW_O_PREPROCESS) {
errx(2, "multiple source files are "
"allowed only with -E or -P");
}
/*
--- 1227,1246 ----
}
}
free(nameflag);
! /*
! * When compiling multiple source files in a single invocation some
! * compilers output objects into the current directory with
! * predictable and conventional names.
! *
! * We prevent any attempt to compile multiple files at once so that
! * any such objects created by a shadow can't escape into a later
! * link-edit.
! */
! if (c_files > 1 && op != CW_O_PREPROCESS) {
errx(2, "multiple source files are "
"allowed only with -E or -P");
}
/*
*** 1257,1277 ****
(void) fprintf(stderr,
"Incompatible -xarch= and/or -m32/-m64 options used.\n");
exit(2);
}
! if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
! (ctx->i_flags & CW_F_SHADOW))
exit(0);
if (model != NULL)
newae(ctx->i_ae, model);
if (!nolibc)
newae(ctx->i_ae, "-lc");
if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
newae(ctx->i_ae, "-o");
! newae(ctx->i_ae, ctx->i_discard);
}
}
static void
do_smatch(cw_ictx_t *ctx)
--- 1304,1327 ----
(void) fprintf(stderr,
"Incompatible -xarch= and/or -m32/-m64 options used.\n");
exit(2);
}
! if (ctx->i_flags & CW_F_SHADOW) {
! if (op == CW_O_PREPROCESS)
! exit(0);
! else if (op == CW_O_LINK && c_files == 0)
exit(0);
+ }
if (model != NULL)
newae(ctx->i_ae, model);
if (!nolibc)
newae(ctx->i_ae, "-lc");
if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
newae(ctx->i_ae, "-o");
! newae(ctx->i_ae, discard_file_name(ctx, NULL));
}
}
static void
do_smatch(cw_ictx_t *ctx)
*** 1300,1310 ****
}
static void
do_cc(cw_ictx_t *ctx)
{
! int in_output = 0, seen_o = 0;
cw_op_t op = CW_O_LINK;
char *nameflag;
if (ctx->i_flags & CW_F_PROG) {
newae(ctx->i_ae, "-V");
--- 1350,1360 ----
}
static void
do_cc(cw_ictx_t *ctx)
{
! int in_output = 0, seen_o = 0, c_files = 0;
cw_op_t op = CW_O_LINK;
char *nameflag;
if (ctx->i_flags & CW_F_PROG) {
newae(ctx->i_ae, "-V");
*** 1314,1335 ****
if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
nomem();
while (--ctx->i_oldargc > 0) {
char *arg = *++ctx->i_oldargv;
if (strncmp(arg, "-_CC=", 5) == 0) {
newae(ctx->i_ae, strchr(arg, '=') + 1);
continue;
}
if (*arg != '-') {
if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
newae(ctx->i_ae, arg);
} else {
in_output = 0;
! newae(ctx->i_ae, ctx->i_discard);
}
continue;
}
switch (*(arg + 1)) {
case '_':
--- 1364,1392 ----
if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
nomem();
while (--ctx->i_oldargc > 0) {
char *arg = *++ctx->i_oldargv;
+ size_t arglen = strlen(arg);
if (strncmp(arg, "-_CC=", 5) == 0) {
newae(ctx->i_ae, strchr(arg, '=') + 1);
continue;
}
if (*arg != '-') {
+ if (!in_output && arglen > 2 &&
+ arg[arglen - 2] == '.' &&
+ (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
+ arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
+ c_files++;
+
if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
newae(ctx->i_ae, arg);
} else {
in_output = 0;
! newae(ctx->i_ae, discard_file_name(ctx, arg));
}
continue;
}
switch (*(arg + 1)) {
case '_':
*** 1349,1359 ****
if (strlen(arg) == 2) {
in_output = 1;
newae(ctx->i_ae, arg);
} else if (ctx->i_flags & CW_F_SHADOW) {
newae(ctx->i_ae, "-o");
! newae(ctx->i_ae, ctx->i_discard);
} else {
newae(ctx->i_ae, arg);
}
break;
case 'c':
--- 1406,1416 ----
if (strlen(arg) == 2) {
in_output = 1;
newae(ctx->i_ae, arg);
} else if (ctx->i_flags & CW_F_SHADOW) {
newae(ctx->i_ae, "-o");
! newae(ctx->i_ae, discard_file_name(ctx, arg));
} else {
newae(ctx->i_ae, arg);
}
break;
case 'c':
*** 1372,1388 ****
}
}
free(nameflag);
! if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
! (ctx->i_flags & CW_F_SHADOW))
exit(0);
if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
newae(ctx->i_ae, "-o");
! newae(ctx->i_ae, ctx->i_discard);
}
}
static void
prepctx(cw_ictx_t *ctx)
--- 1429,1454 ----
}
}
free(nameflag);
! /* See the comment on this same code in do_gcc() */
! if (c_files > 1 && op != CW_O_PREPROCESS) {
! errx(2, "multiple source files are "
! "allowed only with -E or -P");
! }
!
! if (ctx->i_flags & CW_F_SHADOW) {
! if (op == CW_O_PREPROCESS)
exit(0);
+ else if (op == CW_O_LINK && c_files == 0)
+ exit(0);
+ }
if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
newae(ctx->i_ae, "-o");
! newae(ctx->i_ae, discard_file_name(ctx, NULL));
}
}
static void
prepctx(cw_ictx_t *ctx)
*** 1489,1500 ****
break;
}
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
- (void) unlink(ctx->i_discard);
-
if (stat(ctx->i_stderr, &s) < 0) {
warn("stat failed on child cleanup");
return (-1);
}
if (s.st_size != 0) {
--- 1555,1564 ----
*** 1520,1544 ****
}
static int
exec_ctx(cw_ictx_t *ctx, int block)
{
! char *file;
!
! /*
! * To avoid offending cc's sensibilities, the name of its output
! * file must end in '.o'.
! */
! if ((file = tempnam(NULL, ".cw")) == NULL) {
! nomem();
! return (-1);
! }
! (void) strlcpy(ctx->i_discard, file, MAXPATHLEN);
! (void) strlcat(ctx->i_discard, ".o", MAXPATHLEN);
! free(file);
!
! if ((ctx->i_stderr = tempnam(NULL, ".cw")) == NULL) {
nomem();
return (-1);
}
if ((ctx->i_pid = fork()) == 0) {
--- 1584,1594 ----
}
static int
exec_ctx(cw_ictx_t *ctx, int block)
{
! if ((ctx->i_stderr = tempnam(ctx->i_tmpdir, "cw")) == NULL) {
nomem();
return (-1);
}
if ((ctx->i_pid = fork()) == 0) {
*** 1605,1614 ****
--- 1655,1706 ----
if (tspec != NULL)
errx(1, "Excess tokens in compiler: %s", spec);
}
+ static void
+ cleanup(cw_ictx_t *ctx)
+ {
+ DIR *dirp;
+ struct dirent *dp;
+ char buf[MAXPATHLEN];
+
+ if ((dirp = opendir(ctx->i_tmpdir)) == NULL) {
+ if (errno != ENOENT) {
+ err(1, "couldn't open temp directory: %s",
+ ctx->i_tmpdir);
+ } else {
+ return;
+ }
+ }
+
+ errno = 0;
+ while ((dp = readdir(dirp)) != NULL) {
+ (void) snprintf(buf, MAXPATHLEN, "%s/%s", ctx->i_tmpdir,
+ dp->d_name);
+
+ if (strncmp(dp->d_name, ".", strlen(dp->d_name)) == 0 ||
+ strncmp(dp->d_name, "..", strlen(dp->d_name)) == 0)
+ continue;
+
+ if (unlink(buf) == -1)
+ err(1, "failed to unlink temp file: %s", dp->d_name);
+ errno = 0;
+ }
+
+ if (errno != 0) {
+ err(1, "failed to read temporary directory: %s",
+ ctx->i_tmpdir);
+ }
+
+ (void) closedir(dirp);
+ if (rmdir(ctx->i_tmpdir) != 0) {
+ err(1, "failed to unlink temporary directory: %s",
+ ctx->i_tmpdir);
+ }
+ }
+
int
main(int argc, char **argv)
{
int ch;
cw_compiler_t primary = { NULL, NULL, 0 };
*** 1619,1628 ****
--- 1711,1721 ----
boolean_t do_exec = B_FALSE;
boolean_t vflg = B_FALSE;
boolean_t Cflg = B_FALSE;
boolean_t cflg = B_FALSE;
boolean_t nflg = B_FALSE;
+ char *tmpdir;
cw_ictx_t *main_ctx;
static struct option longopts[] = {
{ "compiler", no_argument, NULL, 'c' },
*** 1706,1725 ****
main_ctx->i_flags &= ~CW_F_ECHO;
main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
do_serial = 1;
}
ret |= exec_ctx(main_ctx, do_serial);
for (int i = 0; i < nshadows; i++) {
int r;
cw_ictx_t *shadow_ctx;
if ((shadow_ctx = newictx()) == NULL)
nomem();
! memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
shadow_ctx->i_flags |= CW_F_SHADOW;
shadow_ctx->i_compiler = &shadows[i];
r = exec_ctx(shadow_ctx, do_serial);
--- 1799,1828 ----
main_ctx->i_flags &= ~CW_F_ECHO;
main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
do_serial = 1;
}
+ tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = "/tmp";
+
+ if (asprintf(&main_ctx->i_tmpdir, "%s/cw.XXXXXX", tmpdir) == -1)
+ nomem();
+
+ if ((main_ctx->i_tmpdir = mkdtemp(main_ctx->i_tmpdir)) == NULL)
+ errx(1, "failed to create temporary directory");
+
ret |= exec_ctx(main_ctx, do_serial);
for (int i = 0; i < nshadows; i++) {
int r;
cw_ictx_t *shadow_ctx;
if ((shadow_ctx = newictx()) == NULL)
nomem();
! (void) memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
shadow_ctx->i_flags |= CW_F_SHADOW;
shadow_ctx->i_compiler = &shadows[i];
r = exec_ctx(shadow_ctx, do_serial);
*** 1737,1743 ****
--- 1840,1847 ----
next = next->i_next;
ret |= reap(toreap);
}
}
+ cleanup(main_ctx);
return (ret);
}