1 /* Copyright (C) 1998-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <ctype.h>
19 #include <fnmatch.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include <sys/wait.h>
26 
27 #define HEADER_MAX          256
28 
29 static char macrofile[] = "/tmp/annexc.XXXXXX";
30 
31 /* <aio.h>.  */
32 static const char *const aio_syms[] =
33 {
34   "AIO_ALLDONE", "AIO_CANCELED", "AIO_NOTCANCELED", "LIO_NOP", "LIO_NOWAIT",
35   "LIO_READ", "LIO_WAIT", "LIO_WRITE",
36   /* From <fcntl.h>.  */
37   "FD_CLOEXEC", "F_DUPFD", "F_GETFD", "F_GETFL", "F_GETLK", "F_RDLCK",
38   "F_SETFD", "F_SETFL", "F_SETLK", "F_SETLKW", "F_UNLCK", "F_WRLCK",
39   "O_ACCMODE", "O_APPEND", "O_CREAT", "O_DSYNC", "O_EXCL", "O_NOCTTY",
40   "O_NONBLOCK", "O_RDONLY", "O_RDWR", "O_RSYNC", "O_SYNC", "O_TRUNC",
41   "O_WRONLY",
42   /* From <signal.h>.  */
43   "SA_NOCLDSTOP", "SA_SIGINFO", "SIGABRT", "SIGALRM", "SIGBUS", "SIGCHLD",
44   "SIGCONT", "SIGEV_NONE", "SIGEV_SIGNAL", "SIGEV_SIGNAL", "SIGEV_THREAD",
45   "SIGFPE", "SIGHUP", "SIGILL", "SIGINT", "SIGKILL", "SIGPIPE", "SIGQUIT",
46   "SIGRTMAX", "SIGRTMIN", "SIGSEGV", "SIGSTOP", "SIGTERM", "SIGTSTP",
47   "SIGTTIN", "SIGTTOU", "SIGUSR1", "SIGUSR2", "SIG_BLOCK", "SIG_DFL",
48   "SIG_ERR", "SIG_IGN", "SIG_SETMASK", "SIG_UNBLOCK", "SI_ASYNCIO",
49   "SI_MESGQ", "SI_QUEUE", "SI_TIMER", "SI_USER"
50 };
51 static const char *const aio_maybe[] =
52 {
53   "aio_cancel", "aio_error", "aio_fsync", "aio_read", "aio_return",
54   "aio_suspend", "aio_write", "lio_listio",
55   /* From <fcntl.h>.  */
56   "creat", "fcntl", "open", "SEEK_CUR", "SEEK_END", "SEEK_SET", "S_IRGRP",
57   "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU", "S_ISBLK",
58   "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG", "S_ISUID",
59   "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH", "S_IXUSR",
60   /* From <signal.h>.  */
61   "kill", "raise", "sigaction", "sigaddset", "sigdelset", "sigemptyset",
62   "sigfillset", "sigismember", "signal", "sigpending", "sigprocmask",
63   "sigqueue", "sigsuspend", "sigtimedwait", "sigwait", "sigwaitinfo"
64 };
65 
66 /* <assert.h>.  */
67 static const char *const assert_syms[] =
68 {
69   "assert"
70 };
71 static const char *const assert_maybe[] =
72 {
73 };
74 
75 /* <ctype.h>.   */
76 static const char *const ctype_syms[] =
77 {
78 };
79 static const char *const ctype_maybe[] =
80 {
81   "isalnum", "isalpha", "iscntrl", "isdigit", "isgraph", "islower",
82   "isprint", "ispunct", "isspace", "isupper", "isxdigit", "tolower",
83   "toupper"
84 };
85 
86 /* <dirent.h>.  */
87 static const char *const dirent_syms[] =
88 {
89 };
90 static const char *const dirent_maybe[] =
91 {
92   "closedir", "opendir", "readdir", "readdir_r", "rewinddir"
93 };
94 
95 /* <errno.h>.  */
96 static const char *const errno_syms[] =
97 {
98   "E2BIG", "EACCES", "EAGAIN", "EBADF", "EBADMSG", "EBUSY", "ECANCELED",
99   "ECHILD", "EDEADLK", "EDOM", "EEXIST", "EFAULT", "EFBIG", "EINPROGRESS",
100   "EINTR", "EINVAL", "EIO", "EISDIR", "EMFILE", "EMLINK", "EMSGSIZE",
101   "ENAMETOOLONG", "ENFILE", "ENODEV", "ENOENT", "ENOEXEC", "ENOLCK",
102   "ENOMEM", "ENOSPC", "ENOSYS", "ENOTDIR", "ENOTEMPTY", "ENOTSUP",
103   "ENOTTY", "ENXIO", "EPERM", "EPIPE", "ERANGE", "EROFS", "ESPIPE",
104   "ESRCH", "ETIMEDOUT", "EXDEV"
105 };
106 static const char *const errno_maybe[] =
107 {
108   "errno", "E*"
109 };
110 
111 /* <fcntl.h>.  */
112 static const char *const fcntl_syms[] =
113 {
114   "FD_CLOEXEC", "F_DUPFD", "F_GETFD", "F_GETFL", "F_GETLK", "F_RDLCK",
115   "F_SETFD", "F_SETFL", "F_SETLK", "F_SETLKW", "F_UNLCK", "F_WRLCK",
116   "O_ACCMODE", "O_APPEND", "O_CREAT", "O_DSYNC", "O_EXCL", "O_NOCTTY",
117   "O_NONBLOCK", "O_RDONLY", "O_RDWR", "O_RSYNC", "O_SYNC", "O_TRUNC",
118   "O_WRONLY"
119 };
120 static const char *const fcntl_maybe[] =
121 {
122   "creat", "fcntl", "open", "SEEK_CUR", "SEEK_END", "SEEK_SET", "S_IRGRP",
123   "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU", "S_ISBLK",
124   "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG", "S_ISUID",
125   "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH", "S_IXUSR"
126 };
127 
128 /* <float.h>.  */
129 static const char *const float_syms[] =
130 {
131   "DBL_DIG", "DBL_EPSILON", "DBL_MANT_DIG", "DBL_MAX", "DBL_MAX_10_EXP",
132   "DBL_MAX_EXP", "DBL_MIN", "DBL_MIN_10_EXP", "DBL_MIN_EXP", "FLT_DIG",
133   "FLT_EPSILON", "FLT_MANT_DIG", "FLT_MAX", "FLT_MAX_10_EXP", "FLT_MAX_EXP",
134   "FLT_MIN", "FLT_MIN_10_EXP", "FLT_MIN_EXP", "FLT_RADIX", "FLT_ROUNDS",
135   "LDBL_DIG", "LDBL_EPSILON", "LDBL_MANT_DIG", "LDBL_MAX", "LDBL_MAX_10_EXP",
136   "LDBL_MAX_EXP", "LDBL_MIN", "LDBL_MIN_10_EXP", "LDBL_MIN_EXP"
137 };
138 static const char *const float_maybe[] =
139 {
140 };
141 
142 /* <grp.h>.  */
143 static const char *const grp_syms[] =
144 {
145 };
146 static const char *const grp_maybe[] =
147 {
148   "getgrgid", "getgrgid_r", "getgrnam", "getgrnam_r"
149 };
150 
151 /* <limits.h>.  */
152 static const char *const limits_syms[] =
153 {
154   "_POSIX_AIO_LISTIO_MAX", "_POSIX_AIO_MAX", "_POSIX_ARG_MAX",
155   "_POSIX_CHILD_MAX", "_POSIX_CLOCKRES_MAX", "_POSIX_DELAYTIMER_MAX",
156   "_POSIX_LINK_MAX", "_POSIX_LOGIN_NAME_MAX", "_POSIX_MAX_CANON",
157   "_POSIX_MAX_INPUT", "_POSIX_MQ_OPEN_MAX", "_POSIX_MQ_PRIO_MAX",
158   "_POSIX_NAME_MAX", "_POSIX_NGROUPS_MAX", "_POSIX_OPEN_MAX",
159   "_POSIX_PATH_MAX", "_POSIX_PIPE_BUF", "_POSIX_RTSIG_MAX",
160   "_POSIX_SEM_NSEMS_MAX", "_POSIX_SEM_VALUE_MAX", "_POSIX_SIGQUEUE_MAX",
161   "_POSIX_SSIZE_MAX", "_POSIX_STREAM_MAX",
162   "_POSIX_THREAD_DESTRUCTOR_ITERATIONS", "_POSIX_THREAD_KEYS_MAX",
163   "_POSIX_THREAD_THREADS_MAX", "_POSIX_TIMER_MAX", "_POSIX_TTY_NAME_MAX",
164   "_POSIX_TZNAME_MAX", "_POSIX_THREAD_DESTRUCTOR_ITERATIONS",
165   "CHAR_BIT", "CHAR_MAX", "CHAR_MIN", "INT_MAX", "INT_MIN", "LONG_MAX",
166   "LONG_MIN", "MB_LEN_MAX", "NGROUPS_MAX", "PAGESIZE", "SCHAR_MAX",
167   "SCHAR_MIN", "SHRT_MAX", "SHRT_MIN", "UCHAR_MAX", "UINT_MAX",
168   "ULONG_MAX", "USHRT_MAX"
169 };
170 static const char *const limits_maybe[] =
171 {
172   "AIO_LISTIO_MAX", "AIO_MAX", "ARG_MAX", "CHILD_MAX", "DELAYTIMER_MAX",
173   "LINK_MAX", "LOGIN_NAME_MAX", "LONG_MAX", "LONG_MIN", "MAX_CANON",
174   "MAX_INPUT", "MQ_OPEN_MAX", "MQ_PRIO_MAX", "NAME_MAX", "OPEN_MAX",
175   "PATH_MAX", "PIPE_BUF", "RTSIG_MAX", "PTHREAD_DESTRUCTOR_ITERATIONS",
176   "PTHREAD_KEYS_MAX", "PTHREAD_STACK_MIN", "PTHREAD_THREADS_MAX"
177 };
178 
179 /* <locale.h>.  */
180 static const char *const locale_syms[] =
181 {
182   "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC",
183   "LC_TIME", "NULL"
184 };
185 static const char *const locale_maybe[] =
186 {
187   "LC_*", "localeconv", "setlocale"
188 };
189 
190 /* <math.h>.  */
191 static const char *const math_syms[] =
192 {
193   "HUGE_VAL"
194 };
195 static const char *const math_maybe[] =
196 {
197   "acos", "asin", "atan2", "atan", "ceil", "cos", "cosh", "exp",
198   "fabs", "floor", "fmod", "frexp", "ldexp", "log10", "log", "modf",
199   "pow", "sin", "sinh", "sqrt", "tan", "tanh",
200   "acosf", "asinf", "atan2f", "atanf", "ceilf", "cosf", "coshf", "expf",
201   "fabsf", "floorf", "fmodf", "frexpf", "ldexpf", "log10f", "logf", "modff",
202   "powf", "sinf", "sinhf", "sqrtf", "tanf", "tanhf",
203   "acosl", "asinl", "atan2l", "atanl", "ceill", "cosl", "coshl", "expl",
204   "fabsl", "floorl", "fmodl", "frexpl", "ldexpl", "log10l", "logl", "modfl",
205   "powl", "sinl", "sinhl", "sqrtl", "tanl", "tanhl"
206 };
207 
208 /* <mqueue.h>.  */
209 static const char *const mqueue_syms[] =
210 {
211 };
212 static const char *const mqueue_maybe[] =
213 {
214   "mq_close", "mq_getattr", "mq_notify", "mq_open", "mq_receive",
215   "mq_send", "mq_setattr", "mq_unlink"
216 };
217 
218 /* <pthread.h>.  */
219 static const char *const pthread_syms[] =
220 {
221   "PTHREAD_CANCELED", "PTHREAD_CANCEL_ASYNCHRONOUS",
222   "PTHREAD_CANCEL_DEFERRED", "PTHREAD_CANCEL_DISABLE", "PTHREAD_CANCEL_ENABLE",
223   "PTHREAD_COND_INITIALIZER", "PTHREAD_CREATE_DETACHED",
224   "PTHREAD_CREATE_JOINABLE", "PTHREAD_EXPLICIT_SCHED",
225   "PTHREAD_INHERIT_SCHED", "PTHREAD_MUTEX_INITIALIZER",
226   "PTHREAD_ONCE_INIT", "PTHREAD_PRIO_INHERIT", "PTHREAD_PRIO_NONE",
227   "PTHREAD_PRIO_PROTECT", "PTHREAD_PROCESS_PRIVATE",
228   "PTHREAD_PROCESS_SHARED", "PTHREAD_SCOPE_PROCESS", "PTHREAD_SCOPE_SYSTEM",
229   /* These come from <sched.h>.  */
230   "SCHED_FIFO", "SCHED_OTHER", "SCHED_RR",
231   /* These come from <time.h>.  */
232   "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
233 };
234 static const char *const pthread_maybe[] =
235 {
236   "pthread_atfork", "pthread_attr_destroy", "pthread_attr_getdetachstate",
237   "pthread_attr_getinheritsched", "pthread_attr_getschedparam",
238   "pthread_attr_getschedpolicy", "pthread_attr_getscope",
239   "pthread_attr_getstackaddr", "pthread_attr_getstacksize",
240   "pthread_attr_init", "pthread_attr_setdetachstate",
241   "pthread_attr_setinheritsched", "pthread_attr_setschedparam",
242   "pthread_attr_setschedpolicy", "pthread_attr_setscope",
243   "pthread_attr_setstackaddr", "pthread_attr_setstacksize",
244   "pthread_cleanup_pop", "pthread_cleanup_push", "pthread_cond_broadcast",
245   "pthread_cond_destroy", "pthread_cond_init", "pthread_cond_signal",
246   "pthread_cond_timedwait", "pthread_cond_wait", "pthread_condattr_destroy",
247   "pthread_condattr_getpshared", "pthread_condattr_init",
248   "pthread_condattr_setpshared", "pthread_create", "pthread_detach",
249   "pthread_equal", "pthread_exit", "pthread_getspecific", "pthread_join",
250   "pthread_key_create", "pthread_key_destroy", "pthread_kill",
251   "pthread_mutex_destroy", "pthread_mutex_getprioceiling",
252   "pthread_mutex_init", "pthread_mutex_lock", "pthread_mutex_setprioceiling",
253   "pthread_mutex_trylock", "pthread_mutex_unlock", "pthread_mutexattr_destroy",
254   "pthread_mutexattr_getprioceiling", "pthread_mutexattr_getprotocol",
255   "pthread_mutexattr_getpshared", "pthread_mutexattr_init",
256   "pthread_mutexattr_setprioceiling", "pthread_mutexattr_setprotocol",
257   "pthread_mutexattr_setpshared", "pthread_once", "pthread_self",
258   "pthread_setcancelstate", "pthread_setcanceltype", "pthread_setspecific",
259   "pthread_sigmask", "pthread_testcancel"
260   /* These come from <sched.h>.  */
261   "sched_get_priority_max", "sched_get_priority_min",
262   "sched_get_rr_interval", "sched_getparam", "sched_getscheduler",
263   "sched_setparam", "sched_setscheduler", "sched_yield",
264   /* These come from <time.h>.  */
265   "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
266   "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
267   "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
268   "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
269   "timer_settime", "tzset"
270 };
271 
272 /* <pwd.h>.  */
273 static const char *const pwd_syms[] =
274 {
275 };
276 static const char *const pwd_maybe[] =
277 {
278   "getpwnam", "getpwnam_r", "getpwuid", "getpwuid_r"
279 };
280 
281 /* <sched.h>.  */
282 static const char *const sched_syms[] =
283 {
284   "SCHED_FIFO", "SCHED_OTHER", "SCHED_RR",
285 };
286 static const char *const sched_maybe[] =
287 {
288   "sched_get_priority_max", "sched_get_priority_min",
289   "sched_get_rr_interval", "sched_getparam", "sched_getscheduler",
290   "sched_setparam", "sched_setscheduler", "sched_yield",
291   /* These come from <time.h>.  */
292   "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
293   "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
294   "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
295   "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
296   "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
297   "timer_settime", "tzset"
298 };
299 
300 /* <semaphore.h>.  */
301 static const char *const semaphore_syms[] =
302 {
303 };
304 static const char *const semaphore_maybe[] =
305 {
306   "sem_close", "sem_destroy", "sem_getvalue", "sem_init", "sem_open",
307   "sen_post", "sem_trywait", "sem_unlink", "sem_wait"
308 };
309 
310 /* <setjmp.h>.  */
311 static const char *const setjmp_syms[] =
312 {
313 };
314 static const char *const setjmp_maybe[] =
315 {
316   "longjmp", "setjmp", "siglongjmp", "sigsetjmp"
317 };
318 
319 /* <signal.h>.  */
320 static const char *const signal_syms[] =
321 {
322   "SA_NOCLDSTOP", "SA_SIGINFO", "SIGABRT", "SIGALRM", "SIGBUS", "SIGCHLD",
323   "SIGCONT", "SIGEV_NONE", "SIGEV_SIGNAL", "SIGEV_THREAD",
324   "SIGFPE", "SIGHUP", "SIGILL", "SIGINT", "SIGKILL", "SIGPIPE", "SIGQUIT",
325   "SIGRTMAX", "SIGRTMIN", "SIGSEGV", "SIGSTOP", "SIGTERM", "SIGTSTP",
326   "SIGTTIN", "SIGTTOU", "SIGUSR1", "SIGUSR2", "SIG_BLOCK", "SIG_DFL",
327   "SIG_ERR", "SIG_IGN", "SIG_SETMASK", "SIG_UNBLOCK", "SI_ASYNCIO",
328   "SI_MESGQ", "SI_QUEUE", "SI_TIMER", "SI_USER"
329 };
330 static const char *const signal_maybe[] =
331 {
332   "kill", "raise", "sigaction", "sigaddset", "sigdelset", "sigemptyset",
333   "sigfillset", "sigismember", "signal", "sigpending", "sigprocmask",
334   "sigqueue", "sigsuspend", "sigtimedwait", "sigwait", "sigwaitinfo"
335 };
336 
337 /* <stdarg.h>.  */
338 static const char *const stdarg_syms[] =
339 {
340   "va_arg", "va_end", "va_start"
341 };
342 static const char *const stdarg_maybe[] =
343 {
344   "va_list"
345 };
346 
347 /* <stddef.h>.  */
348 static const char *const stddef_syms[] =
349 {
350   "NULL", "offsetof"
351 };
352 static const char *const stddef_maybe[] =
353 {
354 };
355 
356 /* <stdio.h>.  */
357 static const char *const stdio_syms[] =
358 {
359   "BUFSIZ", "EOF", "FILENAME_MAX", "FOPEN_MAX", "L_ctermid", "L_cuserid",
360   "L_tmpnam", "NULL", "SEEK_CUR", "SEEK_END", "SEEK_SET", "STREAM_MAX",
361   "TMP_MAX", "stderr", "stdin", "stdout", "_IOFBF", "_IOLBF", "_IONBF"
362 };
363 static const char *const stdio_maybe[] =
364 {
365   "clearerr", "fclose", "fdopen", "feof", "ferror", "fflush", "fgetc",
366   "fgetpos", "fgets", "fileno", "flockfile", "fopen", "fprintf", "fputc",
367   "fputs", "fread", "freopen", "fscanf", "fseek", "fsetpos", "ftell",
368   "ftrylockfile", "funlockfile", "fwrite", "getc", "getchar",
369   "getchar_unlocked", "getc_unlocked", "gets", "perror", "printf", "putc",
370   "putchar", "putchar_unlocked", "putc_unlocked", "puts", "remove", "rename",
371   "rewind", "scanf", "setbuf", "setvbuf", "sprintf", "sscanf", "tmpfile",
372   "tmpnam", "ungetc", "vfprintf", "vprintf", "vsprintf"
373 };
374 
375 /* <stdlib.h>.  */
376 static const char *const stdlib_syms[] =
377 {
378   "EXIT_FAILURE", "EXIT_SUCCESS", "MB_CUR_MAX", "NULL", "RAND_MAX"
379 };
380 static const char *const stdlib_maybe[] =
381 {
382   "abort", "abs", "atexit", "atof", "atoi", "atol", "bsearch", "calloc",
383   "div", "exit", "free", "getenv", "labs", "ldiv", "malloc", "mblen",
384   "mbstowcs", "mbtowc", "qsort", "rand", "rand_r", "realloc", "srand",
385   "strtod", "strtol", "strtoul", "system", "wcstombs", "wctomb"
386 };
387 
388 /* <string.h>.  */
389 static const char *const string_syms[] =
390 {
391   "NULL"
392 };
393 static const char *const string_maybe[] =
394 {
395   "memchr", "memcmp", "memcpy", "memmove", "memset", "strcat", "strchr",
396   "strcmp", "strcoll", "strcpy", "strcspn", "strerror", "strlen",
397   "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn",
398   "strstr", "strtok", "strtok_r", "strxfrm"
399 };
400 
401 /* <sys/mman.h>.  */
402 static const char *const mman_syms[] =
403 {
404   "MAP_FAILED", "MAP_FIXED", "MAP_PRIVATE", "MAP_SHARED", "MCL_CURRENT",
405   "MCL_FUTURE", "MS_ASYNC", "MS_INVALIDATE", "MS_SYNC", "PROT_EXEC",
406   "PROT_NONE", "PROT_READ", "PROT_WRITE"
407 };
408 static const char *const mman_maybe[] =
409 {
410   "mlock", "mlockall", "mmap", "mprotect", "msync", "munlock", "munlockall",
411   "munmap", "shm_open", "shm_unlock"
412 };
413 
414 /* <sys/stat.h>.  */
415 static const char *const stat_syms[] =
416 {
417   "S_IRGRP", "S_IROTH", "S_IRUSR", "S_IRWXG", "S_IRWXO", "S_IRWXU",
418   "S_ISBLK", "S_ISCHR", "S_ISDIR", "S_ISFIFO", "S_ISGID", "S_ISREG",
419   "S_ISUID", "S_IWGRP", "S_IWOTH", "S_IWUSR", "S_IXGRP", "S_IXOTH",
420   "S_IXUSR", "S_TYPEISMQ", "S_TYPEISSEM", "S_TYPEISSHM"
421 };
422 static const char *const stat_maybe[] =
423 {
424   "chmod", "fchmod", "fstat", "mkdir", "mkfifo", "stat", "umask"
425 };
426 
427 /* <sys/times.h>.  */
428 static const char *const times_syms[] =
429 {
430 };
431 static const char *const times_maybe[] =
432 {
433   "times"
434 };
435 
436 /* <sys/types.h>.  */
437 static const char *const types_syms[] =
438 {
439 };
440 static const char *const types_maybe[] =
441 {
442 };
443 
444 /* <sys/utsname.h>.  */
445 static const char *const utsname_syms[] =
446 {
447 };
448 static const char *const utsname_maybe[] =
449 {
450   "uname"
451 };
452 
453 /* <sys/wait.h>.  */
454 static const char *const wait_syms[] =
455 {
456   "WEXITSTATUS", "WIFEXITED", "WIFSIGNALED", "WIFSTOPPED", "WNOHANG",
457   "WSTOPSIG", "WTERMSIG", "WUNTRACED"
458 };
459 static const char *const wait_maybe[] =
460 {
461   "wait", "waitpid"
462 };
463 
464 /* <termios.h>.  */
465 static const char *const termios_syms[] =
466 {
467   "B0", "B110", "B1200", "B134", "B150", "B1800", "B19200", "B200", "B2400",
468   "B300", "B38400", "B4800", "B50", "B600", "B75", "B9600", "BRKINT", "CLOCAL",
469   "CREAD", "CS5", "CS6", "CS7", "CS8", "CSIZE", "CSTOPN", "ECHO", "ECHOE",
470   "ECHOK", "ECHONL", "HUPCL", "ICANON", "ICRNL", "IEXTEN", "IGNBRK", "IGNCR",
471   "IGNPAR", "INCLR", "INPCK", "ISIG", "ISTRIP", "IXOFF", "IXON", "NCCS",
472   "NOFLSH", "OPOST", "PARENB", "PARMRK", "PARODD", "TCIFLUSH", "TCIOFF",
473   "TCIOFLUSH", "TCOFLUSH", "TCOOFF", "TCOON", "TCSADRAIN", "TCSAFLUSH",
474   "TCSANOW", "TOSTOP", "VEOF", "VEOL", "VERASE", "VINTR", "VKILL", "VMIN",
475   "VQUIT", "VSTART", "VSTOP", "VSUSP", "VTIME"
476 };
477 static const char *const termios_maybe[] =
478 {
479   "cfgetispeed", "cfgetospeed", "cfsetispeed", "cfsetospeed", "tcdrain",
480   "tcflow", "tcflush", "tcgetattr", "tcsendbrk", "tcsetattr"
481 };
482 
483 /* <time.h>.  */
484 static const char *const time_syms[] =
485 {
486   "CLK_TCK", "CLOCKS_PER_SEC", "CLOCK_REALTIME", "NULL", "TIMER_ABSTIME"
487 };
488 static const char *const time_maybe[] =
489 {
490   "asctime", "asctime_r", "clock", "clock_getres", "clock_gettime",
491   "clock_settime", "ctime", "ctime_r", "difftime", "gmtime", "gmtime_r",
492   "localtime", "localtime_r", "mktime", "nanosleep", "strftime", "time",
493   "timer_create", "timer_delete", "timer_getoverrun", "timer_gettime",
494   "timer_settime", "tzset"
495 };
496 
497 /* <unistd.h>.  */
498 static const char *const unistd_syms[] =
499 {
500   "F_OK", "NULL", "R_OK", "SEEK_CUR", "SEEK_END", "SEEK_SET", "STDERR_FILENO",
501   "STDIN_FILENO", "STDOUT_FILENO", "W_OK", "X_OK",
502   "_PC_ASYNC_IO", "_PC_CHOWN_RESTRICTED", "_PC_LINK_MAX", "_PC_MAX_CANON",
503   "_PC_MAX_INPUT", "_PC_NAME_MAX", "_PC_NO_TRUNC", "_PC_PATH_MAX",
504   "_PC_PIPE_BUF", "_PC_PRIO_IO", "_PC_SYNC_IO", "_PC_VDISABLE",
505   "_SC_AIO_LISTIO_MAX", "_SC_AIO_MAX", "_SC_AIO_PRIO_DELTA_MAX",
506   "_SC_ARG_MAX", "_SC_ASYNCHRONOUS_IO", "_SC_CHILD_MAX", "_SC_CLK_TCK",
507   "_SC_DELAYTIMER_MAX", "_SC_FSYNC", "_SC_GETGR_R_SIZE_MAX",
508   "_SC_GETPW_R_SIZE_MAX", "_SC_JOB_CONTROL", "_SC_LOGIN_NAME_MAX",
509   "_SC_MAPPED_FILES", "_SC_MEMLOCK", "_SC_MEMLOCK_RANGE",
510   "_SC_MEMORY_PROTECTION", "_SC_MESSAGE_PASSING", "_SC_MQ_OPEN_MAX",
511   "_SC_MQ_PRIO_MAX", "_SC_NGROUPS_MAX", "_SC_OPEN_MAX", "_SC_PAGESIZE",
512   "_SC_PRIORITIZED_IO", "_SC_PRIORITY_SCHEDULING", "_SC_REALTIME_SIGNALS",
513   "_SC_RTSIG_MAX", "_SC_SAVED_IDS", "_SC_SEMAPHORES", "_SC_SEM_NSEMS_MAX",
514   "_SC_SEM_VALUE_MAX", "_SC_SHARED_MEMORY_OBJECTS", "_SC_SIGQUEUE_MAX",
515   "_SC_STREAM_MAX", "_SC_SYNCHRONIZED_IO", "_SC_THREADS",
516   "_SC_THREAD_ATTR_STACKADDR", "_SC_THREAD_ATTR_STACKSIZE",
517   "_SC_THREAD_DESTRUCTOR_ITERATIONS", "_SC_THREAD_PRIO_INHERIT",
518   "_SC_THREAD_PRIORITY_SCHEDULING", "_SC_THREAD_PRIO_PROTECT",
519   "_SC_THREAD_PROCESS_SHARED", "_SC_THREAD_SAFE_FUNCTIONS",
520   "_SC_THREAD_STACK_MIN", "_SC_THREAD_THREADS_MAX", "_SC_TIMERS",
521   "_SC_TIMER_MAX", "_SC_TTY_NAME_MAX", "_SC_TZNAME_MAX", "_SC_VERSION"
522 };
523 static const char *const unistd_maybe[] =
524 {
525   "_POSIX_ASYNCHRONOUS_IO", "_POSIX_ASYNC_IO", "_POSIX_CHOWN_RESTRICTED",
526   "_POSIX_FSYNC", "_POSIX_JOB_CONTROL", "_POSIX_MAPPED_FILES",
527   "_POSIX_MEMLOCK", "_POSIX_MEMLOCK_RANGE", "_MEMORY_PROTECTION",
528   "_POSIX_MESSAGE_PASSING", "_POSIX_NO_TRUNC", "_POSIX_PRIORITIZED_IO",
529   "_POSIX_PRIORITY_SCHEDULING", "_POSIX_PRIO_IO", "_POSIX_REATIME_SIGNALS",
530   "_POSIX_SAVED_IDS", "_POSIX_SEMAPHORES", "_POSIX_SHARED_MEMORY_OBJECTS",
531   "_POSIX_SYNCHRONIZED_IO", "_POSIX_SYNC_IO", "_POSIX_THREADS",
532   "_POSIX_THREAD_ATTR_STACKADDR", "_POSIX_THREAD_ATTR_STACKSIZE",
533   "_POSIX_THREAD_PRIO_INHERIT", "_POSIX_THREAD_PRIO_PROTECT",
534   "_POSIX_THREAD_PROCESS_SHARED", "_POSIX_THREAD_SAFE_FUNCTIONS",
535   "_POSIX_THREAD_PRIORITY_SCHEDULING", "_POSIX_TIMERS",
536   "_POSIX_VDISABLE", "_POSIX_VERSION",
537   "_exit", "access", "alarm", "chdir", "chown", "close", "ctermid", "cuserid",
538   "dup2", "dup", "execl", "execle", "execlp", "execv", "execve", "execvp",
539   "fdatasync", "fork", "fpathconf", "fsync", "ftruncate", "getcwd", "getegid",
540   "geteuid", "getgid", "getgroups", "getlogin", "getlogin_r", "getpgrp",
541   "getpid", "getppid", "getuid", "isatty", "link", "lseek", "pathconf",
542   "pause", "pipe", "read", "rmdir", "setgid", "setgpid", "setsid", "setuid",
543   "sleep", "sleep", "sysconf", "tcgetpgrp", "tcsetpgrp", "ttyname",
544   "ttyname_r", "unlink", "write"
545 };
546 
547 /* <utime.h>.  */
548 static const char *const utime_syms[] =
549 {
550 };
551 static const char *const utime_maybe[] =
552 {
553   "utime"
554 };
555 
556 
557 static struct header
558 {
559   const char *name;
560   const char *const *syms;
561   size_t nsyms;
562   const char *const *maybe;
563   size_t nmaybe;
564   const char *subset;
565 } headers[] =
566 {
567 #define H(n) \
568   { #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
569     n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), NULL }
570 #define Hc(n, s) \
571   { #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
572     n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), s }
573 #define Hs(n) \
574   { "sys/" #n ".h", n##_syms, sizeof (n##_syms) / sizeof (n##_syms[0]), \
575     n##_maybe, sizeof (n##_maybe) / sizeof (n##_maybe[0]), NULL }
576   H(aio),
577   H(assert),
578   H(ctype),
579   H(dirent),
580   H(errno),
581   H(fcntl),
582   H(float),
583   H(grp),
584   H(limits),
585   H(locale),
586   H(math),
587   Hc(mqueue, "_POSIX_MESSAGE_PASSING"),
588   H(pthread),
589   H(pwd),
590   H(sched),
591   H(semaphore),
592   H(setjmp),
593   H(signal),
594   H(stdarg),
595   H(stddef),
596   H(stdio),
597   H(stdlib),
598   H(string),
599   Hs(mman),
600   Hs(stat),
601   Hs(times),
602   Hs(types),
603   Hs(utsname),
604   Hs(wait),
605   H(termios),
606   H(time),
607   H(unistd),
608   H(utime)
609 };
610 
611 #define NUMBER_OF_HEADERS              (sizeof headers / sizeof *headers)
612 
613 
614 /* Format string to build command to invoke compiler.  */
615 static const char fmt[] = "\
616 echo \"#include <%s>\" |\
617 %s -E -dM -D_POSIX_SOURCE %s \
618 -isystem `%s --print-prog-name=include` - > %s";
619 
620 static const char testfmt[] = "\
621 echo \"#include <unistd.h>\n#if !defined %s || %s == -1\n#error not defined\n#endif\n\" |\
622 %s -E -dM -D_POSIX_SOURCE %s \
623 -isystem `%s --print-prog-name=include` - 2> /dev/null > %s";
624 
625 
626 /* The compiler we use (given on the command line).  */
627 const char *CC;
628 /* The -I parameters for CC to find all headers.  */
629 const char *INC;
630 
631 static char *xstrndup (const char *, size_t);
632 static const char **get_null_defines (void);
633 static int check_header (const struct header *, const char **);
634 static int xsystem (const char *);
635 
636 int
main(int argc,char * argv[])637 main (int argc, char *argv[])
638 {
639   int h;
640   int result = 0;
641   const char **ignore_list;
642 
643   CC = argc > 1 ? argv[1] : "gcc";
644   INC = argc > 2 ? argv[2] : "";
645 
646   if (system (NULL) == 0)
647     {
648       puts ("Sorry, no command processor.");
649       return EXIT_FAILURE;
650     }
651 
652   /* First get list of symbols which are defined by the compiler.  */
653   ignore_list = get_null_defines ();
654 
655   fputs ("Tested files:\n", stdout);
656 
657   for (h = 0; h < NUMBER_OF_HEADERS; ++h)
658     result |= check_header (&headers[h], ignore_list);
659 
660   remove (macrofile);
661 
662   /* The test suite should return errors but for now this is not
663      practical.  Give a warning and ask the user to correct the bugs.  */
664   return result;
665 }
666 
667 
668 static char *
xstrndup(const char * s,size_t n)669 xstrndup (const char *s, size_t n)
670 {
671   size_t len = n;
672   char *new = malloc (len + 1);
673 
674   if (new == NULL)
675     return NULL;
676 
677   new[len] = '\0';
678   return memcpy (new, s, len);
679 }
680 
681 
682 /* Like system but propagate interrupt and quit signals.  */
683 int
xsystem(const char * cmd)684 xsystem (const char *cmd)
685 {
686   int status;
687 
688   status = system (cmd);
689   if (status != -1)
690     {
691       if (WIFSIGNALED (status))
692 	{
693 	  if (WTERMSIG (status) == SIGINT || WTERMSIG (status) == SIGQUIT)
694 	    raise (WTERMSIG (status));
695 	}
696       else if (WIFEXITED (status))
697 	{
698 	  if (WEXITSTATUS (status) == SIGINT + 128
699 	      || WEXITSTATUS (status) == SIGQUIT + 128)
700 	    raise (WEXITSTATUS (status) - 128);
701 	}
702     }
703   return status;
704 }
705 
706 
707 static const char **
get_null_defines(void)708 get_null_defines (void)
709 {
710   char line[BUFSIZ], *command;
711   char **result = NULL;
712   size_t result_len = 0;
713   size_t result_max = 0;
714   FILE *input;
715   int first = 1;
716 
717   int fd = mkstemp (macrofile);
718   if (fd == -1)
719     {
720       printf ("mkstemp failed: %m\n");
721       exit (1);
722     }
723   close (fd);
724 
725   command = malloc (sizeof fmt + sizeof "/dev/null" + 2 * strlen (CC)
726 		    + strlen (INC) + strlen (macrofile));
727 
728   if (command == NULL)
729     {
730       puts ("No more memory.");
731       exit (1);
732     }
733 
734   sprintf (command, fmt, "/dev/null", CC, INC, CC, macrofile);
735 
736   if (xsystem (command))
737     {
738       puts ("system() returned nonzero");
739       return NULL;
740     }
741   free (command);
742   input = fopen (macrofile, "r");
743 
744   if (input == NULL)
745     {
746       printf ("Could not read %s: ", macrofile);
747       perror (NULL);
748       return NULL;
749     }
750 
751   while (fgets (line, sizeof line, input) != NULL)
752     {
753       char *start;
754       if (strlen (line) < 9 || line[7] != ' ')
755 	{ /* "#define A" */
756 	  printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
757 		  line);
758 	  continue;
759 	}
760       if (line[8] == '_')
761 	/* It's a safe identifier.  */
762 	continue;
763       if (result_len == result_max)
764 	{
765 	  result_max += 10;
766 	  result = realloc (result, result_max * sizeof (char **));
767 	  if (result == NULL)
768 	    {
769 	      puts ("No more memory.");
770 	      exit (1);
771 	    }
772 	}
773       start = &line[8];
774       result[result_len++] = xstrndup (start, strcspn (start, " ("));
775 
776       if (first)
777 	{
778 	  fputs ("The following identifiers will be ignored since the compiler defines them\nby default:\n", stdout);
779 	  first = 0;
780 	}
781       puts (result[result_len - 1]);
782     }
783   if (result_len == result_max)
784     {
785       result_max += 1;
786       result = realloc (result, result_max * sizeof (char **));
787       if (result == NULL)
788 	{
789 	  puts ("No more memory.");
790 	  exit (1);
791 	}
792     }
793   result[result_len] = NULL;
794   fclose (input);
795 
796   return (const char **) result;
797 }
798 
799 
800 static int
check_header(const struct header * header,const char ** except)801 check_header (const struct header *header, const char **except)
802 {
803   char line[BUFSIZ], command[sizeof fmt + strlen (header->name)
804 			     + 2 * strlen (CC)
805 			     + strlen (INC) + strlen (macrofile)];
806   FILE *input;
807   int result = 0;
808   int found[header->nsyms];
809   int i;
810 
811   memset (found, '\0', header->nsyms * sizeof (int));
812 
813   printf ("=== %s ===\n", header->name);
814   sprintf (command, fmt, header->name, CC, INC, CC, macrofile);
815 
816   /* First see whether this subset is supported at all.  */
817   if (header->subset != NULL)
818     {
819       sprintf (line, testfmt, header->subset, header->subset, CC, INC, CC,
820 	       macrofile);
821       if (xsystem (line))
822 	{
823 	  printf ("!! not available\n");
824 	  return 0;
825 	}
826     }
827 
828   if (xsystem (command))
829     {
830       puts ("system() returned nonzero");
831       result = 1;
832     }
833   input = fopen (macrofile, "r");
834 
835   if (input == NULL)
836     {
837       printf ("Could not read %s: ", macrofile);
838       perror (NULL);
839       return 1;
840     }
841 
842   while (fgets (line, sizeof line, input) != NULL)
843     {
844       const char **ignore;
845       if (strlen (line) < 9 || line[7] != ' ')
846 	{ /* "#define A" */
847 	  printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
848 		  line);
849 	  result = 1;
850 	  continue;
851 	}
852 
853       /* Find next char after the macro identifier; this can be either
854 	 a space or an open parenthesis.  */
855       line[8 + strcspn (&line[8], " (")] = '\0';
856 
857       /* Now check whether it's one of the required macros.  */
858       for (i = 0; i < header->nsyms; ++i)
859 	if (!strcmp (&line[8], header->syms[i]))
860 	  break;
861       if (i < header->nsyms)
862 	{
863 	  found[i] = 1;
864 	  continue;
865 	}
866 
867       /* Symbols starting with "_" are ok.  */
868       if (line[8] == '_')
869 	continue;
870 
871       /* Maybe one of the symbols which are always defined.  */
872       for (ignore = except; *ignore != NULL; ++ignore)
873 	if (! strcmp (&line[8], *ignore))
874 	  break;
875       if (*ignore != NULL)
876 	continue;
877 
878       /* Otherwise the symbol better should match one of the following.  */
879       for (i = 0; i < header->nmaybe; ++i)
880 	if (fnmatch (header->maybe[i], &line[8], 0) == 0)
881 	  break;
882       if (i < header->nmaybe)
883 	continue;
884 
885       printf ("*  invalid macro `%s'\n", &line[8]);
886       result |= 1;
887     }
888   fclose (input);
889 
890   for (i = 0; i < header->nsyms; ++i)
891     if (found[i] == 0)
892       printf ("** macro `%s' not defined\n", header->syms[i]);
893 
894   return result;
895 }
896