Print this page
Cleanup temp files without rm
Cleanup cw tempfiles properly
Revert "Revert most of "9899 cw(1onbld) should shadow more compilation""
This reverts commit 67deef8cbc83060db238a0f4ee252d1ba74641ef.


 243  * -xtransition                 -Wtransition
 244  * -xunroll=n                   error
 245  * -W0,-xdbggen=no%usedonly     -fno-eliminate-unused-debug-symbols
 246  *                              -fno-eliminate-unused-debug-types
 247  * -Y<c>,<dir>                      error
 248  * -YA,<dir>                      error
 249  * -YI,<dir>                      -nostdinc -I<dir>
 250  * -YP,<dir>                      error
 251  * -YS,<dir>                      error
 252  */
 253 
 254 #include <ctype.h>
 255 #include <err.h>
 256 #include <errno.h>
 257 #include <fcntl.h>
 258 #include <getopt.h>
 259 #include <stdio.h>
 260 #include <stdlib.h>
 261 #include <string.h>
 262 #include <unistd.h>

 263 
 264 #include <sys/param.h>
 265 #include <sys/stat.h>
 266 #include <sys/types.h>
 267 #include <sys/utsname.h>
 268 #include <sys/wait.h>
 269 
 270 #define CW_F_CXX        0x01
 271 #define CW_F_SHADOW     0x02
 272 #define CW_F_EXEC       0x04
 273 #define CW_F_ECHO       0x08
 274 #define CW_F_XLATE      0x10
 275 #define CW_F_PROG       0x20
 276 
 277 typedef enum cw_op {
 278         CW_O_NONE = 0,
 279         CW_O_PREPROCESS,
 280         CW_O_COMPILE,
 281         CW_O_LINK
 282 } cw_op_t;


 291 
 292 typedef enum {
 293         GNU,
 294         SUN
 295 } compiler_style_t;
 296 
 297 typedef struct {
 298         char *c_name;
 299         char *c_path;
 300         compiler_style_t c_style;
 301 } cw_compiler_t;
 302 
 303 typedef struct cw_ictx {
 304         struct cw_ictx  *i_next;
 305         cw_compiler_t   *i_compiler;
 306         struct aelist   *i_ae;
 307         uint32_t        i_flags;
 308         int             i_oldargc;
 309         char            **i_oldargv;
 310         pid_t           i_pid;
 311         char            i_discard[MAXPATHLEN];
 312         char            *i_stderr;
 313 } cw_ictx_t;
 314 
 315 /*
 316  * Status values to indicate which Studio compiler and associated
 317  * flags are being used.
 318  */
 319 #define M32             0x01    /* -m32 - only on Studio 12 */
 320 #define M64             0x02    /* -m64 - only on Studio 12 */
 321 #define SS11            0x100   /* Studio 11 */
 322 #define SS12            0x200   /* Studio 12 */
 323 
 324 #define TRANS_ENTRY     5
 325 /*
 326  * Translation table definition for the -xarch= flag. The "x_arg"
 327  * value is translated into the appropriate gcc flags according
 328  * to the values in x_trans[n]. The x_flags indicates what compiler
 329  * is being used and what flags have been set via the use of
 330  * "x_arg".
 331  */


 536 static void
 537 xlate(struct aelist *h, const char *xarg, const char **table)
 538 {
 539         while (*table != NULL && strcmp(xarg, *table) != 0) {
 540                 while (*table != NULL)
 541                         table++;
 542                 table++;
 543         }
 544 
 545         if (*table == NULL)
 546                 error(xarg);
 547 
 548         table++;
 549 
 550         while (*table != NULL) {
 551                 newae(h, *table);
 552                 table++;
 553         }
 554 }
 555 





































 556 static void
 557 do_gcc(cw_ictx_t *ctx)
 558 {
 559         int c;
 560         int nolibc = 0;
 561         int in_output = 0, seen_o = 0, c_files = 0;
 562         cw_op_t op = CW_O_LINK;
 563         char *model = NULL;
 564         char *nameflag;
 565         int     mflag = 0;
 566 
 567         if (ctx->i_flags & CW_F_PROG) {
 568                 newae(ctx->i_ae, "--version");
 569                 return;
 570         }
 571 
 572         newae(ctx->i_ae, "-fident");
 573         newae(ctx->i_ae, "-finline");
 574         newae(ctx->i_ae, "-fno-inline-functions");
 575         newae(ctx->i_ae, "-fno-builtin");


 613                 } else {
 614                         /*
 615                          * Discard inline files that gcc doesn't grok
 616                          */
 617                         if (!in_output && arglen > 3 &&
 618                             strcmp(arg + arglen - 3, ".il") == 0)
 619                                 continue;
 620 
 621                         if (!in_output && arglen > 2 &&
 622                             arg[arglen - 2] == '.' &&
 623                             (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
 624                             arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
 625                                 c_files++;
 626 
 627                         /*
 628                          * Otherwise, filenames and partial arguments
 629                          * are passed through for gcc to chew on.  However,
 630                          * output is always discarded for the secondary
 631                          * compiler.
 632                          */
 633                         if ((ctx->i_flags & CW_F_SHADOW) && in_output)
 634                                 newae(ctx->i_ae, ctx->i_discard);
 635                         else
 636                                 newae(ctx->i_ae, arg);

 637                         in_output = 0;
 638                         continue;
 639                 }
 640 
 641                 if (ctx->i_flags & CW_F_CXX) {
 642                         if (strncmp(arg, "-_g++=", 6) == 0) {
 643                                 newae(ctx->i_ae, strchr(arg, '=') + 1);
 644                                 continue;
 645                         }
 646                         if (strncmp(arg, "-compat=", 8) == 0) {
 647                                 /* discard -compat=4 and -compat=5 */
 648                                 continue;
 649                         }
 650                         if (strcmp(arg, "-Qoption") == 0) {
 651                                 /* discard -Qoption and its two arguments */
 652                                 if (ctx->i_oldargc < 3)
 653                                         error(arg);
 654                                 ctx->i_oldargc -= 2;
 655                                 ctx->i_oldargv += 2;
 656                                 continue;


 732                         break;
 733                 case 'A':
 734                 case 'h':
 735                 case 'I':
 736                 case 'i':
 737                 case 'L':
 738                 case 'l':
 739                 case 'R':
 740                 case 'U':
 741                 case 'u':
 742                 case 'w':
 743                         newae(ctx->i_ae, arg);
 744                         break;
 745                 case 'o':
 746                         seen_o = 1;
 747                         if (arglen == 1) {
 748                                 in_output = 1;
 749                                 newae(ctx->i_ae, arg);
 750                         } else if (ctx->i_flags & CW_F_SHADOW) {
 751                                 newae(ctx->i_ae, "-o");
 752                                 newae(ctx->i_ae, ctx->i_discard);
 753                         } else {
 754                                 newae(ctx->i_ae, arg);
 755                         }
 756                         break;
 757                 case 'D':
 758                         newae(ctx->i_ae, arg);
 759                         /*
 760                          * XXX  Clearly a hack ... do we need _KADB too?
 761                          */
 762                         if (strcmp(arg, "-D_KERNEL") == 0 ||
 763                             strcmp(arg, "-D_BOOT") == 0)
 764                                 newae(ctx->i_ae, "-ffreestanding");
 765                         break;
 766                 case 'd':
 767                         if (arglen == 2) {
 768                                 if (strcmp(arg, "-dy") == 0) {
 769                                         newae(ctx->i_ae, "-Wl,-dy");
 770                                         break;
 771                                 }
 772                                 if (strcmp(arg, "-dn") == 0) {


1170                                 s[1] = 'I';
1171                                 newae(ctx->i_ae, "-nostdinc");
1172                                 newae(ctx->i_ae, s);
1173                                 free(s);
1174                                 break;
1175                         }
1176                         error(arg);
1177                         break;
1178                 case 'Q':
1179                         /*
1180                          * We could map -Qy into -Wl,-Qy etc.
1181                          */
1182                 default:
1183                         error(arg);
1184                         break;
1185                 }
1186         }
1187 
1188         free(nameflag);
1189 
1190         if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) &&
1191             op != CW_O_PREPROCESS) {








1192                 errx(2, "multiple source files are "
1193                     "allowed only with -E or -P");
1194         }
1195 
1196         /*
1197          * Make sure that we do not have any unintended interactions between
1198          * the xarch options passed in and the version of the Studio compiler
1199          * used.
1200          */
1201         if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
1202                 errx(2,
1203                     "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
1204         }
1205 
1206         switch (mflag) {
1207         case 0:
1208                 /* FALLTHROUGH */
1209         case M32:
1210 #if defined(__sparc)
1211                 /*


1239                 break;
1240         case (SS12|M32):
1241 #if defined(__sparc)
1242                 /*
1243                  * Need to add in further 32 bit options because with SS12
1244                  * the xarch=sparcvis option can be applied to 32 or 64
1245                  * bit, and so the translatation table (xtbl) cannot handle
1246                  * that.
1247                  */
1248                 newae(ctx->i_ae, "-mv8plus");
1249 #endif
1250                 break;
1251         case (SS12|M64):
1252                 break;
1253         default:
1254                 (void) fprintf(stderr,
1255                     "Incompatible -xarch= and/or -m32/-m64 options used.\n");
1256                 exit(2);
1257         }
1258 
1259         if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
1260             (ctx->i_flags & CW_F_SHADOW))


1261                 exit(0);

1262 
1263         if (model != NULL)
1264                 newae(ctx->i_ae, model);
1265         if (!nolibc)
1266                 newae(ctx->i_ae, "-lc");
1267         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1268                 newae(ctx->i_ae, "-o");
1269                 newae(ctx->i_ae, ctx->i_discard);
1270         }
1271 }
1272 
1273 static void
1274 do_cc(cw_ictx_t *ctx)
1275 {
1276         int in_output = 0, seen_o = 0;
1277         cw_op_t op = CW_O_LINK;
1278         char *nameflag;
1279 
1280         if (ctx->i_flags & CW_F_PROG) {
1281                 newae(ctx->i_ae, "-V");
1282                 return;
1283         }
1284 
1285         if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
1286                 nomem();
1287 
1288         while (--ctx->i_oldargc > 0) {
1289                 char *arg = *++ctx->i_oldargv;

1290 
1291                 if (strncmp(arg, "-_CC=", 5) == 0) {
1292                         newae(ctx->i_ae, strchr(arg, '=') + 1);
1293                         continue;
1294                 }
1295 
1296                 if (*arg != '-') {






1297                         if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
1298                                 newae(ctx->i_ae, arg);
1299                         } else {
1300                                 in_output = 0;
1301                                 newae(ctx->i_ae, ctx->i_discard);
1302                         }
1303                         continue;
1304                 }
1305                 switch (*(arg + 1)) {
1306                 case '_':
1307                         if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
1308                             (strncmp(arg, "-_cc=", 5) == 0) ||
1309                             (strncmp(arg, "-_sun=", 6) == 0)) {
1310                                 newae(ctx->i_ae, strchr(arg, '=') + 1);
1311                         }
1312                         break;
1313 
1314                 case 'V':
1315                         ctx->i_flags &= ~CW_F_ECHO;
1316                         newae(ctx->i_ae, arg);
1317                         break;
1318                 case 'o':
1319                         seen_o = 1;
1320                         if (strlen(arg) == 2) {
1321                                 in_output = 1;
1322                                 newae(ctx->i_ae, arg);
1323                         } else if (ctx->i_flags & CW_F_SHADOW) {
1324                                 newae(ctx->i_ae, "-o");
1325                                 newae(ctx->i_ae, ctx->i_discard);
1326                         } else {
1327                                 newae(ctx->i_ae, arg);
1328                         }
1329                         break;
1330                 case 'c':
1331                 case 'S':
1332                         if (strlen(arg) == 2)
1333                                 op = CW_O_COMPILE;
1334                         newae(ctx->i_ae, arg);
1335                         break;
1336                 case 'E':
1337                 case 'P':
1338                         if (strlen(arg) == 2)
1339                                 op = CW_O_PREPROCESS;
1340                 /*FALLTHROUGH*/
1341                 default:
1342                         newae(ctx->i_ae, arg);
1343                 }
1344         }
1345 
1346         free(nameflag);
1347 
1348         if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
1349             (ctx->i_flags & CW_F_SHADOW))






1350                 exit(0);



1351 
1352         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1353                 newae(ctx->i_ae, "-o");
1354                 newae(ctx->i_ae, ctx->i_discard);
1355         }
1356 }
1357 
1358 static void
1359 prepctx(cw_ictx_t *ctx)
1360 {
1361         newae(ctx->i_ae, ctx->i_compiler->c_path);
1362 
1363         if (ctx->i_flags & CW_F_PROG) {
1364                 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
1365                     "shadow" : "primary", ctx->i_compiler->c_path);
1366                 (void) fflush(stdout);
1367         }
1368 
1369         if (!(ctx->i_flags & CW_F_XLATE))
1370                 return;
1371 
1372         switch (ctx->i_compiler->c_style) {
1373         case SUN:
1374                 do_cc(ctx);


1442          */
1443         if (ctx->i_pid <= 0)
1444                 return (-1);
1445 
1446         do {
1447                 if (waitpid(ctx->i_pid, &status, 0) < 0) {
1448                         warn("cannot reap child");
1449                         return (-1);
1450                 }
1451                 if (status != 0) {
1452                         if (WIFSIGNALED(status)) {
1453                                 ret = -WTERMSIG(status);
1454                                 break;
1455                         } else if (WIFEXITED(status)) {
1456                                 ret = WEXITSTATUS(status);
1457                                 break;
1458                         }
1459                 }
1460         } while (!WIFEXITED(status) && !WIFSIGNALED(status));
1461 
1462         (void) unlink(ctx->i_discard);
1463 
1464         if (stat(ctx->i_stderr, &s) < 0) {
1465                 warn("stat failed on child cleanup");
1466                 return (-1);
1467         }
1468         if (s.st_size != 0) {
1469                 FILE *f;
1470 
1471                 if ((f = fopen(ctx->i_stderr, "r")) != NULL) {
1472                         while (fgets(buf, sizeof (buf), f))
1473                                 (void) fprintf(stderr, "%s", buf);
1474                         (void) fflush(stderr);
1475                         (void) fclose(f);
1476                 }
1477         }
1478         (void) unlink(ctx->i_stderr);
1479         free(ctx->i_stderr);
1480 
1481         /*
1482          * cc returns an error code when given -V; we want that to succeed.
1483          */
1484         if (ctx->i_flags & CW_F_PROG)
1485                 return (0);
1486 
1487         return (ret);
1488 }
1489 
1490 static int
1491 exec_ctx(cw_ictx_t *ctx, int block)
1492 {
1493         char *file;
1494 
1495         /*
1496          * To avoid offending cc's sensibilities, the name of its output
1497          * file must end in '.o'.
1498          */
1499         if ((file = tempnam(NULL, ".cw")) == NULL) {
1500                 nomem();
1501                 return (-1);
1502         }
1503         (void) strlcpy(ctx->i_discard, file, MAXPATHLEN);
1504         (void) strlcat(ctx->i_discard, ".o", MAXPATHLEN);
1505         free(file);
1506 
1507         if ((ctx->i_stderr = tempnam(NULL, ".cw")) == NULL) {
1508                 nomem();
1509                 return (-1);
1510         }
1511 
1512         if ((ctx->i_pid = fork()) == 0) {
1513                 int fd;
1514 
1515                 (void) fclose(stderr);
1516                 if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL,
1517                     0666)) < 0) {
1518                         err(1, "open failed for standard error");
1519                 }
1520                 if (dup2(fd, 2) < 0) {
1521                         err(1, "dup2 failed for standard error");
1522                 }
1523                 if (fd != 2)
1524                         (void) close(fd);
1525                 if (freopen("/dev/fd/2", "w", stderr) == NULL) {
1526                         err(1, "freopen failed for /dev/fd/2");
1527                 }


1555         if ((token = strsep(&tspec, ",")) == NULL)
1556                 errx(1, "Compiler is missing a path: %s", spec);
1557         compiler->c_path = token;
1558 
1559         if ((token = strsep(&tspec, ",")) == NULL)
1560                 errx(1, "Compiler is missing a style: %s", spec);
1561 
1562         if ((strcasecmp(token, "gnu") == 0) ||
1563             (strcasecmp(token, "gcc") == 0))
1564                 compiler->c_style = GNU;
1565         else if ((strcasecmp(token, "sun") == 0) ||
1566             (strcasecmp(token, "cc") == 0))
1567                 compiler->c_style = SUN;
1568         else
1569                 errx(1, "unknown compiler style: %s", token);
1570 
1571         if (tspec != NULL)
1572                 errx(1, "Excess tokens in compiler: %s", spec);
1573 }
1574 










































1575 int
1576 main(int argc, char **argv)
1577 {
1578         int ch;
1579         cw_compiler_t primary = { NULL, NULL, 0 };
1580         cw_compiler_t shadows[10];
1581         int nshadows = 0;
1582         int ret = 0;
1583         boolean_t do_serial = B_FALSE;
1584         boolean_t do_exec = B_FALSE;
1585         boolean_t vflg = B_FALSE;
1586         boolean_t Cflg = B_FALSE;
1587         boolean_t cflg = B_FALSE;
1588         boolean_t nflg = B_FALSE;

1589 
1590         cw_ictx_t *main_ctx;
1591 
1592         static struct option longopts[] = {
1593                 { "compiler", no_argument, NULL, 'c' },
1594                 { "noecho", no_argument, NULL, 'n' },
1595                 { "primary", required_argument, NULL, 'p' },
1596                 { "shadow", required_argument, NULL, 's' },
1597                 { "versions", no_argument, NULL, 'v' },
1598                 { NULL, 0, NULL, 0 },
1599         };
1600 
1601 
1602         if ((main_ctx = newictx()) == NULL)
1603                 nomem();
1604 
1605         while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
1606                 switch (ch) {
1607                 case 'c':
1608                         cflg = B_TRUE;


1656         if (nflg == 0)
1657                 main_ctx->i_flags |= CW_F_ECHO;
1658         if (do_exec)
1659                 main_ctx->i_flags |= CW_F_EXEC;
1660         if (Cflg)
1661                 main_ctx->i_flags |= CW_F_CXX;
1662         main_ctx->i_compiler = &primary;
1663 
1664         if (cflg) {
1665                 (void) fputs(primary.c_path, stdout);
1666         }
1667 
1668         if (vflg) {
1669                 (void) printf("cw version %s\n", CW_VERSION);
1670                 (void) fflush(stdout);
1671                 main_ctx->i_flags &= ~CW_F_ECHO;
1672                 main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
1673                 do_serial = 1;
1674         }
1675 










1676         ret |= exec_ctx(main_ctx, do_serial);
1677 
1678         for (int i = 0; i < nshadows; i++) {
1679                 int r;
1680                 cw_ictx_t *shadow_ctx;
1681 
1682                 if ((shadow_ctx = newictx()) == NULL)
1683                         nomem();
1684 
1685                 memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
1686 
1687                 shadow_ctx->i_flags |= CW_F_SHADOW;
1688                 shadow_ctx->i_compiler = &shadows[i];
1689 
1690                 r = exec_ctx(shadow_ctx, do_serial);
1691                 if (r == 0) {
1692                         shadow_ctx->i_next = main_ctx->i_next;
1693                         main_ctx->i_next = shadow_ctx;
1694                 }
1695                 ret |= r;
1696         }
1697 
1698         if (!do_serial) {
1699                 cw_ictx_t *next = main_ctx;
1700                 while (next != NULL) {
1701                         cw_ictx_t *toreap = next;
1702                         next = next->i_next;
1703                         ret |= reap(toreap);
1704                 }
1705         }
1706 

1707         return (ret);
1708 }


 243  * -xtransition                 -Wtransition
 244  * -xunroll=n                   error
 245  * -W0,-xdbggen=no%usedonly     -fno-eliminate-unused-debug-symbols
 246  *                              -fno-eliminate-unused-debug-types
 247  * -Y<c>,<dir>                      error
 248  * -YA,<dir>                      error
 249  * -YI,<dir>                      -nostdinc -I<dir>
 250  * -YP,<dir>                      error
 251  * -YS,<dir>                      error
 252  */
 253 
 254 #include <ctype.h>
 255 #include <err.h>
 256 #include <errno.h>
 257 #include <fcntl.h>
 258 #include <getopt.h>
 259 #include <stdio.h>
 260 #include <stdlib.h>
 261 #include <string.h>
 262 #include <unistd.h>
 263 #include <dirent.h>
 264 
 265 #include <sys/param.h>
 266 #include <sys/stat.h>
 267 #include <sys/types.h>
 268 #include <sys/utsname.h>
 269 #include <sys/wait.h>
 270 
 271 #define CW_F_CXX        0x01
 272 #define CW_F_SHADOW     0x02
 273 #define CW_F_EXEC       0x04
 274 #define CW_F_ECHO       0x08
 275 #define CW_F_XLATE      0x10
 276 #define CW_F_PROG       0x20
 277 
 278 typedef enum cw_op {
 279         CW_O_NONE = 0,
 280         CW_O_PREPROCESS,
 281         CW_O_COMPILE,
 282         CW_O_LINK
 283 } cw_op_t;


 292 
 293 typedef enum {
 294         GNU,
 295         SUN
 296 } compiler_style_t;
 297 
 298 typedef struct {
 299         char *c_name;
 300         char *c_path;
 301         compiler_style_t c_style;
 302 } cw_compiler_t;
 303 
 304 typedef struct cw_ictx {
 305         struct cw_ictx  *i_next;
 306         cw_compiler_t   *i_compiler;
 307         struct aelist   *i_ae;
 308         uint32_t        i_flags;
 309         int             i_oldargc;
 310         char            **i_oldargv;
 311         pid_t           i_pid;
 312         char            *i_tmpdir;
 313         char            *i_stderr;
 314 } cw_ictx_t;
 315 
 316 /*
 317  * Status values to indicate which Studio compiler and associated
 318  * flags are being used.
 319  */
 320 #define M32             0x01    /* -m32 - only on Studio 12 */
 321 #define M64             0x02    /* -m64 - only on Studio 12 */
 322 #define SS11            0x100   /* Studio 11 */
 323 #define SS12            0x200   /* Studio 12 */
 324 
 325 #define TRANS_ENTRY     5
 326 /*
 327  * Translation table definition for the -xarch= flag. The "x_arg"
 328  * value is translated into the appropriate gcc flags according
 329  * to the values in x_trans[n]. The x_flags indicates what compiler
 330  * is being used and what flags have been set via the use of
 331  * "x_arg".
 332  */


 537 static void
 538 xlate(struct aelist *h, const char *xarg, const char **table)
 539 {
 540         while (*table != NULL && strcmp(xarg, *table) != 0) {
 541                 while (*table != NULL)
 542                         table++;
 543                 table++;
 544         }
 545 
 546         if (*table == NULL)
 547                 error(xarg);
 548 
 549         table++;
 550 
 551         while (*table != NULL) {
 552                 newae(h, *table);
 553                 table++;
 554         }
 555 }
 556 
 557 /*
 558  * The compiler wants the output file to end in appropriate extension.  If
 559  * we're generating a name from whole cloth (path == NULL), we assume that
 560  * extension to be .o, otherwise we match the extension of the caller.
 561  */
 562 static char *
 563 discard_file_name(cw_ictx_t *ctx, const char *path)
 564 {
 565         char *ret, *ext;
 566         char tmpl[] = "cwXXXXXX";
 567 
 568         if (path == NULL) {
 569                 ext = ".o";
 570         } else {
 571                 ext = strrchr(path, '.');
 572         }
 573 
 574         /*
 575          * We need absolute control over where the temporary file goes, since
 576          * we rely on it for cleanup so tempnam(3C) and tmpnam(3C) are
 577          * inappropriate (they use TMPDIR, preferentially).
 578          *
 579          * mkstemp(3C) doesn't actually help us, since the temporary file
 580          * isn't used by us, only its name.
 581          */
 582         if (mktemp(tmpl) == NULL)
 583                 nomem();
 584 
 585         (void) asprintf(&ret, "%s/%s%s", ctx->i_tmpdir, tmpl,
 586             (ext != NULL) ? ext : "");
 587 
 588         if (ret == NULL)
 589                 nomem();
 590 
 591         return (ret);
 592 }
 593 
 594 static void
 595 do_gcc(cw_ictx_t *ctx)
 596 {
 597         int c;
 598         int nolibc = 0;
 599         int in_output = 0, seen_o = 0, c_files = 0;
 600         cw_op_t op = CW_O_LINK;
 601         char *model = NULL;
 602         char *nameflag;
 603         int mflag = 0;
 604 
 605         if (ctx->i_flags & CW_F_PROG) {
 606                 newae(ctx->i_ae, "--version");
 607                 return;
 608         }
 609 
 610         newae(ctx->i_ae, "-fident");
 611         newae(ctx->i_ae, "-finline");
 612         newae(ctx->i_ae, "-fno-inline-functions");
 613         newae(ctx->i_ae, "-fno-builtin");


 651                 } else {
 652                         /*
 653                          * Discard inline files that gcc doesn't grok
 654                          */
 655                         if (!in_output && arglen > 3 &&
 656                             strcmp(arg + arglen - 3, ".il") == 0)
 657                                 continue;
 658 
 659                         if (!in_output && arglen > 2 &&
 660                             arg[arglen - 2] == '.' &&
 661                             (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
 662                             arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
 663                                 c_files++;
 664 
 665                         /*
 666                          * Otherwise, filenames and partial arguments
 667                          * are passed through for gcc to chew on.  However,
 668                          * output is always discarded for the secondary
 669                          * compiler.
 670                          */
 671                         if ((ctx->i_flags & CW_F_SHADOW) && in_output) {
 672                                 newae(ctx->i_ae, discard_file_name(ctx, arg));
 673                         } else {
 674                                 newae(ctx->i_ae, arg);
 675                         }
 676                         in_output = 0;
 677                         continue;
 678                 }
 679 
 680                 if (ctx->i_flags & CW_F_CXX) {
 681                         if (strncmp(arg, "-_g++=", 6) == 0) {
 682                                 newae(ctx->i_ae, strchr(arg, '=') + 1);
 683                                 continue;
 684                         }
 685                         if (strncmp(arg, "-compat=", 8) == 0) {
 686                                 /* discard -compat=4 and -compat=5 */
 687                                 continue;
 688                         }
 689                         if (strcmp(arg, "-Qoption") == 0) {
 690                                 /* discard -Qoption and its two arguments */
 691                                 if (ctx->i_oldargc < 3)
 692                                         error(arg);
 693                                 ctx->i_oldargc -= 2;
 694                                 ctx->i_oldargv += 2;
 695                                 continue;


 771                         break;
 772                 case 'A':
 773                 case 'h':
 774                 case 'I':
 775                 case 'i':
 776                 case 'L':
 777                 case 'l':
 778                 case 'R':
 779                 case 'U':
 780                 case 'u':
 781                 case 'w':
 782                         newae(ctx->i_ae, arg);
 783                         break;
 784                 case 'o':
 785                         seen_o = 1;
 786                         if (arglen == 1) {
 787                                 in_output = 1;
 788                                 newae(ctx->i_ae, arg);
 789                         } else if (ctx->i_flags & CW_F_SHADOW) {
 790                                 newae(ctx->i_ae, "-o");
 791                                 newae(ctx->i_ae, discard_file_name(ctx, arg));
 792                         } else {
 793                                 newae(ctx->i_ae, arg);
 794                         }
 795                         break;
 796                 case 'D':
 797                         newae(ctx->i_ae, arg);
 798                         /*
 799                          * XXX  Clearly a hack ... do we need _KADB too?
 800                          */
 801                         if (strcmp(arg, "-D_KERNEL") == 0 ||
 802                             strcmp(arg, "-D_BOOT") == 0)
 803                                 newae(ctx->i_ae, "-ffreestanding");
 804                         break;
 805                 case 'd':
 806                         if (arglen == 2) {
 807                                 if (strcmp(arg, "-dy") == 0) {
 808                                         newae(ctx->i_ae, "-Wl,-dy");
 809                                         break;
 810                                 }
 811                                 if (strcmp(arg, "-dn") == 0) {


1209                                 s[1] = 'I';
1210                                 newae(ctx->i_ae, "-nostdinc");
1211                                 newae(ctx->i_ae, s);
1212                                 free(s);
1213                                 break;
1214                         }
1215                         error(arg);
1216                         break;
1217                 case 'Q':
1218                         /*
1219                          * We could map -Qy into -Wl,-Qy etc.
1220                          */
1221                 default:
1222                         error(arg);
1223                         break;
1224                 }
1225         }
1226 
1227         free(nameflag);
1228 
1229         /*
1230          * When compiling multiple source files in a single invocation some
1231          * compilers output objects into the current directory with
1232          * predictable and conventional names.
1233          *
1234          * We prevent any attempt to compile multiple files at once so that
1235          * any such objects created by a shadow can't escape into a later
1236          * link-edit.
1237          */
1238         if (c_files > 1 && op != CW_O_PREPROCESS) {
1239                 errx(2, "multiple source files are "
1240                     "allowed only with -E or -P");
1241         }
1242 
1243         /*
1244          * Make sure that we do not have any unintended interactions between
1245          * the xarch options passed in and the version of the Studio compiler
1246          * used.
1247          */
1248         if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
1249                 errx(2,
1250                     "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
1251         }
1252 
1253         switch (mflag) {
1254         case 0:
1255                 /* FALLTHROUGH */
1256         case M32:
1257 #if defined(__sparc)
1258                 /*


1286                 break;
1287         case (SS12|M32):
1288 #if defined(__sparc)
1289                 /*
1290                  * Need to add in further 32 bit options because with SS12
1291                  * the xarch=sparcvis option can be applied to 32 or 64
1292                  * bit, and so the translatation table (xtbl) cannot handle
1293                  * that.
1294                  */
1295                 newae(ctx->i_ae, "-mv8plus");
1296 #endif
1297                 break;
1298         case (SS12|M64):
1299                 break;
1300         default:
1301                 (void) fprintf(stderr,
1302                     "Incompatible -xarch= and/or -m32/-m64 options used.\n");
1303                 exit(2);
1304         }
1305 
1306         if (ctx->i_flags & CW_F_SHADOW) {
1307                 if (op == CW_O_PREPROCESS)
1308                         exit(0);
1309                 else if (op == CW_O_LINK && c_files == 0)
1310                         exit(0);
1311         }
1312 
1313         if (model != NULL)
1314                 newae(ctx->i_ae, model);
1315         if (!nolibc)
1316                 newae(ctx->i_ae, "-lc");
1317         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1318                 newae(ctx->i_ae, "-o");
1319                 newae(ctx->i_ae, discard_file_name(ctx, NULL));
1320         }
1321 }
1322 
1323 static void
1324 do_cc(cw_ictx_t *ctx)
1325 {
1326         int in_output = 0, seen_o = 0, c_files = 0;
1327         cw_op_t op = CW_O_LINK;
1328         char *nameflag;
1329 
1330         if (ctx->i_flags & CW_F_PROG) {
1331                 newae(ctx->i_ae, "-V");
1332                 return;
1333         }
1334 
1335         if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
1336                 nomem();
1337 
1338         while (--ctx->i_oldargc > 0) {
1339                 char *arg = *++ctx->i_oldargv;
1340                 size_t arglen = strlen(arg);
1341 
1342                 if (strncmp(arg, "-_CC=", 5) == 0) {
1343                         newae(ctx->i_ae, strchr(arg, '=') + 1);
1344                         continue;
1345                 }
1346 
1347                 if (*arg != '-') {
1348                         if (!in_output && arglen > 2 &&
1349                             arg[arglen - 2] == '.' &&
1350                             (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
1351                             arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
1352                                 c_files++;
1353 
1354                         if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
1355                                 newae(ctx->i_ae, arg);
1356                         } else {
1357                                 in_output = 0;
1358                                 newae(ctx->i_ae, discard_file_name(ctx, arg));
1359                         }
1360                         continue;
1361                 }
1362                 switch (*(arg + 1)) {
1363                 case '_':
1364                         if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
1365                             (strncmp(arg, "-_cc=", 5) == 0) ||
1366                             (strncmp(arg, "-_sun=", 6) == 0)) {
1367                                 newae(ctx->i_ae, strchr(arg, '=') + 1);
1368                         }
1369                         break;
1370 
1371                 case 'V':
1372                         ctx->i_flags &= ~CW_F_ECHO;
1373                         newae(ctx->i_ae, arg);
1374                         break;
1375                 case 'o':
1376                         seen_o = 1;
1377                         if (strlen(arg) == 2) {
1378                                 in_output = 1;
1379                                 newae(ctx->i_ae, arg);
1380                         } else if (ctx->i_flags & CW_F_SHADOW) {
1381                                 newae(ctx->i_ae, "-o");
1382                                 newae(ctx->i_ae, discard_file_name(ctx, arg));
1383                         } else {
1384                                 newae(ctx->i_ae, arg);
1385                         }
1386                         break;
1387                 case 'c':
1388                 case 'S':
1389                         if (strlen(arg) == 2)
1390                                 op = CW_O_COMPILE;
1391                         newae(ctx->i_ae, arg);
1392                         break;
1393                 case 'E':
1394                 case 'P':
1395                         if (strlen(arg) == 2)
1396                                 op = CW_O_PREPROCESS;
1397                 /*FALLTHROUGH*/
1398                 default:
1399                         newae(ctx->i_ae, arg);
1400                 }
1401         }
1402 
1403         free(nameflag);
1404 
1405         /* See the comment on this same code in do_gcc() */
1406         if (c_files > 1 && op != CW_O_PREPROCESS) {
1407                 errx(2, "multiple source files are "
1408                     "allowed only with -E or -P");
1409         }
1410 
1411         if (ctx->i_flags & CW_F_SHADOW) {
1412                 if (op == CW_O_PREPROCESS)
1413                         exit(0);
1414                 else if (op == CW_O_LINK && c_files == 0)
1415                         exit(0);
1416         }
1417 
1418         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1419                 newae(ctx->i_ae, "-o");
1420                 newae(ctx->i_ae, discard_file_name(ctx, NULL));
1421         }
1422 }
1423 
1424 static void
1425 prepctx(cw_ictx_t *ctx)
1426 {
1427         newae(ctx->i_ae, ctx->i_compiler->c_path);
1428 
1429         if (ctx->i_flags & CW_F_PROG) {
1430                 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
1431                     "shadow" : "primary", ctx->i_compiler->c_path);
1432                 (void) fflush(stdout);
1433         }
1434 
1435         if (!(ctx->i_flags & CW_F_XLATE))
1436                 return;
1437 
1438         switch (ctx->i_compiler->c_style) {
1439         case SUN:
1440                 do_cc(ctx);


1508          */
1509         if (ctx->i_pid <= 0)
1510                 return (-1);
1511 
1512         do {
1513                 if (waitpid(ctx->i_pid, &status, 0) < 0) {
1514                         warn("cannot reap child");
1515                         return (-1);
1516                 }
1517                 if (status != 0) {
1518                         if (WIFSIGNALED(status)) {
1519                                 ret = -WTERMSIG(status);
1520                                 break;
1521                         } else if (WIFEXITED(status)) {
1522                                 ret = WEXITSTATUS(status);
1523                                 break;
1524                         }
1525                 }
1526         } while (!WIFEXITED(status) && !WIFSIGNALED(status));
1527 


1528         if (stat(ctx->i_stderr, &s) < 0) {
1529                 warn("stat failed on child cleanup");
1530                 return (-1);
1531         }
1532         if (s.st_size != 0) {
1533                 FILE *f;
1534 
1535                 if ((f = fopen(ctx->i_stderr, "r")) != NULL) {
1536                         while (fgets(buf, sizeof (buf), f))
1537                                 (void) fprintf(stderr, "%s", buf);
1538                         (void) fflush(stderr);
1539                         (void) fclose(f);
1540                 }
1541         }
1542         (void) unlink(ctx->i_stderr);
1543         free(ctx->i_stderr);
1544 
1545         /*
1546          * cc returns an error code when given -V; we want that to succeed.
1547          */
1548         if (ctx->i_flags & CW_F_PROG)
1549                 return (0);
1550 
1551         return (ret);
1552 }
1553 
1554 static int
1555 exec_ctx(cw_ictx_t *ctx, int block)
1556 {
1557         if ((ctx->i_stderr = tempnam(ctx->i_tmpdir, "cw")) == NULL) {














1558                 nomem();
1559                 return (-1);
1560         }
1561 
1562         if ((ctx->i_pid = fork()) == 0) {
1563                 int fd;
1564 
1565                 (void) fclose(stderr);
1566                 if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL,
1567                     0666)) < 0) {
1568                         err(1, "open failed for standard error");
1569                 }
1570                 if (dup2(fd, 2) < 0) {
1571                         err(1, "dup2 failed for standard error");
1572                 }
1573                 if (fd != 2)
1574                         (void) close(fd);
1575                 if (freopen("/dev/fd/2", "w", stderr) == NULL) {
1576                         err(1, "freopen failed for /dev/fd/2");
1577                 }


1605         if ((token = strsep(&tspec, ",")) == NULL)
1606                 errx(1, "Compiler is missing a path: %s", spec);
1607         compiler->c_path = token;
1608 
1609         if ((token = strsep(&tspec, ",")) == NULL)
1610                 errx(1, "Compiler is missing a style: %s", spec);
1611 
1612         if ((strcasecmp(token, "gnu") == 0) ||
1613             (strcasecmp(token, "gcc") == 0))
1614                 compiler->c_style = GNU;
1615         else if ((strcasecmp(token, "sun") == 0) ||
1616             (strcasecmp(token, "cc") == 0))
1617                 compiler->c_style = SUN;
1618         else
1619                 errx(1, "unknown compiler style: %s", token);
1620 
1621         if (tspec != NULL)
1622                 errx(1, "Excess tokens in compiler: %s", spec);
1623 }
1624 
1625 static void
1626 cleanup(cw_ictx_t *ctx)
1627 {
1628         DIR *dirp;
1629         struct dirent *dp;
1630         char buf[MAXPATHLEN];
1631 
1632         if ((dirp = opendir(ctx->i_tmpdir)) == NULL) {
1633                 if (errno != ENOENT) {
1634                         err(1, "couldn't open temp directory: %s",
1635                             ctx->i_tmpdir);
1636                 } else {
1637                         return;
1638                 }
1639         }
1640 
1641         errno = 0;
1642         while ((dp = readdir(dirp)) != NULL) {
1643                 (void) snprintf(buf, MAXPATHLEN, "%s/%s", ctx->i_tmpdir,
1644                     dp->d_name);
1645 
1646                 if (strncmp(dp->d_name, ".", strlen(dp->d_name)) == 0 ||
1647                     strncmp(dp->d_name, "..", strlen(dp->d_name)) == 0)
1648                         continue;
1649 
1650                 if (unlink(buf) == -1)
1651                         err(1, "failed to unlink temp file: %s", dp->d_name);
1652                 errno = 0;
1653         }
1654 
1655         if (errno != 0) {
1656                 err(1, "failed to read temporary directory: %s",
1657                     ctx->i_tmpdir);
1658         }
1659 
1660         (void) closedir(dirp);
1661         if (rmdir(ctx->i_tmpdir) != 0) {
1662                 err(1, "failed to unlink temporary directory: %s",
1663                     ctx->i_tmpdir);
1664         }
1665 }
1666 
1667 int
1668 main(int argc, char **argv)
1669 {
1670         int ch;
1671         cw_compiler_t primary = { NULL, NULL, 0 };
1672         cw_compiler_t shadows[10];
1673         int nshadows = 0;
1674         int ret = 0;
1675         boolean_t do_serial = B_FALSE;
1676         boolean_t do_exec = B_FALSE;
1677         boolean_t vflg = B_FALSE;
1678         boolean_t Cflg = B_FALSE;
1679         boolean_t cflg = B_FALSE;
1680         boolean_t nflg = B_FALSE;
1681         char *tmpdir;
1682 
1683         cw_ictx_t *main_ctx;
1684 
1685         static struct option longopts[] = {
1686                 { "compiler", no_argument, NULL, 'c' },
1687                 { "noecho", no_argument, NULL, 'n' },
1688                 { "primary", required_argument, NULL, 'p' },
1689                 { "shadow", required_argument, NULL, 's' },
1690                 { "versions", no_argument, NULL, 'v' },
1691                 { NULL, 0, NULL, 0 },
1692         };
1693 
1694 
1695         if ((main_ctx = newictx()) == NULL)
1696                 nomem();
1697 
1698         while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
1699                 switch (ch) {
1700                 case 'c':
1701                         cflg = B_TRUE;


1749         if (nflg == 0)
1750                 main_ctx->i_flags |= CW_F_ECHO;
1751         if (do_exec)
1752                 main_ctx->i_flags |= CW_F_EXEC;
1753         if (Cflg)
1754                 main_ctx->i_flags |= CW_F_CXX;
1755         main_ctx->i_compiler = &primary;
1756 
1757         if (cflg) {
1758                 (void) fputs(primary.c_path, stdout);
1759         }
1760 
1761         if (vflg) {
1762                 (void) printf("cw version %s\n", CW_VERSION);
1763                 (void) fflush(stdout);
1764                 main_ctx->i_flags &= ~CW_F_ECHO;
1765                 main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
1766                 do_serial = 1;
1767         }
1768 
1769         tmpdir = getenv("TMPDIR");
1770         if (tmpdir == NULL)
1771                 tmpdir = "/tmp";
1772 
1773         if (asprintf(&main_ctx->i_tmpdir, "%s/cw.XXXXXX", tmpdir) == -1)
1774                 nomem();
1775 
1776         if ((main_ctx->i_tmpdir = mkdtemp(main_ctx->i_tmpdir)) == NULL)
1777                 errx(1, "failed to create temporary directory");
1778 
1779         ret |= exec_ctx(main_ctx, do_serial);
1780 
1781         for (int i = 0; i < nshadows; i++) {
1782                 int r;
1783                 cw_ictx_t *shadow_ctx;
1784 
1785                 if ((shadow_ctx = newictx()) == NULL)
1786                         nomem();
1787 
1788                 (void) memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
1789 
1790                 shadow_ctx->i_flags |= CW_F_SHADOW;
1791                 shadow_ctx->i_compiler = &shadows[i];
1792 
1793                 r = exec_ctx(shadow_ctx, do_serial);
1794                 if (r == 0) {
1795                         shadow_ctx->i_next = main_ctx->i_next;
1796                         main_ctx->i_next = shadow_ctx;
1797                 }
1798                 ret |= r;
1799         }
1800 
1801         if (!do_serial) {
1802                 cw_ictx_t *next = main_ctx;
1803                 while (next != NULL) {
1804                         cw_ictx_t *toreap = next;
1805                         next = next->i_next;
1806                         ret |= reap(toreap);
1807                 }
1808         }
1809 
1810         cleanup(main_ctx);
1811         return (ret);
1812 }