linux: Use fchmodat2 on fchmod for flags different than 0 (BZ 26401)
[glibc.git] / stdlib / isomac.c
bloba371bb25935ea43db29b4f9ab0f4b7b60937c6f1
1 /* Check system header files for ISO 9899:1990 (ISO C) compliance.
2 Copyright (C) 1996-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 /* This is a simple minded program that tries to find illegal macro
20 definitions in system header files. Illegal macro definitions are
21 those not from the implementation namespace (i.e. not starting with
22 an underscore) or not matching any identifier mandated by The
23 Standard. Some common macro names are considered okay, e.g. all those
24 beginning with E (which may be defined in <errno.h>) or ending in
25 _MAX. See the arrays prefix[] and suffix[] below for details.
27 In a compliant implementation no other macros can be defined, because
28 you could write strictly conforming programs that may fail to compile
29 due to syntax errors: suppose <stdio.h> defines PIPE_BUF, then the
30 conforming
32 #include <assert.h>
33 #include <stdio.h> <- or where the bogus macro is defined
34 #include <string.h>
35 #define STR(x) #x
36 #define XSTR(x) STR(x)
37 int main (void)
39 int PIPE_BUF = 0;
40 assert (strcmp ("PIPE_BUF", XSTR (PIPE_BUF)) == 0);
41 return 0;
44 is expected to compile and meet the assertion. If it does not, your
45 compiler compiles some other language than Standard C.
47 REQUIREMENTS:
48 This program calls ${1-gcc} to get the list of defined macros. If you
49 don't have gcc you're probably out of luck unless your compiler or
50 preprocessor has something similar to gcc's -dM option. This program
51 assumes headers are found in the default search path (pass -I... in
52 $2 if this is not the case) and that there is a writable /tmp directory.
54 OUTPUT:
55 Each header file name is printed, followed by illegal macro names
56 and their definition. For the above example, you would see
57 ...
58 /usr/include/stdio.h
59 #define PIPE_BUF 5120
60 ...
61 If your implementation does not yet incorporate Amendment 1 you
62 will see messages about iso646.h, wctype.h and wchar.h not being
63 found. */
65 #ifndef _GNU_SOURCE
66 # define _GNU_SOURCE 1
67 #endif
69 #include <ctype.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
75 #define HEADER_MAX 256
77 static char macrofile[] = "/tmp/isomac.XXXXXX";
79 /* ISO C header names including Amendment 1 (without ".h" suffix). */
80 static char *header[] =
82 "assert", "ctype", "errno", "float", "iso646", "limits", "locale",
83 "math", "setjmp", "signal", "stdarg", "stddef", "stdio", "stdlib",
84 "string", "time", "wchar", "wctype"
87 /* Macros with these prefixes are considered okay. */
88 static char *prefix[] =
90 "_", "E", "is", "str", "mem", "SIG", "FLT_", "DBL_", "LDBL_",
91 "LC_", "wmem", "wcs"
94 /* Macros with these suffixes are considered okay. Will not work for
95 parametrized macros with arguments. */
96 static char *suffix[] =
98 "_MAX", "_MIN"
101 /* These macros are considered okay. In fact, these are just more prefixes. */
102 static char *macros[] =
104 "BUFSIZ", "CHAR_BIT", "CHAR_MAX", "CHAR_MIN", "CLOCKS_PER_SEC",
105 "DBL_DIG", "DBL_EPSILON", "DBL_MANT_DIG", "DBL_MAX",
106 "DBL_MAX_10_EXP", "DBL_MAX_EXP", "DBL_MIN", "DBL_MIN_10_EXP",
107 "DBL_MIN_EXP", "EDOM", "EILSEQ", "EOF", "ERANGE", "EXIT_FAILURE",
108 "EXIT_SUCCESS", "FILENAME_MAX", "FLT_DIG", "FLT_EPSILON",
109 "FLT_MANT_DIG", "FLT_MAX", "FLT_MAX_10_EXP", "FLT_MAX_EXP",
110 "FLT_MIN", "FLT_MIN_10_EXP", "FLT_MIN_EXP", "FLT_RADIX",
111 "FLT_ROUNDS", "FOPEN_MAX", "HUGE_VAL", "INT_MAX", "INT_MIN",
112 "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC",
113 "LC_TIME", "LDBL_DIG", "LDBL_EPSILON", "LDBL_MANT_DIG", "LDBL_MAX",
114 "LDBL_MAX_10_EXP", "LDBL_MAX_EXP", "LDBL_MIN", "LDBL_MIN_10_EXP",
115 "LDBL_MIN_EXP", "LONG_MAX", "LONG_MIN", "L_tmpnam", "MB_CUR_MAX",
116 "MB_LEN_MAX", "NDEBUG", "NULL", "RAND_MAX", "SCHAR_MAX",
117 "SCHAR_MIN", "SEEK_CUR", "SEEK_END", "SEEK_SET", "SHRT_MAX",
118 "SHRT_MIN", "SIGABRT", "SIGFPE", "SIGILL", "SIGINT", "SIGSEGV",
119 "SIGTERM", "SIG_DFL", "SIG_ERR", "SIG_IGN", "TMP_MAX", "UCHAR_MAX",
120 "UINT_MAX", "ULONG_MAX", "USHRT_MAX", "WCHAR_MAX", "WCHAR_MIN",
121 "WEOF", "_IOFBF", "_IOLBF", "_IONBF", "abort", "abs", "acos",
122 "acosf", "acosl", "and", "and_eq", "asctime", "asin", "asinf",
123 "asinl", "assert", "atan", "atan2", "atan2f", "atan2l", "atanf",
124 "atanl", "atexit", "atof", "atoi", "atol", "bitand", "bitor",
125 "bsearch", "btowc", "calloc", "ceil", "ceilf", "ceill", "clearerr",
126 "clock", "clock_t", "compl", "cos", "cosf", "cosh", "coshf",
127 "coshl", "cosl", "ctime", "difftime", "div", "div_t", "errno",
128 "exit", "exp", "expf", "expl", "fabs", "fabsf", "fabsl", "fclose",
129 "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets", "fgetwc",
130 "fgetws", "floor", "floorf", "floorl", "fmod", "fmodf", "fmodl",
131 "fopen", "fprintf", "fputc", "fputs", "fputwc", "fputws", "fread",
132 "free", "freopen", "frexp", "frexpf", "frexpl", "fscanf", "fseek",
133 "fsetpos", "ftell", "fwide", "fwprintf", "fwrite", "fwscanf",
134 "getc", "getchar", "getenv", "gets", "getwc", "getwchar", "gmtime",
135 "isalnum", "isalpha", "iscntrl", "isdigit", "isgraph", "islower",
136 "isprint", "ispunct", "isspace", "isupper", "iswalnum", "iswalpha",
137 "iswcntrl", "iswctype", "iswdigit", "iswgraph", "iswlower",
138 "iswprint", "iswpunct", "iswspace", "iswupper", "iswxdigit",
139 "isxdigit", "labs", "ldexp", "ldexpf", "ldexpl", "ldiv", "ldiv_t",
140 "localeconv", "localtime", "log", "log10", "log10f", "log10l",
141 "logf", "logl", "longjmp", "malloc", "mblen", "mbrlen", "mbrtowc",
142 "mbsinit", "mbsrtowcs", "mbstate_t", "mbstowcs", "mbtowc", "memchr",
143 "memcmp", "memcpy", "memmove", "memset", "mktime", "modf", "modff",
144 "modfl", "not", "not_eq", "offsetof", "or", "or_eq", "perror",
145 "pow", "powf", "powl", "printf", "ptrdiff_t", "putc", "putchar",
146 "puts", "putwc", "putwchar", "qsort", "raise", "rand", "realloc",
147 "remove", "rename", "rewind", "scanf", "setbuf", "setjmp",
148 "setlocale", "setvbuf", "sig_atomic_t", "signal", "sin", "sinf",
149 "sinh", "sinhf", "sinhl", "sinl", "size_t", "sprintf", "sqrt",
150 "sqrtf", "sqrtl", "srand", "sscanf", "stderr", "stdin", "stdout",
151 "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn",
152 "strerror", "strftime", "strlen", "strncat", "strncmp", "strncpy",
153 "strpbrk", "strrchr", "strspn", "strstr", "strtod", "strtok",
154 "strtol", "strtoul", "strxfrm", "swprintf", "swscanf", "system",
155 "tan", "tanf", "tanh", "tanhf", "tanhl", "tanl", "time", "time_t",
156 "tmpfile", "tmpnam", "tolower", "toupper", "towctrans", "towlower",
157 "towupper", "ungetc", "ungetwc", "va_arg", "va_copy", "va_end", "va_start",
158 "vfprintf", "vfwprintf", "vprintf", "vsprintf", "vswprintf",
159 "vwprintf", "wchar_t", "wcrtomb", "wcscat", "wcschr", "wcscmp",
160 "wcscoll", "wcscpy", "wcscspn", "wcsftime", "wcslen", "wcsncat",
161 "wcsncmp", "wcsncpy", "wcspbrk", "wcsrchr", "wcsrtombs", "wcsspn",
162 "wcsstr", "wcstod", "wcstok", "wcstol", "wcstombs", "wcstoul",
163 "wcsxfrm", "wctob", "wctomb", "wctrans", "wctrans_t", "wctype",
164 "wctype_t", "wint_t", "wmemchr", "wmemcmp", "wmemcpy", "wmemmove",
165 "wmemset", "wprintf", "wscanf", "xor", "xor_eq"
168 #define NUMBER_OF_HEADERS (sizeof header / sizeof *header)
169 #define NUMBER_OF_PREFIXES (sizeof prefix / sizeof *prefix)
170 #define NUMBER_OF_SUFFIXES (sizeof suffix / sizeof *suffix)
171 #define NUMBER_OF_MACROS (sizeof macros / sizeof *macros)
174 /* Format string to build command to invoke compiler. */
175 static const char fmt[] = "\
176 echo \"#include <%s>\" |\
177 %s -E -dM -ansi -pedantic %s -D_LIBC -D_ISOMAC \
178 -DIN_MODULE=MODULE_extramodules -I. \
179 -isystem `%s --print-prog-name=include` - 2> /dev/null > %s";
182 /* The compiler we use (given on the command line). */
183 char *CC;
184 /* The -I parameters for CC to find all headers. */
185 char *INC;
187 static char *xstrndup (const char *, size_t);
188 static const char **get_null_defines (void);
189 static int check_header (const char *, const char **);
192 main (int argc, char *argv[])
194 int h;
195 int result = 0;
196 const char **ignore_list;
198 CC = argc > 1 ? argv[1] : "gcc";
199 INC = argc > 2 ? argv[2] : "";
201 if (system (NULL) == 0)
203 puts ("Sorry, no command processor.");
204 return EXIT_FAILURE;
207 /* First get list of symbols which are defined by the compiler. */
208 ignore_list = get_null_defines ();
210 fputs ("Tested files:\n", stdout);
212 for (h = 0; h < NUMBER_OF_HEADERS; ++h)
214 char file_name[HEADER_MAX];
215 sprintf (file_name, "%s.h", header[h]);
216 result |= check_header (file_name, ignore_list);
219 remove (macrofile);
221 /* The test suite should return errors but for now this is not
222 practical. Give a warning and ask the user to correct the bugs. */
223 return result;
227 static char *
228 xstrndup (const char *s, size_t n)
230 size_t len = n;
231 char *new = malloc (len + 1);
233 if (new == NULL)
234 return NULL;
236 new[len] = '\0';
237 return memcpy (new, s, len);
241 static const char **
242 get_null_defines (void)
244 char line[BUFSIZ], *command;
245 char **result = NULL;
246 size_t result_len = 0;
247 size_t result_max = 0;
248 FILE *input;
249 int first = 1;
251 int fd = mkstemp (macrofile);
252 if (fd == -1)
254 printf ("mkstemp failed: %m\n");
255 exit (1);
257 close (fd);
259 command = malloc (sizeof fmt + sizeof "/dev/null" + 2 * strlen (CC)
260 + strlen (INC) + strlen (macrofile));
262 if (command == NULL)
264 puts ("No more memory.");
265 exit (1);
268 sprintf (command, fmt, "/dev/null", CC, INC, CC, macrofile);
270 if (system (command))
272 puts ("system() returned nonzero");
273 free (command);
274 return NULL;
276 free (command);
277 input = fopen (macrofile, "r");
279 if (input == NULL)
281 printf ("Could not read %s: ", macrofile);
282 perror (NULL);
283 return NULL;
286 while (fgets (line, sizeof line, input) != NULL)
288 int i, okay = 0;
289 size_t endmac;
290 char *start, *end;
291 if (strlen (line) < 9 || line[7] != ' ')
292 { /* "#define A" */
293 printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
294 line);
295 continue;
297 if (line[8] == '_')
298 /* It's a safe identifier. */
299 continue;
300 if (result_len == result_max)
302 result_max += 10;
303 result = realloc (result, result_max * sizeof (char **));
304 if (result == NULL)
306 puts ("No more memory.");
307 exit (1);
310 start = &line[8];
311 for (end = start + 1; !isspace (*end) && *end != '\0'; ++end)
313 result[result_len] = xstrndup (start, end - start);
315 if (strcmp (result[result_len], "IN_MODULE") != 0)
317 if (first)
319 fputs ("The following identifiers will be ignored since the compiler defines them\nby default:\n", stdout);
320 first = 0;
322 puts (result[result_len]);
324 ++result_len;
326 if (result_len == result_max)
328 result_max += 1;
329 result = realloc (result, result_max * sizeof (char **));
330 if (result == NULL)
332 puts ("No more memory.");
333 exit (1);
336 result[result_len] = NULL;
337 fclose (input);
339 return (const char **) result;
343 static int
344 check_header (const char *file_name, const char **except)
346 char line[BUFSIZ], *command;
347 FILE *input;
348 int result = 0;
350 command = malloc (sizeof fmt + strlen (file_name) + 2 * strlen (CC)
351 + strlen (INC) + strlen (macrofile));
353 if (command == NULL)
355 puts ("No more memory.");
356 exit (1);
359 puts (file_name);
360 sprintf (command, fmt, file_name, CC, INC, CC, macrofile);
362 if (system (command))
364 puts ("system() returned nonzero");
365 result = 1;
367 free (command);
368 input = fopen (macrofile, "r");
370 if (input == NULL)
372 printf ("Could not read %s: ", macrofile);
373 perror (NULL);
374 return 1;
377 while (fgets (line, sizeof line, input) != NULL)
379 int i, okay = 0;
380 size_t endmac;
381 const char **cpp;
382 if (strlen (line) < 9 || line[7] != ' ')
383 { /* "#define A" */
384 printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
385 line);
386 result = 1;
387 continue;
389 for (i = 0; i < NUMBER_OF_PREFIXES; ++i)
391 if (!strncmp (line+8, prefix[i], strlen (prefix[i]))) {
392 ++okay;
393 break;
396 if (okay)
397 continue;
398 for (i = 0; i < NUMBER_OF_MACROS; ++i)
400 if (!strncmp (line + 8, macros[i], strlen (macros[i])))
402 ++okay;
403 break;
406 if (okay)
407 continue;
408 /* Find next char after the macro identifier; this can be either
409 a space or an open parenthesis. */
410 endmac = strcspn (line + 8, " (");
411 if (line[8+endmac] == '\0')
413 printf ("malformed input, expected '#define MACRO VALUE'\n"
414 "got '%s'\n", line);
415 result = 1;
416 continue;
418 for (i = 0; i < NUMBER_OF_SUFFIXES; ++i)
420 size_t len = strlen (suffix[i]);
421 if (!strncmp (line + 8 + endmac - len, suffix[i], len))
423 ++okay;
424 break;
427 if (okay)
428 continue;
429 if (except != NULL)
430 for (cpp = except; *cpp != NULL; ++cpp)
432 size_t len = strlen (*cpp);
433 if (!strncmp (line + 8, *cpp, len) && isspace (line[8 + len]))
435 ++okay;
436 break;
439 if (!okay)
441 fputs (line, stdout);
442 result = 2;
445 fclose (input);
447 return result;
450 /* EOF */