| /* |
| * |
| * Copyright (c) International Business Machines Corp., 2001 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| /* |
| * runcc.a - common functions for lib6 testing |
| * |
| * HISTORY |
| * 05/2005 written by David L Stevens |
| * |
| * RESTRICTIONS: |
| * None. |
| * |
| */ |
| |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <ctype.h> |
| |
| #include <sys/wait.h> |
| |
| #include "test.h" |
| |
| char fieldref[1024]; |
| char program[8192]; |
| |
| char *filetmpl = "/tmp/%.*s_XXXXXX"; |
| |
| char cmd[1024]; |
| |
| /* |
| * like strspn, with ASCII, numbers and underscore only |
| */ |
| int strfpn(char *name) |
| { |
| int i; |
| |
| for (i = 0; *name; ++name, ++i) |
| if (!(isalnum(*name) || *name == '_')) |
| break; |
| return i; |
| } |
| |
| int runcc(char *tname, char *filename0, char *program) |
| { |
| static char filename[1024]; |
| int fd, es, saved_errno; |
| char *cflags = ""; |
| |
| fd = mkstemp(filename0); |
| if (fd < 0) { |
| perror("mkstemp"); |
| return -1; |
| } |
| strncpy(filename, filename0, sizeof(filename) - 1); |
| filename[sizeof(filename) - 1] = '\0'; |
| strncat(filename, ".c", sizeof(filename) - strlen(filename) - 1); |
| if (rename(filename0, filename) < 0) { |
| perror("rename"); |
| unlink(filename0); |
| return -1; |
| } |
| if (write(fd, program, strlen(program)) < 0) { |
| perror("write"); |
| unlink(filename); |
| return -1; |
| } |
| (void)close(fd); |
| |
| cflags = getenv("CFLAGS"); |
| if (cflags == NULL) { |
| tst_resm(TINFO, "CFLAGS not found, using default cc arch."); |
| cflags = ""; |
| } |
| |
| snprintf(cmd, sizeof(cmd), "%s %s -o %s %s > /tmp/test 2>&1", "cc", |
| cflags, filename0, filename); |
| es = system(cmd); |
| if (WEXITSTATUS(es) == 127) { |
| tst_resm(TBROK, "can't run C compiler: \"%s\"", cmd); |
| if (unlink(filename) < 0) |
| tst_resm(TWARN, "%s; unlink \"%s\" failed: %s", tname, |
| filename, strerror(errno)); |
| return -1; |
| } |
| if (unlink(filename) < 0) |
| tst_resm(TWARN, "%s: unlink \"%s\" failed: %s", tname, |
| filename, strerror(errno)); |
| |
| if (WIFSIGNALED(es) && |
| (WTERMSIG(es) == SIGINT || WTERMSIG(es) == SIGQUIT)) |
| exit(1); |
| |
| if (WEXITSTATUS(es)) { |
| tst_resm(TFAIL, "%s: not present", tname); |
| return -1; |
| } |
| /* run the test */ |
| |
| es = system(filename0); |
| saved_errno = errno; |
| if (unlink(filename0) < 0) |
| tst_resm(TWARN, "%s: unlink \"%s\" failed: %s", tname, |
| filename0, strerror(errno)); |
| |
| if (WIFSIGNALED(es) && |
| (WTERMSIG(es) == SIGINT || WTERMSIG(es) == SIGQUIT)) |
| exit(1); |
| |
| if (WEXITSTATUS(es) == 127) |
| tst_resm(TBROK, "%s: can't run \"%s\": %s", tname, filename0, |
| strerror(saved_errno)); |
| if (WEXITSTATUS(es)) |
| tst_resm(TFAIL, "%s: present, but incorrect", tname); |
| else |
| tst_resm(TPASS, "%s present and correct", tname); |
| return 0; |
| } |
| |
| char *field_fmt = "\n\texit((offsetof(struct %s, %s) != %s) || " |
| "sizeof(tst.%s) != (%s));\n"; |
| /* no offset check */ |
| char *field_fmt2 = "\n\texit(sizeof(tst.%s) != (%s));\n"; |
| |
| const char *stmpl = |
| "%s\n#ifndef offsetof\n" |
| "#define offsetof(dtype, dfield) ((int)&((dtype *)0)->dfield)\n" |
| "#endif\n\nstruct %s tst;\n\nmain(int argc, char *argv[])\n{\n\t%s\n}\n"; |
| |
| int |
| structcheck(char *tname, char *incl, char *structure, char *field, |
| char *offset, char *size) |
| { |
| int rv; |
| static char filename[1024]; |
| |
| if (offset) |
| sprintf(fieldref, field_fmt, structure, field, offset, field, |
| size); |
| else |
| sprintf(fieldref, field_fmt2, field, size); |
| sprintf(program, stmpl, incl, structure, fieldref); |
| snprintf(filename, sizeof(filename), filetmpl, strfpn(structure), |
| structure); |
| rv = runcc(tname, filename, program); |
| return rv; |
| } |
| |
| char *aliasfmt = |
| "exit(&tst.%s != &tst.%s || sizeof(tst.%s) != sizeof(tst.%s));"; |
| |
| int |
| aliascheck(char *tname, char *incl, char *structure, char *field, char *dname) |
| { |
| int rv; |
| static char filename[1024]; |
| |
| sprintf(fieldref, aliasfmt, field, dname, field, dname); |
| sprintf(program, stmpl, incl, structure, fieldref); |
| snprintf(filename, sizeof(filename), filetmpl, strfpn(structure), |
| structure); |
| rv = runcc(tname, filename, program); |
| return rv; |
| } |
| |
| const char *dtmpl = |
| "%s\n\nmain(int argc, char *argv[])\n{\n\texit((%s) != (%s));\n}\n"; |
| |
| int valuecheck(char *tname, char *incl, char *dname, char *dval) |
| { |
| int rv; |
| static char filename[1024]; |
| |
| sprintf(program, dtmpl, incl, dname, dval); |
| snprintf(filename, sizeof(filename), filetmpl, strfpn(dname), dname); |
| rv = runcc(tname, filename, program); |
| return rv; |
| } |
| |
| const char *ftmpl = |
| "%s\n\nmain(int argc, char *argv[])\n{\n#ifdef %s\n\texit(0);\n#else\n" |
| "\tsyntax error;\n#endif\n}\n"; |
| |
| int funccheck(char *tname, char *incl, char *fname) |
| { |
| int rv; |
| static char filename[1024]; |
| |
| sprintf(program, ftmpl, incl, fname); |
| snprintf(filename, sizeof(filename), filetmpl, strfpn(fname), fname); |
| rv = runcc(tname, filename, program); |
| return rv; |
| } |