diff options
| author | Richard Lowe <richlowe@richlowe.net> | 2018-12-17 17:54:19 +0000 |
|---|---|---|
| committer | Richard Lowe <richlowe@richlowe.net> | 2019-01-31 01:37:40 +0000 |
| commit | 88e61e85cc7078a2b481258cf9441eeee7ff548d (patch) | |
| tree | 68087541d726c8536f33c0518326145911713bf9 /usr/src/tools/cw | |
| parent | d75f3745ad3c36431063bb316666f4d316eabc8c (diff) | |
| download | illumos-joyent-88e61e85cc7078a2b481258cf9441eeee7ff548d.tar.gz | |
9899 cw(1onbld) should shadow more compilation
Reviewed by: John Levon <john.levon@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src/tools/cw')
| -rw-r--r-- | usr/src/tools/cw/Makefile | 1 | ||||
| -rw-r--r-- | usr/src/tools/cw/cw.1onbld | 9 | ||||
| -rw-r--r-- | usr/src/tools/cw/cw.c | 202 |
3 files changed, 166 insertions, 46 deletions
diff --git a/usr/src/tools/cw/Makefile b/usr/src/tools/cw/Makefile index e5100189d2..00099cb2e5 100644 --- a/usr/src/tools/cw/Makefile +++ b/usr/src/tools/cw/Makefile @@ -49,6 +49,7 @@ $(__GNUC)LDLIBS += -lc $(__GNUC)LDFLAGS= $(MAPFILE.NES:%=-Wl,-M%) $(ROOTONBLDMAN1ONBLDFILES) := FILEMODE= 644 +CSTD= $(CSTD_GNU99) # Assume we don't have the install.bin available yet INS.file= $(RM) $@; $(CP) $< $(@D); $(CHMOD) $(FILEMODE) $@ diff --git a/usr/src/tools/cw/cw.1onbld b/usr/src/tools/cw/cw.1onbld index da3f224cd2..62800bb727 100644 --- a/usr/src/tools/cw/cw.1onbld +++ b/usr/src/tools/cw/cw.1onbld @@ -137,11 +137,10 @@ will invoke each shadow compiler, with the outputs modified (as well as any translation for compiler style) as follows: .Bl -enum .It -If neither of -.Fl c , -.Fl S -appears in the argument list (that is, linking is attempted or only the -pre-processor is invoked), the shadow compilers will not be invoked. +If +.Nm cw +is invoked to link-edit without compilation (the input files are all objects), +the shadow compiler is not invoked. .It If the .Fl o Ar filename diff --git a/usr/src/tools/cw/cw.c b/usr/src/tools/cw/cw.c index 7806b50626..eaa58a1c3e 100644 --- a/usr/src/tools/cw/cw.c +++ b/usr/src/tools/cw/cw.c @@ -262,6 +262,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <dirent.h> #include <sys/param.h> #include <sys/stat.h> @@ -311,7 +312,7 @@ typedef struct cw_ictx { int i_oldargc; char **i_oldargv; pid_t i_pid; - char i_discard[MAXPATHLEN]; + char *i_tmpdir; char *i_stderr; } cw_ictx_t; @@ -556,6 +557,65 @@ xlate(struct aelist *h, const char *xarg, const char **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 boolean_t +is_source_file(const char *path) +{ + char *ext = strrchr(path, '.'); + + if ((ext == NULL) || ((ext + 1) == '\0')) + return (B_FALSE); + + ext += 1; + + if ((strcasecmp(ext, "c") == 0) || + (strcmp(ext, "cc") == 0) || + (strcmp(ext, "i") == 0) || + (strcasecmp(ext, "s") == 0) || + (strcmp(ext, "cpp") == 0)) { + return (B_TRUE); + } + + return (B_FALSE); +} + + static void do_gcc(cw_ictx_t *ctx) { @@ -565,7 +625,7 @@ do_gcc(cw_ictx_t *ctx) cw_op_t op = CW_O_LINK; char *model = NULL; char *nameflag; - int mflag = 0; + int mflag = 0; if (ctx->i_flags & CW_F_PROG) { newae(ctx->i_ae, "--version"); @@ -621,10 +681,7 @@ do_gcc(cw_ictx_t *ctx) strcmp(arg + arglen - 3, ".il") == 0) continue; - if (!in_output && arglen > 2 && - arg[arglen - 2] == '.' && - (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' || - arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i')) + if (!in_output && is_source_file(arg)) c_files++; /* @@ -633,10 +690,11 @@ do_gcc(cw_ictx_t *ctx) * 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 + 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; } @@ -752,7 +810,7 @@ do_gcc(cw_ictx_t *ctx) 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); + newae(ctx->i_ae, discard_file_name(ctx, arg)); } else { newae(ctx->i_ae, arg); } @@ -1190,8 +1248,16 @@ do_gcc(cw_ictx_t *ctx) free(nameflag); - if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) && - op != CW_O_PREPROCESS) { + /* + * 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"); } @@ -1259,9 +1325,12 @@ do_gcc(cw_ictx_t *ctx) exit(2); } - if ((op == CW_O_LINK || op == CW_O_PREPROCESS) && - (ctx->i_flags & CW_F_SHADOW)) - exit(0); + 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); @@ -1269,7 +1338,7 @@ do_gcc(cw_ictx_t *ctx) 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); + newae(ctx->i_ae, discard_file_name(ctx, NULL)); } } @@ -1302,7 +1371,7 @@ do_smatch(cw_ictx_t *ctx) static void do_cc(cw_ictx_t *ctx) { - int in_output = 0, seen_o = 0; + int in_output = 0, seen_o = 0, c_files = 0; cw_op_t op = CW_O_LINK; char *nameflag; @@ -1323,11 +1392,14 @@ do_cc(cw_ictx_t *ctx) } if (*arg != '-') { + if (!in_output && is_source_file(arg)) + 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, ctx->i_discard); + newae(ctx->i_ae, discard_file_name(ctx, arg)); } continue; } @@ -1351,7 +1423,7 @@ do_cc(cw_ictx_t *ctx) 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); + newae(ctx->i_ae, discard_file_name(ctx, arg)); } else { newae(ctx->i_ae, arg); } @@ -1374,13 +1446,22 @@ do_cc(cw_ictx_t *ctx) free(nameflag); - if ((op == CW_O_LINK || op == CW_O_PREPROCESS) && - (ctx->i_flags & CW_F_SHADOW)) - exit(0); + /* 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, ctx->i_discard); + newae(ctx->i_ae, discard_file_name(ctx, NULL)); } } @@ -1491,8 +1572,6 @@ reap(cw_ictx_t *ctx) } } 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); @@ -1522,21 +1601,7 @@ reap(cw_ictx_t *ctx) 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) { + if ((ctx->i_stderr = tempnam(ctx->i_tmpdir, "cw")) == NULL) { nomem(); return (-1); } @@ -1607,6 +1672,49 @@ parse_compiler(const char *spec, cw_compiler_t *compiler) 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 (strcmp(dp->d_name, ".") == 0 || + strcmp(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) { @@ -1621,6 +1729,7 @@ main(int argc, char **argv) boolean_t Cflg = B_FALSE; boolean_t cflg = B_FALSE; boolean_t nflg = B_FALSE; + char *tmpdir; cw_ictx_t *main_ctx; @@ -1708,6 +1817,16 @@ main(int argc, char **argv) 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++) { @@ -1717,7 +1836,7 @@ main(int argc, char **argv) if ((shadow_ctx = newictx()) == NULL) nomem(); - memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t)); + (void) memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t)); shadow_ctx->i_flags |= CW_F_SHADOW; shadow_ctx->i_compiler = &shadows[i]; @@ -1739,5 +1858,6 @@ main(int argc, char **argv) } } + cleanup(main_ctx); return (ret); } |
